Source code for sknano.core.atoms.mixins.dihedrals

# -*- coding: utf-8 -*-
"""
======================================================================================
Class representations of dihedral angles (:mod:`sknano.core.atoms.mixins.dihedrals`)
======================================================================================

.. currentmodule:: sknano.core.atoms.mixins.dihedrals

"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals
__docformat__ = 'restructuredtext en'

from collections import namedtuple

import numpy as np

from sknano.core.math import vector as vec
from .bonds import Bond
from .topology_base import AngularTopology, AngularTopologyCollection, \
    TopologyStats, check_operands as check_operands_


__all__ = ['compute_dihedral', 'Dihedral', 'Dihedrals', 'DihedralStats']

DihedralStats = namedtuple('DihedralStats', TopologyStats._fields)


[docs]def compute_dihedral(*atoms, check_operands=True, degrees=False): """Compute dihedral angle. Parameters ---------- *atoms : {:class:`~python:list`, :class:`~sknano.core.atoms.Atoms`} :class:`~python:list` of :class:`~sknano.core.atoms.Atom`\ s or an :class:`~sknano.core.atoms.Atoms` object. check_operands : :class:`~python:bool`, optional degrees : :class:`~python:bool`, optional Returns ------- :class:`~python:float` Raises ------ :class:`~python:TypeError` if `atoms` is not a list of :class:`~sknano.core.atoms.Atom` objects or an :class:`~sknano.core.atoms.Atoms` object. :class:`~python:ValueError` if len(atoms) != 4. """ if check_operands: atoms = check_operands_(*atoms, size=4) atom1, atom2, atom3, atom4 = atoms b12 = Bond(atom1, atom2).vector b23 = Bond(atom2, atom3).vector b34 = Bond(atom3, atom4).vector m = b12.cross(b23) n = b23.cross(b34) sina = vec.dot(m, b34) * b23.norm cosa = vec.dot(m, n) angle = np.arctan2(sina, cosa) if degrees: angle = np.degrees(angle) return angle
[docs]class Dihedral(AngularTopology): """Class representation of dihedral angle between 4 `Atom` objects. Parameters ---------- *atoms : {:class:`~python:list`, :class:`~sknano.core.atoms.Atoms`} :class:`~python:list` of :class:`~sknano.core.atoms.Atom`\ s or an :class:`~sknano.core.atoms.Atoms` object. size : :class:`~python:int` parent : Parent :class:`~sknano.core.atoms.Molecule`, if any. id : :class:`~python:int` check_operands : :class:`~python:bool`, optional degrees : :class:`~python:bool`, optional Raises ------ :class:`~python:TypeError` if `atoms` is not a list of :class:`~sknano.core.atoms.Atom` objects or an :class:`~sknano.core.atoms.Atoms` object. :class:`~python:ValueError` if len(atoms) != 4. """ def __init__(self, *args, **kwargs): super().__init__(*args, size=4, **kwargs) self.fmtstr = "{atom1!r}, {atom2!r}, {atom3!r}, {atom4!r} " + \ super().fmtstr def __str__(self): """Return nice string representation of `Dihedral`.""" return "Dihedral({!r}->{!r}->{!r}->{!r})".format(self.atom1.id, self.atom2.id, self.atom3.id, self.atom4.id) @property def atom1(self): """:class:`~sknano.core.atoms.Atom` 1 in `Dihedral`.""" return self.atoms[0] @property def atom2(self): """:class:`~sknano.core.atoms.Atom` 2 in `Dihedral`.""" return self.atoms[1] @property def atom3(self): """:class:`~sknano.core.atoms.Atom` 3 in `Dihedral`.""" return self.atoms[2] @property def atom4(self): """:class:`~sknano.core.atoms.Atom` 4 in `Dihedral`.""" return self.atoms[3] @property def dihedral(self): """An alias for :attr:`Topology.measure`.""" return self.dihedral
[docs] def compute_measure(self): """Compute the bond angle, which is the measure of an :class:`Angle`. Returns ------- :class:`~python:float` """ return compute_dihedral(*self.atoms, degrees=self.degrees)
[docs] def todict(self): """Return :class:`~python:dict` of constructor parameters.""" super_dict = super().todict() super_dict.update(dict(atom1=self.atom1, atom2=self.atom2, atom3=self.atom3, atom4=self.atom4)) return super_dict
[docs]class Dihedrals(AngularTopologyCollection): """Base class for collection of atom `Dihedral`\ s. Parameters ---------- topolist : {None, sequence, `Dihedrals`}, optional if not `None`, then a list of `Dihedral` objects parent : Parent :class:`~sknano.core.atoms.Molecule`, if any. degrees : :class:`~python:bool`, optional """ @property def __item_class__(self): return Dihedral @property def Ndihedrals(self): """Number of `Dihedral`\ s in `Dihedrals`.""" return len(self) @property def dihedrals(self): """:class:`~numpy:numpy.ndarray` of :attr:`~Dihedral.dihedral`\ s.""" return self.measures @property def mean_dihedral(self): """Mean dihedral angle.""" return self.mean_measure @property def statistics(self): """Dihedral stats.""" return DihedralStats(**super().statistics._asdict())