Exemple #1
0
 def __init__(self, mol, tol=0.1):
     """The default settings are usually sufficient.
         -- mol : Molecule to determine point group for.
     """
     self.tol = tol
     self.etol = self.tol / 3.0
     self.mol = mol
     # center molecule
     self.mol.positions -= self.mol.positions.mean(axis=0)
     # normalize
     norm_factor = numpy.amax(
         numpy.linalg.norm(self.mol.positions, axis=1, keepdims=True))
     if norm_factor < 1e-6:
         norm_factor = 1.0
     self.mol.positions /= norm_factor
     self.symmops = {"C": [], "S": [], "sigma": []}
     # identity
     self.symmops["I"] = numpy.eye(3)
     #inversion
     inversion = -numpy.eye(3)
     if is_valid_op(self.mol, inversion):
         self.symmops["-I"] = inversion
         logger.debug("Inversion center present")
     else:
         self.symmops["-I"] = None
     self.nrot = 0
     self.nref = 0
     self.analyze()
     if self.schoenflies in ["C1v", "C1h"]:
         self.schoenflies = "Cs"
Exemple #2
0
    def find_spherical_axes(self):
        """Looks for R5, R4, R3 and R2 axes in spherical top molecules.  Point
        group T molecules have only one unique 3-fold and one unique 2-fold
        axis. O molecules have one unique 4, 3 and 2-fold axes. I molecules
        have a unique 5-fold axis.
        """
        rot_present = {2: False, 3: False, 4: False, 5: False}
        test_set = self.find_possible_equivalent_positions()
        for c1, c2, c3 in itertools.combinations(test_set, 3):
            for cc1, cc2 in itertools.combinations([c1, c2, c3], 2):
                if not rot_present[2]:
                    test_axis = cc1 + cc2
                    if numpy.linalg.norm(test_axis) > self.tol:
                        op = rotation(axis=test_axis, order=2)
                        if is_valid_op(self.mol, op):
                            logger.debug("Found axis with order {0}".format(2))
                            rot_present[2] = True
                            self.symmops["C"] += [
                                (2, test_axis, op),
                            ]
                            self.nrot += 1

            test_axis = numpy.cross(c2 - c1, c3 - c1)
            if numpy.linalg.norm(test_axis) > self.tol:
                for order in (3, 4, 5):
                    if not rot_present[order]:
                        op = rotation(axis=test_axis, order=order)
                        if is_valid_op(self.mol, op):
                            logger.debug(
                                "Found axis with order {0}".format(order))
                            rot_present[order] = True
                            self.symmops["C"] += [
                                (order, test_axis, op),
                            ]
                            self.nrot += 1
                            break
            if (rot_present[2] & rot_present[3] &
                (rot_present[4] | rot_present[5])):
                break
        return
Exemple #3
0
 def find_reflection_plane(self, axis):
     """Looks for mirror symmetry of specified type about axis.  Possible
     types are "h" or "vd".  Horizontal (h) mirrors are perpendicular to
     the axis while vertical (v) or diagonal (d) mirrors are parallel.  v
     mirrors has atoms lying on the mirror plane while d mirrors do
     not.
     """
     symmop = None
     # First test whether the axis itself is the normal to a mirror plane.
     op = reflection(axis)
     if is_valid_op(self.mol, op):
         symmop = ("h", axis, op)
     else:
         # Iterate through all pairs of atoms to find mirror
         for s1, s2 in itertools.combinations(self.mol, 2):
             if s1.symbol == s2.symbol:
                 normal = s1.position - s2.position
                 if normal.dot(axis) < self.tol:
                     op = reflection(normal)
                     if is_valid_op(self.mol, op):
                         if self.nrot > 1:
                             symmop = ("d", normal, op)
                             for prev_order, prev_axis, prev_op in self.symmops[
                                     "C"]:
                                 if not numpy.linalg.norm(prev_axis -
                                                          axis) < self.tol:
                                     if numpy.dot(prev_axis,
                                                  normal) < self.tol:
                                         symmop = ("v", normal, op)
                                         break
                         else:
                             symmop = ("v", normal, op)
                         break
     if symmop is not None:
         self.symmops["sigma"] += [
             symmop,
         ]
         return symmop[0]
     else:
         return symmop
Exemple #4
0
 def has_perpendicular_C2(self, axis):
     """Checks for R2 axes perpendicular to unique axis.  For handling
     symmetric top molecules.
     """
     min_set = self.find_possible_equivalent_positions(axis=axis)
     found = False
     for s1, s2 in itertools.combinations(min_set, 2):
         test_axis = numpy.cross(s1 - s2, axis)
         if numpy.linalg.norm(test_axis) > self.tol:
             op = rotation(axis=test_axis, order=2)
             if is_valid_op(self.mol, op):
                 self.symmops["C"] += [(2, test_axis, op), ]
                 self.nrot += 1
                 found = True
     return found
