Example #1
0
 def __str__(self):
     ret_val = "CartesianRepresentation of molecule {}, in {}:\n".format(
         shortstr(self.molecule), self.units)
     for i, (x, y, z) in enumerate(grouper(3, self)):
         ret_val += indent(
             '{:>9} {:12.8f} {:12.8f} {:12.8f}\n'.format(
                 '[{}-{}]'.format(3 * i, 3 * i + 2), x.value, y.value,
                 z.value), 2)
     return ret_val
 def __str__(self):
     ret_val = "CartesianRepresentation of molecule {}, in {}:\n".format(shortstr(self.molecule), self.units)
     for i, (x, y, z) in enumerate(grouper(3, self)):
         ret_val += indent(
             "{:>9} {:12.8f} {:12.8f} {:12.8f}\n".format(
                 "[{}-{}]".format(3 * i, 3 * i + 2), x.value, y.value, z.value
             ),
             2,
         )
     return ret_val
Example #3
0
 def task_description(self):
     # TODO add some more helpful information to this, with an argument for verbosity level
     ret_val = ""
     basics = [
         "Path", self.directory,
         "Input File Name", self.runner.input_file.split(os.sep)[-1],
         "Output File Name", self.runner.output_file.split(os.sep)[-1],
     ]
     extras = [
         "Input Generator Class", self.input_generator.__class__.__name__,
         "Output Parser Class", self.output_parser.__class__.__name__,
         "Runner Class", self.runner.__class__.__name__,
     ]
     allstats = basics + extras
     lwidth = max(len(k) for k, v in grouper(2, allstats))
     rwidth = max(len(v) for k, v in grouper(2, allstats))
     props = []
     for name, value in grouper(2, allstats):
         props.append(('{:.<'+str(lwidth)+'}{:.>'+str(rwidth)+'}').format(
             name, value
         ))
     return '\n'.join(props)
Example #4
0
 def coordinate_with_cartesian_displacements(self, base_coord, disps):
     disps = tuple(disps)
     if all(d == 0 for d in disps):
         return base_coord
     ret_val = self.displaced_coordinates.get((base_coord, disps), None)
     if ret_val is None:
         new_atoms = []
         for atom, disp in zip(base_coord.atoms, grouper(3, disps)):
             new_atoms.append(atom.displaced(LightVector(disp)*self.delta))
         ret_val = base_coord.copy_with_atoms(new_atoms)
         # Cache it for later to avoid gratuitous creation of displaced Molecule instances
         self.displaced_coordinates[(base_coord, disps)] = ret_val
     return ret_val
Example #5
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))
         )
     )
Example #6
0
 def iter_atom_coords(self, with_atom=False):
     for i, (a, b, c) in enumerate(grouper(3, self)):
         if with_atom:
             yield a, b, c, self.atoms[i]
         else:
             yield a, b, c
Example #7
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__))
 def iter_atom_coords(self, with_atom=False):
     for i, (a, b, c) in enumerate(grouper(3, self)):
         if with_atom:
             yield a, b, c, self.atoms[i]
         else:
             yield a, b, c
 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__
             )
         )