Beispiel #1
0
 def value_for_coords_and_displacements(self, pairs, internal_coord, cart_coords):
     cart_coords = tuple(cart_coords)
     disps = [0] * (len(internal_coord.atoms) * 3)
     for coord, ndeltas in pairs:
         idx = internal_coord.internal_indices_for_coordinates(coord)[0]
         disps[idx] = ndeltas
     coord_idxs = internal_coord.internal_indices_for_coordinates(*cart_coords)
     dispcoord = self.coordinate_with_cartesian_displacements(internal_coord, disps)
     if len(cart_coords) == 0:
         # For some reason, BondAngle thinks it's a subclass of PeriodicCoordinate (!?)
         if hasattr(dispcoord, 'possible_values_for_xyz'):
             baseval = internal_coord.value_for_xyz(
                 Matrix([a.pos for a in internal_coord.atoms])
             )
             pos_vals = dispcoord.possible_values_for_xyz(
                 Matrix([a.pos for a in dispcoord.atoms])
             )
             # Including the half-periods makes this work...
             # TODO fix and/or justify this
             val = min(*(pos_vals + tuple(p+math.pi for p in pos_vals)), key=lambda p: abs(p - baseval))
             # No need to convert angular units, since value_for_xyz always returns Radians
             return val
         else:
             val = dispcoord.value
             if hasunits(internal_coord) and internal_coord.units.genre is AngularUnit:
                 val *= dispcoord.units.to(Radians)
             return val
     else:
         B = dispcoord.get_b_tensor(max_order=len(cart_coords))
         return B[tuple(coord_idxs)]
Beispiel #2
0
 def _recompute_b_vector(self):
     #TODO Fix units
     b = Matrix(shape=(self.molecule.natoms, 3))
     i = self.atom_indices
     b[i[0]], b[i[1]], b[i[2]], b[i[3]] = self.b_vector_for_positions(
         *[a.pos for a in self.atoms])
     self._bvector = b.flatten('C').view(Vector)
Beispiel #3
0
 def matrix(self):
     """
     """
     if not self._matrix is None:
         return self._matrix
     self._matrix = Matrix([[-1, 0, 0], [0, -1, 0], [0, 0, -1]])
     return self._matrix
 def g_matrix(self):
     B = self.b_matrix
     # TODO G matrix units
     G = Matrix(shape=(len(self), ) * 2)
     for i, j in product(xrange(len(self)), repeat=2):
         G[i, j] = sum(B[i, k] * B[j, k] / self.molecule.atoms[k // 3].mass
                       for k in xrange(3 * self.molecule.natoms))
     return G
Beispiel #5
0
 def matrix(self):
     if not self._matrix is None:
         return self._matrix
     x = self.axis[0]
     y = self.axis[1]
     z = self.axis[2]
     self._matrix = Matrix([[1 - 2 * x * x, -2 * x * y, -2 * x * z],
                            [-2 * x * y, 1 - 2 * y * y, -2 * y * z],
                            [-2 * x * z, -2 * y * z, 1 - 2 * z * z]])
     return self._matrix
Beispiel #6
0
 def value_for_displacements(self, pairs):
     # get the position vector
     xyzvect = LightVector([a.position for a in self.atoms]).ravel()
     # make pairs into a list in case it's a general iterator
     pairs = list(pairs)
     int_idxs = self.internal_indices_for_coordinates(*[pair[0] for pair in pairs])
     for i, (__, ndeltas) in enumerate(pairs):
         xyzvect[int_idxs[i]] += self.b_tensor_finite_difference_delta * ndeltas
     return self.__class__.value_for_xyz(
         Matrix(
             list(grouper(3, xyzvect))
         )
     )
Beispiel #7
0
 def matrix(self):
     if self._matrix is not None:
         return self._matrix
     u = self.axis
     cos = math.cos(self.theta)
     sin = math.sin(self.theta)
     self._matrix = Matrix(
         [
             [ cos + u.x**2*(1-cos), u.x*u.y*(1-cos) - u.z*sin, u.x*u.z*(1-cos) + u.y*sin ],
             [ u.y*u.x*(1-cos) + u.z*sin, cos + u.y**2*(1-cos), u.y*u.z*(1-cos) - u.x*sin ],
             [ u.z*u.x*(1-cos) - u.y*sin, u.z*u.y*(1-cos) + u.x*sin, cos + u.z**2*(1-cos) ]
         ]
     )
     return self._matrix
Beispiel #8
0
 def format(self, tensor, labels=None):
     ret_val = ''
     #--------------------------------------------------------------------------------#
     shp = tensor.shape
     if labels is None:
         if self.one_based:
             labels = [map(str, range(1, dim + 1)) for dim in shp]
         else:
             labels = [map(str, range(dim)) for dim in shp]
     elif isinstance(labels,
                     Sequence) and not isinstance(labels[0], (list, tuple)):
         labels = (tuple(labels), ) * len(shp)
     #--------------------------------------------------------------------------------#
     for idxs in product(*map(range, shp[:-2])):
         if self.symmetric and idxs != sorted(idxs):
             continue
         mtx = Matrix(tensor[idxs])
         ret_val += ", ".join(labels[i][n]
                              for i, n in enumerate(idxs)) + ":\n"
         ret_val += super(TensorFormatter, self).format(mtx, labels[-2:])
         ret_val += "\n"
     #--------------------------------------------------------------------------------#
     return ret_val
Beispiel #9
0
 def b_matrix(self):
     return Matrix([c.b_vector for c in self.coords])
 def b_matrix(self):
     """ The El'yashevich--Wilson B matrix for the molecule in the representation.
     """
     rows = [coord.b_vector for coord in self]
     return Matrix(rows)
Beispiel #11
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__))
Beispiel #12
0
 def matrix(self):
     if self._matrix is not None:
         return self._matrix
     self._matrix = Matrix([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])
     return self._matrix
Beispiel #13
0
    def _recompute_b_vector(self):

        b = Matrix(shape=(self.molecule.natoms, 3))
        i = self.atom_indices
        b[i[0]], b[i[1]], b[i[2]], b[i[3]] = self.__class__.b_vector_for_positions(*[a.pos for a in self.atoms])
        self._bvector = b.flatten('C').view(Vector)
Beispiel #14
0
 def value_for_molecule_matrix(self, mat):
     i = self.atom_indices
     new_mat = Matrix([mat[i[j]] for j in range(len(self.atoms))])
     return self.__class__.value_for_xyz(new_mat)