Exemple #5
0
 def analyze_cyclic_groups(self):
     """Handles cyclic group molecules."""
     order, axis, op = max(self.symmops["C"], key=lambda v: v[0])
     self.schoenflies = "C{0}".format(order)
     mirror_type = self.find_reflection_plane(axis)
     if mirror_type == "h":
         self.schoenflies += "h"
     elif mirror_type == "v":
         self.schoenflies += "v"
     elif mirror_type is None:
         rotoref = reflection(axis).dot(
             rotation(axis=axis, order=2 * order))
         if is_valid_op(self.mol, rotoref):
             self.schoenflies = "S{0}".format(2 * order)
             self.symmops["S"] += [(order, axis, rotoref), ]
Exemple #6
0
 def detect_rotational_symmetry(self, axis):
     """Determines the rotational symmetry about supplied axis.  Used only for
     symmetric top molecules which has possible rotational symmetry
     operations > 2.
     """
     min_set = self.find_possible_equivalent_positions(axis=axis)
     max_sym = len(min_set)
     for order in range(max_sym, 0, -1):
         if max_sym % order != 0:
             continue
         op = rotation(axis=axis, order=order)
         if is_valid_op(self.mol, op):
             logger.debug("Found axis with order {0}".format(order))
             self.symmops["C"] += [(order, axis, op), ]
             self.nrot += 1
             return order
     return 1
Exemple #7
0
 def analyze_asymmetric_top(self):
     """Handles assymetric top molecules, which cannot contain rotational
     symmetry larger than 2.
     """
     for axis in self.eigvecs:
         op = rotation(axis=axis, order=2)
         if is_valid_op(self.mol, op):
             self.symmops["C"] += [(2, axis, op), ]
             self.nrot += 1
     if self.nrot == 0:
         logger.debug("No rotation symmetries detected.")
         self.analyze_nonrotational_groups()
     elif self.nrot == 3:
         logger.debug("Dihedral group detected.")
         self.analyze_dihedral_groups()
     else:
         logger.debug("Cyclic group detected.")
         self.analyze_cyclic_groups()
Exemple #8
0
def get_symmetry_elements(mol,
                          max_order=8,
                          epsilon=0.1):
    """Return an array counting the found symmetries
    of the object, up to axes of order max_order.
    Enables fast comparison of compatibility between objects:
    if array1 - array2 > 0, that means object1 fits the slot2
    """
    if len(mol) == 1:
        logger.debug("Point-symmetry detected.")
        symmetries = numpy.array([0, 0, 0, 0, 0, 1])
        return symmetries
    if len(mol) == 2:
        logger.debug("Linear connectivity detected.")
        # simplest, linear case
        symmetries = numpy.array([1, 1, 0, 1, 1, 2])
        return symmetries
    mol.center(about=0)
    # ensure there is a sufficient distance between connections
    dist = mol.get_all_distances().mean()
    if dist < 10.0:
        alpha = 10.0 / dist
        mol.positions = mol.positions.dot(numpy.eye(3) * alpha)
    logger.debug("DIST {}".format(dist))
    axes = get_potential_axes(mol)
    # array for the operations:
    # size = (1inversion+rotationorders+rotinvorders+2planes+1multiplicity)
    symmetries = numpy.zeros(4 + 2 * max_order)
    # inversion
    inv = -1.0 * numpy.eye(3)
    has_inv = is_valid_op(mol, inv)
    symmetries[0] += int(has_inv)
    # rotations:
    principal_order = 1
    principal_axes = []
    for axis in axes:
        for order in range(2, max_order + 1):
            rot = rotation(axis, order)
            has_rot = is_valid_op(mol, rot)
            symmetries[order - 1] += int(has_rot)
            if has_rot:
                logger.debug("Detected: C{order}".format(order=order))
            # bookkeeping for the planes
            if has_rot and order > principal_order:
                principal_order = order
                principal_axes = [axis, ]
            elif has_rot and order == principal_order:
                principal_axes.append(axis)
    # planes
    for axis in axes:
        ref = reflection(axis)
        has_ref = is_valid_op(mol, ref)
        if has_ref:
            dots = [abs(axis.dot(max_axis))
                    for max_axis in principal_axes]
            if not dots:
                continue
            mindot = numpy.amin(dots)
            maxdot = numpy.amax(dots)
            if maxdot > 1.0 - epsilon:
                # sigma h
                symmetries[-2] += 1
                logger.debug("Detected: sigma h")
            elif mindot < epsilon:
                # sigma vd
                symmetries[-3] += 1
                logger.debug("Detected: sigma vd")
    # rotoreflections
    for axis in axes:
        ref = reflection(axis)
        for order in range(2, max_order + 1):
            rot = rotation(axis, order)
            rr = rot.dot(ref)
            has_rr = is_valid_op(mol, rr)
            symmetries[order + max_order - 2] += int(has_rr)
            if has_rr:
                logger.debug("Detected: S{order}".format(order=order))
    # multiplicity
    symmetries[-1] = len([x for x in mol if x.symbol == "X"])
    return numpy.array(symmetries, dtype=int)