Beispiel #1
0
    def _validate_initialization(self):
        """ Make sure we have all of the things we need.  Subclasses may override this,
        but all subclass implementations should call `super()._validate_initialization()` at
        the end of this method (if they do not, a SuperCallMissingError is raised).

        .. note::
           This method should not make any modifications to the `Coordinate` itself, since it is
           only called when `sanity_checking_enabled` is `True`.  Use `_finilize_initialization()`
           for this purpose.
        """
        #--------------------------------------------------------------------------------#
        # Type 1 coordinate: non-orphaned
        if not self.is_orphaned():
            # Enforce the requirement that all atoms of a type 1 coordinate be non-orphaned
            if any(a.is_orphaned() for a in self.atoms):
                raise ValueError(
                    "non-orphaned Coordinates must be constructed entirely of non-orphaned"
                    " atoms, but atom '{}' on coordinate '{}' is orphaned.".format(
                        first(a for a in self.atoms if a.is_orphaned()),
                        self
                    ))
            # Enforce the requirement that all atoms of a type 1 coordinate should have
            #   the exact same parent molecule as the parent representation's molecule
            if any(a.parent is not self.molecule for a in self.atoms):
                raise ValueError(
                    "all atoms in a non-orphaned coordinate must have the same parent"
                    " molecule (i.e. the exact same instance) as the coordinate, but"
                    " atom '{}' does not have the same parent molecule as Coordinate"
                    " '{}' ({} != {}).".format(
                        first(a for a in self.atoms if a.parent is not self.molecule),
                        self,
                        id(first(a for a in self.atoms if a.parent is not self.molecule).parent),
                        id(self.molecule)
                    ))
        #--------------------------------------------------------------------------------#
        # Type 2 coordinate: orphaned with non-orphaned atoms
        elif any(not a.is_orphaned() for a in self.atoms):
            # Enforce the requirement that if one atom is non-orphaned, all of them must be.
            if any(a.is_orphaned() for a in self.atoms):
                raise ValueError(
                    "orphaned coordinates composed of non-orphaned atoms must have all"
                    " atoms non-orphaned, but atom '{}' on coordinate '{}' is orphaned.".format(
                        first(a for a in self.atoms if a.is_orphaned()),
                        self
                    ))
            # Enforce the requirement that all atoms be on the same molecule
            if any(a.parent is not self.molecule for a in self.atoms):
                raise ValueError(
                    "all atoms in a orphaned coordinate composed of non-orphaned atoms"
                    "must have the same parent molecule (i.e. the exact same instance),"
                    " but atom '{}' does not have the same parent molecule as '{}' for"
                    " coordinate '{}'.".format(
                        first(a for a in self.atoms if a.parent is not self.molecule),
                        self.atoms[0],
                        self
                    ))
        #--------------------------------------------------------------------------------#
        # Type 3 coordinate: orphaned coordinate with all orphaned atoms, base_analog not None
        elif self.base_analog is not None:
            # Enforce the requirement that the base_analog's atoms exactly match the
            #   coordinate's atoms' respective base_atom attributes
            if len(self.base_analog.atoms) != len(self.atoms):
                raise ValueError("orphaned coordinates with a base_analog must be composed"
                                 " of the same number of Atoms as their base_analog (got {}"
                                 " atoms for derived coordinate, {} atoms for base"
                                 " coordinate)".format(
                    len(self.atoms),
                    len(self.base_analog.atoms)))
            for my_atom, base_atom in zip(self.atoms, self.base_analog.atoms):
                if my_atom.base_atom is not base_atom:
                    raise ValueError("base_atom of displaced Atom must correspond to the"
                                     " analogous atom in the displaced coordinate's"
                                     " base_analog's atoms, but '{}' is not the same as"
                                     " '{}' for coordinate '{}'".format(
                        my_atom.base_atom, base_atom, short_str(self)
                    ))
        #--------------------------------------------------------------------------------#
        # Type 4 coordinate: orphaned coordinate with all orphaned atoms, base_analog is None
        else:
            # Enforce the requirement that all atom's eventual parent molecules should be
            #   the same.
            mol_found = None
            for atom in self.atoms:
                iter_atom = atom
                visited = []
                while iter_atom is not None and iter_atom.parent is None:
                    if iter_atom in visited:
                        raise ValueError("circular base_atom dependency for '{}'".format(atom))
                    iter_atom = iter_atom.base_atom
                if iter_atom is None:
                    raise ValueError("all orphaned atoms on an orphaned coordinate must have"
                                     " a `base_atom` that is not orphaned somewhere down the"
                                     " line.  '{}' in coordinate '{}' is not like that.".format(
                        atom, short_str(self)
                    ))
                if mol_found is None:
                    mol_found = iter_atom.parent
                elif mol_found is not iter_atom.parent:
                    raise ValueError("all orphaned atoms on an orphaned coordinate must have"
                                     " the same parent molecule of the first non-orphaned coordinate"
                                     " in the `base_atom` hierarchy.  The molecule obtained in this"
                                     " manner from '{}' in coordinate '{}' is not the same"
                                     " as the molecule obtained in this manner from '{}'.".format(
                        atom, self.atoms[0], short_str(self)
                    ))
        #--------------------------------------------------------------------------------#
        self._Coordinate_validate_called = True
 def b_tensor_element_reindexed(current_coord, *coords):
     coords = tuple(coords) if not isinstance(coords[0], tuple) else coords[0]
     internal = coords[0]
     carts = coords[1:]
     #========================================#
     if internal.is_orphaned():
         #----------------------------------------#
         # avoid the gratuitous creation of coordinates
         key = (type(internal), tuple(internal.atoms))
         internal = SimpleInternalCoordinate.created_coords.get(key, None)
         if internal is None:
             SimpleInternalCoordinate.created_coords[key] = internal = coords[0]
             # TODO UNITS FOR CREATED COORDINATES!!!
         #----------------------------------------#
         # Check to make sure their all integers...
         if sanity_checking_enabled:
             if any(isinstance(cart, CartesianCoordinate) for cart in carts):
                 cart = first(carts, lambda c: isinstance(c, CartesianCoordinate))
                 raise ValueError("ambiguous B tensor element retrieval for orphaned internal"
                                  " coordinate '{}' using cartesian coordinate '{}'".format(
                     short_str(internal), short_str(cart)
                 ))
             if not all(isinstance(cart, int) for cart in carts):
                 raise ValueError(
                     "b_tensor elements may not be retrieved for "
                     " orphaned coordinates by anything but integer indices"
                 )
         #----------------------------------------#
         # get the offset indices
         # what we have now is integers in current_coord's internal indexing scheme
         new_idxs = current_coord.molecule_indices_for(carts)
         # This method uses the molecular indexing scheme.  This is why we needed to
         #   do the above index translation.
         return internal.b_tensor_element(*new_idxs)
     #========================================#
     else: # internal is not orphaned
         #----------------------------------------#
         # Tidy things up and convert internal indices
         #   to molecular indices
         if sanity_checking_enabled:
             if any(isinstance(cart, CartesianCoordinate) for cart in carts) \
                     and not all(isinstance(cart, CartesianCoordinate) for cart in carts):
                 raise ValueError("mixing of CartesianCoordinates and integers in b tensor"
                                  " element retrieval is confusing and thus no longer allowed."
                                  " coordinates were ('{}')".format(
                     "', '".join(str(c) for c in carts)
                 ))
         if all(isinstance(c, int) for c in carts):
             # These are integers in current_coord's internal scheme.  Translate them to
             #   the molecular indexing scheme.
             carts = current_coord.molecule_indices_for(carts)
         elif type_checking_enabled:
             if not all(isinstance(cart, CartesianCoordinate) for cart in carts):
                 raise TypeError("arguments beyond the first two to b_tensor_element_reindexed"
                                 " must be either all ints or all CartesianCoordinates."
                                 " coordinates were ('{}')".format(
                     "', '".join(str(c) for c in carts)
                 ))
         #----------------------------------------#
         # This method uses the molecular indexing scheme.  This is why we needed to
         #   do the above index translation.
         return internal.b_tensor_element(*carts)
