Пример #1
0
 def b_vector_for_positions(cls, *args):
     if sanity_checking_enabled:
         if len(args) != 4:
             raise TypeError
     #--------------------------------------------------------------------------------#
     # Check the cache first
     cache_resp = SimpleInternalCoordinate._check_b_tensor_cache(cls, args)
     if cache_resp:
         return cache_resp
     #--------------------------------------------------------------------------------#
     # Not in the cache...so compute it
     def e(j, k):
         ev = LightVector.l_sub(args[k-1], args[j-1]); ev.normalize()
         return ev
     def r(j, k):
         return LightVector.l_sub(args[k-1], args[j-1]).magnitude()
     e12, e23, e43 = e(1,2), e(2,3), e(4,3)
     e32 = -e23
     r12, r23, r43 = r(1,2), r(2, 3), r(3, 4)
     r32 = r23
     sin2phi2 = sin(angle_between_vectors(e12, e32))**2
     cosphi2 = cos(angle_between_vectors(e12, e32))
     sin2phi3 = sin(angle_between_vectors(e23, e43))**2
     cosphi3 = cos(angle_between_vectors(e23, e43))
     ret_val = [0,0,0,0]
     ret_val[0] = cross(e12, e23) * (-1.0 / (r12 * sin2phi2))
     ret_val[1] = ((r23 - r12 * cosphi2)/(r23*r12*sin2phi2)) * cross(e12, e23)\
                     + (cosphi3/(r23*sin2phi3)) * cross(e43, e32)
     ret_val[2] = ((r32 - r43 * cosphi3)/(r32*r43*sin2phi3)) * cross(e43, e32)\
                     + (cosphi2/(r32*sin2phi2)) * cross(e12, e23)
     ret_val[3] = cross(e43, e32) * (-1.0 / (r43 * sin2phi3))
     SimpleInternalCoordinate.b_tensor_cache[(cls,) + tuple(args)] = ret_val
     return ret_val
Пример #2
0
 def noncanonical_value_for_xyz(cls, xyz):
     def e(j, k):
         ev = LightVector.l_sub(xyz[k-1], xyz[j-1]); ev.normalize()
         return ev
     e12 = e(1,2)
     e21 = -e12
     e32 = e(3,2)
     e23 = -e32
     e34 = e(3,4)
     phi2 = angle_between_vectors(e21, e23)
     phi3 = angle_between_vectors(e32, e34)
     sinphi2, sinphi3 = sin(phi2), sin(phi3)
     sintau = e21.dot(cross(e32, e34)) / (sinphi2 * sinphi3)
     tau_0 = safe_asin(sintau)
     #----------------------------------------#
     # Deal with the sign
     sign_val = cross(e21, e23).dot(cross(e32, e34))
     #zero_cutoff = 1e-10
     zero_cutoff = 0
     if sign_val < -zero_cutoff:
         tau_e = math.pi - tau_0
         #tau_e = - tau_0
     elif sign_val > zero_cutoff:
         tau_e = tau_0
     else:
         tau_e = math.pi / 2.0
     #----------------------------------------#
     return tau_e
