import numpy as np

from ..core.errors import 分子Error
from ..core.settings import 设置
from import 单位

__all__ = ['Bond']

[docs]class : """A class representing a bond between two atoms. An instance of this class has the following attributes: * ``atom1`` and ``atom2`` -- two instances of |Atom| that form this bond * ``order`` -- order of the bond. It is either an integer number or the floating point value stored in ``Bond.AR``, indicating an aromatic bond * ``mol`` -- |Molecule| this bond belongs to * ``properties`` -- |Settings| instance storing all other information about this bond (initially it is populated with *\*\*other*) .. note:: Newly created bond is **not** added to ``atom1.bonds`` or ``atom2.bonds``. Storing information about |Bond| in |Atom| is relevant only in the context of the whole |Molecule|, so this information is updated by :meth:`~Molecule.add_bond`. """ AR = 1.5
[docs] def __init__(self, atom1=None, atom2=None, order=1, mol=None, **other): self.atom1 = atom1 self.atom2 = atom2 self.order = order self.mol = mol = 设置(other)
[docs] def __str__(self): """Return a string representation of this bond.""" return '({})--{:1.1f}--({})'.format(str(self.atom1).strip(), self.order, str(self.atom2).strip())
[docs] def __iter__(self): """Iterate over bonded atoms (``atom1`` first, then ``atom2``).""" yield self.atom1 yield self.atom2
[docs] def is_aromatic(self): """Check if this bond is aromatic.""" return self.order == .AR
[docs] def length(self, unit='angstrom'): """Return bond length, expressed in *unit*.""" return self.atom1.distance_to(self.atom2, result_unit=unit)
[docs] def as_vector(self, start=None, unit='angstrom'): """Return a vector between two atoms that form this bond. *start* can be used to indicate which atom should be the beginning of that vector. If not specified, ``self.atom1`` is used. Returned value if a tuple of length 3, expressed in *unit*. """ if start: if start 不是 in self: raise 分子Error('Bond.as_vector: given atom is not a part of this bond') a,b = start, self.other_end(start) else: a,b = self.atom1, self.atom2 return a.vector_to(b, result_unit=unit)
[docs] def other_end(self, atom): """Return the atom on the other end of this bond with respect to *atom*. *atom* has to be one of the atoms forming this bond, otherwise an exception is raised. """ if atom is self.atom1: return self.atom2 elif atom is self.atom2: return self.atom1 else: raise 分子Error('Bond.other_end: invalid atom passed')
[docs] def resize(self, moving_atom, length, unit='angstrom'): """Change the length of this bond to *length* expressed in *unit* by moving *moving_atom*. *moving_atom* should be one of the atoms that form this bond. This atom is moved along the bond axis in such a way that new bond length equals *length*. If this bond is a part of a |Molecule| the whole part connected to *moving_atom* is moved. .. note:: Calling this method on a bond that forms a ring within a molecule raises a |MoleculeError|. """ if self.mol: self.mol.resize_bond(self, moving_atom, length, unit) else: bond_v = np.array(self.as_vector(start=moving_atom)) trans_v = (1 - length/self.length(unit)) * bond_v moving_atom.translate(trans_v)
[docs] def rotate(self, moving_atom, angle, unit='radian'): """Rotate part of the molecule containing *moving_atom* along axis defined by this bond by an *angle* expressed in *unit*. Calling this method makes sense only if this bond is a part of a |Molecule|. *moving_atom* should be one of the atoms that form this bond and it indicates which part of the molecule is rotated. A positive value of *angle* denotes counterclockwise rotation (when looking along the bond, from the stationary part of the molecule). .. note:: Calling this method on a bond that forms a ring raises a |MoleculeError|. """ if self.mol: self.mol.rotate_bond(self, moving_atom, angle, unit)