Beispiel #3
0
    def _validate_initialization(self):
        """ Make sure we have all of the things we need.  Subclasses may override this,
        but all subclass implementations should call `super()._validate_initialization()` at
        the end of this method (if they do not, a SuperCallMissingError is raised).

        .. note::
           This method should not make any modifications to the `Coordinate` itself, since it is
           only called when `sanity_checking_enabled` is `True`.  Use `_finilize_initialization()`
           for this purpose.
        """
        #--------------------------------------------------------------------------------#
        # Type 1 coordinate: non-orphaned
        if not self.is_orphaned():
            # Enforce the requirement that all atoms of a type 1 coordinate be non-orphaned
            if any(a.is_orphaned() for a in self.atoms):
                raise ValueError(
                    "non-orphaned Coordinates must be constructed entirely of non-orphaned"
                    " atoms, but atom '{}' on coordinate '{}' is orphaned.".
                    format(first(a for a in self.atoms if a.is_orphaned()),
                           self))
            # Enforce the requirement that all atoms of a type 1 coordinate should have
            #   the exact same parent molecule as the parent representation's molecule
            if any(a.parent is not self.molecule for a in self.atoms):
                raise ValueError(
                    "all atoms in a non-orphaned coordinate must have the same parent"
                    " molecule (i.e. the exact same instance) as the coordinate, but"
                    " atom '{}' does not have the same parent molecule as Coordinate"
                    " '{}' ({} != {}).".format(
                        first(a for a in self.atoms
                              if a.parent is not self.molecule), self,
                        id(
                            first(a for a in self.atoms
                                  if a.parent is not self.molecule).parent),
                        id(self.molecule)))
        #--------------------------------------------------------------------------------#
        # Type 2 coordinate: orphaned with non-orphaned atoms
        elif any(not a.is_orphaned() for a in self.atoms):
            # Enforce the requirement that if one atom is non-orphaned, all of them must be.
            if any(a.is_orphaned() for a in self.atoms):
                raise ValueError(
                    "orphaned coordinates composed of non-orphaned atoms must have all"
                    " atoms non-orphaned, but atom '{}' on coordinate '{}' is orphaned."
                    .format(first(a for a in self.atoms if a.is_orphaned()),
                            self))
            # Enforce the requirement that all atoms be on the same molecule
            if any(a.parent is not self.molecule for a in self.atoms):
                raise ValueError(
                    "all atoms in a orphaned coordinate composed of non-orphaned atoms"
                    "must have the same parent molecule (i.e. the exact same instance),"
                    " but atom '{}' does not have the same parent molecule as '{}' for"
                    " coordinate '{}'.".format(
                        first(a for a in self.atoms
                              if a.parent is not self.molecule), self.atoms[0],
                        self))
        #--------------------------------------------------------------------------------#
        # Type 3 coordinate: orphaned coordinate with all orphaned atoms, base_analog not None
        elif self.base_analog is not None:
            # Enforce the requirement that the base_analog's atoms exactly match the
            #   coordinate's atoms' respective base_atom attributes
            if len(self.base_analog.atoms) != len(self.atoms):
                raise ValueError(
                    "orphaned coordinates with a base_analog must be composed"
                    " of the same number of Atoms as their base_analog (got {}"
                    " atoms for derived coordinate, {} atoms for base"
                    " coordinate)".format(len(self.atoms),
                                          len(self.base_analog.atoms)))
            for my_atom, base_atom in zip(self.atoms, self.base_analog.atoms):
                if my_atom.base_atom is not base_atom:
                    raise ValueError(
                        "base_atom of displaced Atom must correspond to the"
                        " analogous atom in the displaced coordinate's"
                        " base_analog's atoms, but '{}' is not the same as"
                        " '{}' for coordinate '{}'".format(
                            my_atom.base_atom, base_atom, short_str(self)))
        #--------------------------------------------------------------------------------#
        # Type 4 coordinate: orphaned coordinate with all orphaned atoms, base_analog is None
        else:
            # Enforce the requirement that all atom's eventual parent molecules should be
            #   the same.
            mol_found = None
            for atom in self.atoms:
                iter_atom = atom
                visited = []
                while iter_atom is not None and iter_atom.parent is None:
                    if iter_atom in visited:
                        raise ValueError(
                            "circular base_atom dependency for '{}'".format(
                                atom))
                    iter_atom = iter_atom.base_atom
                if iter_atom is None:
                    raise ValueError(
                        "all orphaned atoms on an orphaned coordinate must have"
                        " a `base_atom` that is not orphaned somewhere down the"
                        " line.  '{}' in coordinate '{}' is not like that.".
                        format(atom, short_str(self)))
                if mol_found is None:
                    mol_found = iter_atom.parent
                elif mol_found is not iter_atom.parent:
                    raise ValueError(
                        "all orphaned atoms on an orphaned coordinate must have"
                        " the same parent molecule of the first non-orphaned coordinate"
                        " in the `base_atom` hierarchy.  The molecule obtained in this"
                        " manner from '{}' in coordinate '{}' is not the same"
                        " as the molecule obtained in this manner from '{}'.".
                        format(atom, self.atoms[0], short_str(self)))
        #--------------------------------------------------------------------------------#
        self._Coordinate_validate_called = True