Пример #3
0
 def transform_tensor(self, tensor, to_representation):
     """
     """
     self.freeze()
     to_representation.freeze()
     shape = (len(to_representation), ) * len(tensor.shape)
     ret_val = RepresentationDependentTensor(
         shape=shape, representation=to_representation)
     #--------------------------------------------------------------------------------#
     if isinstance(to_representation, CartesianRepresentation):
         if len(self) != len(to_representation):
             raise ValueError(
                 "incompatible representation sizes ({} != {})".format(
                     len(self), len(to_representation)))
         if tensor.representation is not self:
             raise ValueError(
                 "representation {} can only transform a tensor whose representation attribute is the same "
                 " as itself (tensor.representation was {} ".format(
                     self, tensor.representation))
         if self.molecule.is_linear():
             raise NotImplementedError(
                 "linear molecule cartesian-to-cartesian transformation is not"
                 " yet implemented.  Shouldn't be too hard...")
         if sanity_checking_enabled:
             #TODO use a recentered version of the 'from' representation if it is not centered
             pass
             # Make sure things are centered
             #if not self.molecule.is_centered(cartesian_representation=self):
             #    raise ValueError("CartesianRepresentation objects transformed from and to"
             #                     " must be centered at the center of mass ({} was not)".format(
             #        self
             #    ))
             #elif not self.molecule.is_centered(cartesian_representation=to_representation):
             #    raise ValueError("CartesianRepresentation objects transformed from and to"
             #                     " must be centered at the center of mass ({} was not)".format(
             #        to_representation
             #    ))
         #----------------------------------------#
         old = self.value
         new = to_representation.value
         unitconv = self.units.to(to_representation.units)
         oldmat = Matrix(old).reshape((len(self) / 3, 3))
         newmat = Matrix(new).reshape((len(self) / 3, 3))
         #----------------------------------------#
         # Check to see if the molecule is planar.  If so, append the cross product of any
         #   two atoms' positions not colinear with the origin
         if any(norm(oldmat[:dir].view(Vector)) < 1e-12 \
                 or norm(newmat[:dir].view(Vector)) < 1e-12 \
                     for dir in [X, Y, Z]):
             first_atom = None
             # TODO unit concious cutoff (e.g. this would fail if the units of the position matrix were meters)
             nonorigin_cutoff = 1e-2
             for i, v in enumerate(grouper(3, old)):
                 if norm(LightVector(v)) > nonorigin_cutoff:
                     first_atom = i
                     break
             second_atom = None
             for i in range(first_atom + 1, len(self) // 3):
                 #TODO make sure this works with Molecule.linear_cutoff
                 if norm(oldmat[i]) > nonorigin_cutoff and norm(newmat[i]) > nonorigin_cutoff \
                         and abs(angle_between_vectors(oldmat[first_atom], oldmat[i])) > 1e-5 \
                         and abs(angle_between_vectors(newmat[first_atom], newmat[i])) > 1e-5:
                     second_atom = i
                     break
             oldmat = Matrix(
                 list(oldmat.rows) +
                 [cross(oldmat[first_atom], oldmat[second_atom])])
             newmat = Matrix(
                 list(newmat.rows) +
                 [cross(newmat[first_atom], newmat[second_atom])])
         #----------------------------------------#
         rot_mat = newmat.T * np.linalg.pinv(oldmat.T)
         # Divide by unit conversion because the representation dependent tensor
         #   is [some units] *per* representation units
         rot_mat /= unitconv
         trans_mat = Matrix(shape=(len(self), len(self)))
         for idx in xrange(len(self) // 3):
             off = idx * 3
             trans_mat[off:off + 3, off:off + 3] = rot_mat
         order = len(tensor.shape)
         # This is basically impossible to read what I'm doing here, but work it out
         #   looking at the numpy.einsum documentation and you'll see that this is correct.
         #   Basically, we want to contract the row indices of the transformation matrix
         #   with each axis of the tensor to be transformed.
         einsumargs = sum(
             ([trans_mat, [2 * i, 2 * i + 1]] for i in xrange(order)), [])
         einsumargs += [
             tensor, [i for i in xrange(2 * order) if i % 2 != 0]
         ]
         einsumargs += [[i for i in xrange(2 * order) if i % 2 == 0]]
         np.einsum(*einsumargs, out=ret_val)
         return ret_val
     #--------------------------------------------------------------------------------#
     elif isinstance(to_representation, InternalRepresentation):
         if len(tensor.shape) == 1:
             A = to_representation.a_matrix
             ret_val[...] = A.T * tensor.view(Vector)
         else:
             raise NotImplementedError("use transform_forcefield instead")
         return ret_val
     #--------------------------------------------------------------------------------#
     elif isinstance(to_representation, NormalRepresentation):
         B = to_representation.b_matrix
         ret_val[...] = tensor.linearly_transformed(B)
         return ret_val
     else:
         raise NotImplementedError(
             "Transformation of arbitrary tensors from representation of type '{}' to "
             " representations of type '{}' is not implemented.".format(
                 self.__class__.__name__,
                 to_representation.__class__.__name__))
Пример #4
0
 def is_perpendicular(cls, v1, v2):
     return abs(math.pi / 2.0 -
                angle_between_vectors(v1, v2)) < cls.perpendicular_tolerance
Пример #5
0
 def value_for_xyz(cls, xyz):
     v1 = LightVector.l_sub(xyz[0], xyz[1])
     v2 = LightVector.l_sub(xyz[2], xyz[1])
     return angle_between_vectors(v1, v2)
Пример #6
0
 def is_perpendicular(cls, v1, v2):
     return abs(math.pi / 2.0 - angle_between_vectors(v1, v2)) < cls.perpendicular_tolerance
Пример #7
0
 def value_for_xyz(cls, xyz):
     v1 = LightVector.l_sub(xyz[0], xyz[1])
     v2 = LightVector.l_sub(xyz[2], xyz[1])
     return angle_between_vectors(v1, v2)
Пример #8
0
 def transform_tensor(self, tensor, to_representation):
     """
     """
     self.freeze()
     to_representation.freeze()
     shape = (len(to_representation),) * len(tensor.shape)
     ret_val = RepresentationDependentTensor(shape=shape, representation=to_representation)
     # --------------------------------------------------------------------------------#
     if isinstance(to_representation, CartesianRepresentation):
         if len(self) != len(to_representation):
             raise ValueError(
                 "incompatible representation sizes ({} != {})".format(len(self), len(to_representation))
             )
         if tensor.representation is not self:
             raise ValueError(
                 "representation {} can only transform a tensor whose representation attribute is the same "
                 " as itself (tensor.representation was {} ".format(self, tensor.representation)
             )
         if self.molecule.is_linear():
             raise NotImplementedError(
                 "linear molecule cartesian-to-cartesian transformation is not"
                 " yet implemented.  Shouldn't be too hard..."
             )
         if sanity_checking_enabled:
             # TODO use a recentered version of the 'from' representation if it is not centered
             pass
             # Make sure things are centered
             # if not self.molecule.is_centered(cartesian_representation=self):
             #    raise ValueError("CartesianRepresentation objects transformed from and to"
             #                     " must be centered at the center of mass ({} was not)".format(
             #        self
             #    ))
             # elif not self.molecule.is_centered(cartesian_representation=to_representation):
             #    raise ValueError("CartesianRepresentation objects transformed from and to"
             #                     " must be centered at the center of mass ({} was not)".format(
             #        to_representation
             #    ))
         # ----------------------------------------#
         old = self.value
         new = to_representation.value
         unitconv = self.units.to(to_representation.units)
         oldmat = Matrix(old).reshape((len(self) / 3, 3))
         newmat = Matrix(new).reshape((len(self) / 3, 3))
         # ----------------------------------------#
         # Check to see if the molecule is planar.  If so, append the cross product of any
         #   two atoms' positions not colinear with the origin
         if any(
             norm(oldmat[:dir].view(Vector)) < 1e-12 or norm(newmat[:dir].view(Vector)) < 1e-12 for dir in [X, Y, Z]
         ):
             first_atom = None
             # TODO unit concious cutoff (e.g. this would fail if the units of the position matrix were meters)
             nonorigin_cutoff = 1e-2
             for i, v in enumerate(grouper(3, old)):
                 if norm(LightVector(v)) > nonorigin_cutoff:
                     first_atom = i
                     break
             second_atom = None
             for i in range(first_atom + 1, len(self) // 3):
                 # TODO make sure this works with Molecule.linear_cutoff
                 if (
                     norm(oldmat[i]) > nonorigin_cutoff
                     and norm(newmat[i]) > nonorigin_cutoff
                     and abs(angle_between_vectors(oldmat[first_atom], oldmat[i])) > 1e-5
                     and abs(angle_between_vectors(newmat[first_atom], newmat[i])) > 1e-5
                 ):
                     second_atom = i
                     break
             oldmat = Matrix(list(oldmat.rows) + [cross(oldmat[first_atom], oldmat[second_atom])])
             newmat = Matrix(list(newmat.rows) + [cross(newmat[first_atom], newmat[second_atom])])
         # ----------------------------------------#
         rot_mat = newmat.T * np.linalg.pinv(oldmat.T)
         # Divide by unit conversion because the representation dependent tensor
         #   is [some units] *per* representation units
         rot_mat /= unitconv
         trans_mat = Matrix(shape=(len(self), len(self)))
         for idx in xrange(len(self) // 3):
             off = idx * 3
             trans_mat[off : off + 3, off : off + 3] = rot_mat
         order = len(tensor.shape)
         # This is basically impossible to read what I'm doing here, but work it out
         #   looking at the numpy.einsum documentation and you'll see that this is correct.
         #   Basically, we want to contract the row indices of the transformation matrix
         #   with each axis of the tensor to be transformed.
         einsumargs = sum(([trans_mat, [2 * i, 2 * i + 1]] for i in xrange(order)), [])
         einsumargs += [tensor, [i for i in xrange(2 * order) if i % 2 != 0]]
         einsumargs += [[i for i in xrange(2 * order) if i % 2 == 0]]
         np.einsum(*einsumargs, out=ret_val)
         return ret_val
     # --------------------------------------------------------------------------------#
     elif isinstance(to_representation, InternalRepresentation):
         if len(tensor.shape) == 1:
             A = to_representation.a_matrix
             ret_val[...] = A.T * tensor.view(Vector)
         else:
             raise NotImplementedError("use transform_forcefield instead")
         return ret_val
     # --------------------------------------------------------------------------------#
     elif isinstance(to_representation, NormalRepresentation):
         B = to_representation.b_matrix
         ret_val[...] = tensor.linearly_transformed(B)
         return ret_val
     else:
         raise NotImplementedError(
             "Transformation of arbitrary tensors from representation of type '{}' to "
             " representations of type '{}' is not implemented.".format(
                 self.__class__.__name__, to_representation.__class__.__name__
             )
         )