Beispiel #4
0
 def b_tensor_element_reindexed(current_coord, *coords):
     coords = tuple(coords) if not isinstance(coords[0],
                                              tuple) else coords[0]
     internal = coords[0]
     carts = coords[1:]
     #========================================#
     if internal.is_orphaned():
         #----------------------------------------#
         # avoid the gratuitous creation of coordinates
         key = (type(internal), tuple(internal.atoms))
         internal = SimpleInternalCoordinate.created_coords.get(key, None)
         if internal is None:
             SimpleInternalCoordinate.created_coords[
                 key] = internal = coords[0]
             # TODO UNITS FOR CREATED COORDINATES!!!
         #----------------------------------------#
         # Check to make sure their all integers...
         if sanity_checking_enabled:
             if any(
                     isinstance(cart, CartesianCoordinate)
                     for cart in carts):
                 cart = first(carts,
                              lambda c: isinstance(c, CartesianCoordinate))
                 raise ValueError(
                     "ambiguous B tensor element retrieval for orphaned internal"
                     " coordinate '{}' using cartesian coordinate '{}'".
                     format(short_str(internal), short_str(cart)))
             if not all(isinstance(cart, int) for cart in carts):
                 raise ValueError(
                     "b_tensor elements may not be retrieved for "
                     " orphaned coordinates by anything but integer indices"
                 )
         #----------------------------------------#
         # get the offset indices
         # what we have now is integers in current_coord's internal indexing scheme
         new_idxs = current_coord.molecule_indices_for(carts)
         # This method uses the molecular indexing scheme.  This is why we needed to
         #   do the above index translation.
         return internal.b_tensor_element(*new_idxs)
     #========================================#
     else:  # internal is not orphaned
         #----------------------------------------#
         # Tidy things up and convert internal indices
         #   to molecular indices
         if sanity_checking_enabled:
             if any(isinstance(cart, CartesianCoordinate) for cart in carts) \
                     and not all(isinstance(cart, CartesianCoordinate) for cart in carts):
                 raise ValueError(
                     "mixing of CartesianCoordinates and integers in b tensor"
                     " element retrieval is confusing and thus no longer allowed."
                     " coordinates were ('{}')".format("', '".join(
                         str(c) for c in carts)))
         if all(isinstance(c, int) for c in carts):
             # These are integers in current_coord's internal scheme.  Translate them to
             #   the molecular indexing scheme.
             carts = current_coord.molecule_indices_for(carts)
         elif type_checking_enabled:
             if not all(
                     isinstance(cart, CartesianCoordinate)
                     for cart in carts):
                 raise TypeError(
                     "arguments beyond the first two to b_tensor_element_reindexed"
                     " must be either all ints or all CartesianCoordinates."
                     " coordinates were ('{}')".format("', '".join(
                         str(c) for c in carts)))
         #----------------------------------------#
         # This method uses the molecular indexing scheme.  This is why we needed to
         #   do the above index translation.
         return internal.b_tensor_element(*carts)