Пример #1
0
 def is_dihedral(self):
     """ Whether or not the reflection is a sigma_d
     """
     if self.principal_reflection:
         return False
     for atom in self.molecule:
         # If there's an atom in the plane, it's a sigma_v.  If there's an atom in the direction of the normal (or it's negative),
         # it's sigma_v.  Otherwise, it's a sigma_d.  If the atom is at the origin, ignore it.
         if atom.pos.is_zero():
             continue
         elif SymmetryOperation.is_same_axis(self.axis, atom.pos):
             return False
         elif SymmetryOperation.is_perpendicular(self.axis, atom.pos):
             return False
     return True
Пример #2
0
 def is_dihedral(self):
     """ Whether or not the reflection is a sigma_d
     """
     if self.principal_reflection:
         return False
     for atom in self.molecule:
         # If there's an atom in the plane, it's a sigma_v.  If there's an atom in the direction of the normal (or it's negative),
         # it's sigma_v.  Otherwise, it's a sigma_d.  If the atom is at the origin, ignore it.
         if atom.pos.is_zero():
             continue
         elif SymmetryOperation.is_same_axis(self.axis, atom.pos):
             return False
         elif SymmetryOperation.is_perpendicular(self.axis, atom.pos):
             return False
     return True
Пример #3
0
def check_improper_rotation(atoms,
                            vector,
                            angle,
                            center,
                            n,
                            result,
                            order_no=0):
    a = atoms.copy()
    a.rotate(vector, a=angle, center=center)
    positions = mirror_through_plane(a, vector)
    equals = get_equals(atoms, positions)
    on = order_no
    # n = 2 is equal with inversion operator
    if n == 2 or (float(order_no + 1) / float(n)) == 0.5:
        return
    if equals != None:
        operation_name = "S%i" % n
        while order_no > 0:
            operation_name += "'"
            order_no -= 1
        result.append(
            SymmetryOperation(operation_name,
                              equals,
                              None,
                              vector=vector,
                              magnitude=n,
                              type='S',
                              order_no=on))
Пример #4
0
def check_mirror(atoms, normal_vector, debug=False):
    com = atoms.get_center_of_mass()
    # normalize vector
    L = numpy.linalg.norm(normal_vector)
    normal_vector /= L
    mirrored = mirror_through_plane(atoms, normal_vector, debug=debug)
    if debug:
        print normal_vector
        print atoms.get_positions()
        print mirrored
        from ice_package.help_methods import get_oxygens
        import ase
        ase.visualize.view(get_oxygens(mirrored))
        ase.visualize.view(atoms)
        print normal_vector
        raw_input("Continue")
    result = get_equals(atoms, mirrored, debug=debug)
    if result == None:
        return None
    return SymmetryOperation('sigma',
                             result,
                             None,
                             vector=normal_vector,
                             magnitude=1,
                             order_no=0,
                             type='sigma')
Пример #5
0
 def element_with_matrix(self, mat):
     """ Returns the element that has the matrix `mat` in the group `self`.
     Raises a `GroupTheoryError` indicating the group is not closed if no such element is found.
     """
     for op in self:
         if SymmetryOperation.is_same_matrix(op.matrix, mat):
             return op
     mat_list = [str(op.matrix) for op in sorted(self, key=lambda o: (o.matrix-mat).norm())]
     raise GroupTheoryError("Group not closed:  In group with elements: \n[" + ", ".join(str(el) for el in self)
                            + "],\n Could not find element with the following matrix:\n"
                            + str(mat) + " in list (" + str(len(mat_list))
                            + " operations total):\n" + ",\n".join(mat_list))
Пример #6
0
def check_inversion_center(atoms):
    positions = positions_related_to_center_of_mass(atoms,
                                                    atoms.get_positions())
    positions = -positions + atoms.get_center_of_mass()
    result = get_equals(atoms, positions)
    if result == None:
        return None
    print "Inversion center found"
    return SymmetryOperation("i",
                             result,
                             None,
                             type='i',
                             order_no=0,
                             magnitude=1)
Пример #7
0
 def element_with_matrix(self, mat):
     """ Returns the element that has the matrix `mat` in the group `self`.
     Raises a `GroupTheoryError` indicating the group is not closed if no such element is found.
     """
     for op in self:
         if SymmetryOperation.is_same_matrix(op.matrix, mat):
             return op
     mat_list = [
         str(op.matrix)
         for op in sorted(self, key=lambda o: (o.matrix - mat).norm())
     ]
     raise GroupTheoryError(
         "Group not closed:  In group with elements: \n[" +
         ", ".join(str(el) for el in self) +
         "],\n Could not find element with the following matrix:\n" +
         str(mat) + " in list (" + str(len(mat_list)) +
         " operations total):\n" + ",\n".join(mat_list))
Пример #8
0
def check_single_rotation(atoms, vector, angle, center, n, result, order_no=0):
    a = atoms.copy()
    a.rotate(vector, a=angle, center=center)
    positions = a.get_positions()
    equals = get_equals(atoms, positions)
    on = order_no
    if equals != None:
        operation_name = "C%i" % n
        while order_no > 0:
            operation_name += "'"
            order_no -= 1
        result.append(
            SymmetryOperation(operation_name,
                              equals,
                              None,
                              vector=vector,
                              magnitude=n,
                              type='C',
                              order_no=on))
Пример #9
0
 def _get_name(self):
     """ Get the name of the point group
     """
     # Using a flow charts from http://www.mineralatlas.com/fga/image007.gif and
     # http://capsicum.me.utexas.edu/ChE386K/html/flowchart_point_groups.htm
     # If two or more C_n with n > 2...
     if len(
         [rot for rot in self.rotations if rot.n > 2 and rot.exponent == 1
          ]) >= 2:
         # 12 C5 axes?
         if self.num_C_n_axes(5) == 12:
             if self.inversion is None:
                 self.name = 'I'
                 return
             else:
                 self.name = 'I_h'
                 return
         # 6 C4s?
         elif self.num_C_n_axes(4) == 6:
             if self.inversion is None:
                 self.name = 'O'
                 return
             else:
                 self.name = 'O_h'
                 return
         # 4 C3s?
         elif self.num_C_n_axes(3) == 4:
             # 8 C3s?
             if self.inversion is None:
                 if len(self.reflections) == 6:
                     self.name = 'T_d'
                     return
                 else:
                     self.name = 'T'
                     return
             else:
                 self.name = 'T_h'
                 return
         else:
             raise GroupTheoryError(
                 "Don't know the name of group with classes: " +
                 str(self.classes) + ".  (Perhaps adjust tolerances?)")
     elif len(self.rotations) > 0:
         highest_Cn = self.rotations[0]
         highest_n = highest_Cn.n
         highest_axis = highest_Cn.axis
         count = 0
         for rot in self.rotations:
             if rot.n == 2 and SymmetryOperation.is_perpendicular(
                     highest_axis, rot.axis):
                 count += 1
         if count == highest_n:
             if any(ref.is_principal_reflection()
                    for ref in self.reflections):
                 self.name = 'D_' + str(highest_n) + 'h'
                 return
             elif len(self.reflections) == highest_n:
                 self.name = 'D_' + str(highest_n) + 'd'
                 return
             elif len(self.reflections) == 0:
                 self.name = 'D_' + str(highest_n)
             else:
                 raise GroupTheoryError(
                     "Don't know the name of group with classes: " +
                     str(self.classes) + ".  (Perhaps adjust tolerances?)")
         else:
             if any(ref.is_principal_reflection()
                    for ref in self.reflections):
                 self.name = 'C_' + str(highest_n) + 'h'
                 return
             elif len(self.reflections) == highest_n:
                 self.name = 'C_' + str(highest_n) + 'v'
                 return
             elif any(irot.n == 2 * highest_n
                      for irot in self.improper_rotations):
                 self.name = 'S_' + str(2 * highest_n)
                 return
             else:
                 self.name = 'C_' + str(highest_n)
                 return
     else:
         if len(self.reflections) == 1:
             self.name = 'C_s'
             return
         elif not self.inversion is None:
             self.name = 'C_i'
             return
         elif len(self) == 1:
             self.name = 'C_1'
         else:
             raise GroupTheoryError(
                 "Don't know the name of group with classes: " +
                 str(self.classes) + ".  (Perhaps adjust tolerances?)")
Пример #10
0
    def _name_operations(self):
        """ Determines the most-likely-to-be human-readable names for the operations.
        """

        # Figure out the principal reflections (sigma_h's)
        principal_rotations = []
        for k, g in itertools.groupby(sorted(self.rotations),
                                      attrgetter('n', 'exponent')):
            principal_rotations = list(g)
            break
        if len(principal_rotations) > 0:
            if principal_rotations[0].n > 2:
                # Mark them all as sigma_h's
                for rot in principal_rotations:
                    for op in self.reflections:
                        if SymmetryOperation.is_same_axis(op.axis, rot.axis):
                            op.principal_reflection = True
            else:
                # Otherwise, just choose the Z axis
                for op in self.reflections:
                    if SymmetryOperation.is_same_axis(
                            op.axis, principal_rotations[0].axis):
                        op.principal_reflection = True
                        break
        self.operations.sort()
        self._rotations = None
        self._improper_rotations = None
        self._reflections = None
        self.identity_element.name = "E"
        if not self.inversion is None:
            self.inversion.name = 'i'
        for key, rotiter in itertools.groupby(self.rotations, attrgetter('n')):
            rotgrp = list(rotiter)
            prime_count = 0
            labels = []
            order = rotgrp[0].n
            if len(rotgrp) == rotgrp[0].n - 1:
                # only one axis, label it simply
                rotgrp[0].name = "C_" + str(order)
                for i in xrange(1, len(rotgrp)):
                    rotgrp[i].name = "C_" + str(order) + "^" + str(
                        rotgrp[i].exponent)
            else:
                naxes = len([x for x in rotgrp if x.exponent == 1])
                has_paren_label = False
                for i, rot in enumerate(rotgrp):
                    if i < naxes:
                        if SymmetryOperation.is_same_axis(
                                rot.axis, Vector(0, 0, 1)):
                            labels.append("(z)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(z)"
                        elif SymmetryOperation.is_same_axis(
                                rot.axis, Vector(0, 1, 1)):
                            labels.append("(y)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(y)"
                        elif SymmetryOperation.is_same_axis(
                                rot.axis, Vector(1, 0, 0)):
                            labels.append("(x)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(x)"
                        else:
                            label = "'" * (prime_count +
                                           (1 if has_paren_label else 0))
                            labels.append(label)
                            prime_count += 1
                            rot.name = "C_" + str(order) + label
                    else:
                        rot.name = "C_" + str(order) + labels[
                            i % naxes] + "^" + str(rot.exponent)
        for key, rotiter in itertools.groupby(self.improper_rotations,
                                              attrgetter('n')):
            rotgrp = list(rotiter)
            prime_count = 0
            labels = []
            order = rotgrp[0].n
            if len(rotgrp) == rotgrp[0].n - 1:
                # only one axis, label it simply
                rotgrp[0].name = "S_" + str(order)
                for i in xrange(1, len(rotgrp)):
                    rotgrp[i].name = "S_" + str(order) + "^" + str(
                        rotgrp[i].exponent)
            else:
                has_paren_label = False
                naxes = len([x for x in rotgrp if x.exponent == 1])
                for i, rot in enumerate(rotgrp):
                    if i < naxes:
                        if SymmetryOperation.is_same_axis(
                                rot.axis, Vector(0, 0, 1)):
                            labels.append("(z)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(z)"
                        elif SymmetryOperation.is_same_axis(
                                rot.axis, Vector(0, 1, 0)):
                            labels.append("(y)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(y)"
                        elif SymmetryOperation.is_same_axis(
                                rot.axis, Vector(1, 0, 0)):
                            labels.append("(x)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(x)"
                        else:
                            label = "'" * (prime_count +
                                           (1 if has_paren_label else 0))
                            labels.append(label)
                            prime_count += 1
                            rot.name = "S_" + str(order) + label
                    else:
                        rot.name = "S_" + str(order) + labels[
                            i % naxes] + "^" + str(rot.exponent)
        prime_count = {'v': 0, 'd': 0, 'h': 0}
        has_paren_label = False
        for ref in self.reflections:
            subscript = ''
            if ref.is_principal_reflection():
                subscript = 'h'
            elif ref.is_dihedral():
                subscript = 'd'
            else:
                subscript = 'v'
            if SymmetryOperation.is_same_axis(ref.axis, Vector(0, 0, 1)):
                ref.name = "sigma_" + subscript + "(xy)"
                has_paren_label = True
            elif SymmetryOperation.is_same_axis(ref.axis, Vector(0, 1, 0)):
                ref.name = "sigma_" + subscript + "(xz)"
                has_paren_label = True
            elif SymmetryOperation.is_same_axis(ref.axis, Vector(1, 0, 0)):
                ref.name = "sigma_" + subscript + "(yz)"
                has_paren_label = True
            else:
                label = "'" * (prime_count[subscript] +
                               (1 if has_paren_label else 0))
                prime_count[subscript] += 1
                ref.name = "sigma_" + subscript + label
        self.classes.sort(key=attrgetter('first_element'))
Пример #11
0
def get_periodic_symmetry_operations(atoms, error_tolerance=0.01, debug=False):
    from ase.utils import irotate
    from ase.visualize import view
    from pyspglib import spglib
    #symmetry = spglib.get_symmetry(atoms, symprec=1e-5)
    symmetry = spglib.get_symmetry(atoms, symprec=1e-2)
    dataset = spglib.get_symmetry_dataset(atoms, symprec=1e-2)

    result = []
    if debug:
        cell, scaled_positions, numbers = spglib.find_primitive(atoms,
                                                                symprec=1e-5)
        a = Atoms(symbols='O4',
                  cell=cell,
                  scaled_positions=scaled_positions,
                  pbc=True)
        #symmetry = spglib.get_symmetry(a, symprec=1e-2)
        #dataset = spglib.get_symmetry_dataset(a, symprec=1e-2)
        print dataset['equivalent_atoms']
        print dataset['international']
        print dataset['hall']
        print dataset['wyckoffs']
        print dataset['transformation_matrix']
        print "Number of symmetry operations %i" % len(dataset['rotations'])
    for i in range(dataset['rotations'].shape[0]):

        new_atoms = atoms.copy()
        test = atoms.copy()
        rot = dataset['rotations'][i]
        trans = dataset['translations'][i]
        if debug:
            x, y, z = irotate(rot)
            #print x, y, z
            print "------------------- %i -----------------------" % i
            print "Rotation"
            print rot
            print "Translation"
            print trans
        new_pos = new_atoms.get_scaled_positions()

        for l, pos in enumerate(new_atoms.get_scaled_positions()):
            #print new_pos[l]
            new_pos[l] = (numpy.dot(rot, pos))
            new_pos[l] += trans
            #print new_pos[l]
        new_atoms.set_scaled_positions(new_pos)
        equals = get_equals_periodic(atoms,
                                     new_atoms,
                                     error_tolerance=error_tolerance,
                                     debug=debug)
        if equals != None:
            so = SymmetryOperation(str(i),
                                   equals,
                                   None,
                                   vector=None,
                                   magnitude=1,
                                   rotation_matrix=rot,
                                   translation_vector=trans)
            #if debug:
            #    print so
            result.append(so)
        else:
            print "Equivalent not found"
            #view(test)
            #view(new_atoms)
            #raw_input()

    return result
Пример #12
0
def get_identity_operator(atoms):
    equals = numpy.arange(0, len(atoms), 1)
    return SymmetryOperation("Identity", equals, None)
Пример #13
0
 def _get_name(self):
     """ Get the name of the point group
     """
     # Using a flow charts from http://www.mineralatlas.com/fga/image007.gif and
     # http://capsicum.me.utexas.edu/ChE386K/html/flowchart_point_groups.htm
     # If two or more C_n with n > 2...
     if len([rot for rot in self.rotations if rot.n > 2 and rot.exponent == 1 ]) >= 2:
         # 12 C5 axes?
         if self.num_C_n_axes(5) == 12:
             if self.inversion is None:
                 self.name = 'I'
                 return
             else:
                 self.name = 'I_h'
                 return
         # 6 C4s?
         elif self.num_C_n_axes(4) == 6:
             if self.inversion is None:
                 self.name = 'O'
                 return
             else:
                 self.name = 'O_h'
                 return
         # 4 C3s?
         elif self.num_C_n_axes(3) == 4:
             # 8 C3s?
             if self.inversion is None:
                 if len(self.reflections) == 6:
                     self.name = 'T_d'
                     return
                 else:
                     self.name = 'T'
                     return
             else:
                 self.name = 'T_h'
                 return
         else:
             raise GroupTheoryError("Don't know the name of group with classes: " + str(self.classes)
                                     + ".  (Perhaps adjust tolerances?)")
     elif len(self.rotations) > 0:
         highest_Cn = self.rotations[0]
         highest_n = highest_Cn.n
         highest_axis = highest_Cn.axis
         count = 0
         for rot in self.rotations:
             if rot.n == 2 and SymmetryOperation.is_perpendicular(highest_axis, rot.axis):
                 count += 1
         if count == highest_n:
             if any(ref.is_principal_reflection() for ref in self.reflections):
                 self.name = 'D_' + str(highest_n) + 'h'
                 return
             elif len(self.reflections) == highest_n:
                 self.name = 'D_' + str(highest_n) + 'd'
                 return
             elif len(self.reflections) == 0:
                 self.name = 'D_' + str(highest_n)
             else:
                 raise GroupTheoryError("Don't know the name of group with classes: " + str(self.classes)
                                         + ".  (Perhaps adjust tolerances?)")
         else:
             if any(ref.is_principal_reflection() for ref in self.reflections):
                 self.name = 'C_' + str(highest_n) + 'h'
                 return
             elif len(self.reflections) == highest_n:
                 self.name = 'C_' + str(highest_n) + 'v'
                 return
             elif any(irot.n == 2*highest_n for irot in self.improper_rotations):
                 self.name = 'S_' + str(2*highest_n)
                 return
             else:
                 self.name = 'C_' + str(highest_n)
                 return
     else:
         if len(self.reflections) == 1:
             self.name = 'C_s'
             return
         elif not self.inversion is None:
             self.name = 'C_i'
             return
         elif len(self) == 1:
             self.name = 'C_1'
         else:
             raise GroupTheoryError("Don't know the name of group with classes: " + str(self.classes)
                                     + ".  (Perhaps adjust tolerances?)")
Пример #14
0
    def _name_operations(self):
        """ Determines the most-likely-to-be human-readable names for the operations.
        """

        # Figure out the principal reflections (sigma_h's)
        principal_rotations = []
        for k, g in itertools.groupby(sorted(self.rotations), attrgetter('n', 'exponent')):
            principal_rotations = list(g)
            break
        if len(principal_rotations) > 0:
            if principal_rotations[0].n > 2:
                # Mark them all as sigma_h's
                for rot in principal_rotations:
                    for op in self.reflections:
                        if SymmetryOperation.is_same_axis(op.axis, rot.axis):
                            op.principal_reflection = True
            else:
                # Otherwise, just choose the Z axis
                for op in self.reflections:
                    if SymmetryOperation.is_same_axis(op.axis, principal_rotations[0].axis):
                        op.principal_reflection = True
                        break
        self.operations.sort()
        self._rotations = None
        self._improper_rotations = None
        self._reflections = None
        self.identity_element.name = "E"
        if not self.inversion is None:
            self.inversion.name = 'i'
        for key, rotiter in itertools.groupby(self.rotations, attrgetter('n')):
            rotgrp = list(rotiter)
            prime_count = 0
            labels = []
            order = rotgrp[0].n
            if len(rotgrp) == rotgrp[0].n - 1:
                # only one axis, label it simply
                rotgrp[0].name = "C_" + str(order)
                for i in xrange(1, len(rotgrp)):
                    rotgrp[i].name = "C_" + str(order) + "^" + str(rotgrp[i].exponent)
            else:
                naxes = len([x for x in rotgrp if x.exponent == 1])
                has_paren_label = False
                for i, rot in enumerate(rotgrp):
                    if i < naxes:
                        if SymmetryOperation.is_same_axis(rot.axis, Vector(0,0,1)):
                            labels.append("(z)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(z)"
                        elif SymmetryOperation.is_same_axis(rot.axis, Vector(0,1,1)):
                            labels.append("(y)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(y)"
                        elif SymmetryOperation.is_same_axis(rot.axis, Vector(1,0,0)):
                            labels.append("(x)")
                            has_paren_label = True
                            rot.name = "C_" + str(order) + "(x)"
                        else:
                            label = "'" * (prime_count + (1 if has_paren_label else 0))
                            labels.append(label)
                            prime_count += 1
                            rot.name = "C_" + str(order) + label
                    else:
                        rot.name = "C_" + str(order) + labels[i % naxes] + "^" + str(rot.exponent)
        for key, rotiter in itertools.groupby(self.improper_rotations, attrgetter('n')):
            rotgrp = list(rotiter)
            prime_count = 0
            labels = []
            order = rotgrp[0].n
            if len(rotgrp) == rotgrp[0].n - 1:
                # only one axis, label it simply
                rotgrp[0].name = "S_" + str(order)
                for i in xrange(1, len(rotgrp)):
                    rotgrp[i].name = "S_" + str(order) + "^" + str(rotgrp[i].exponent)
            else:
                has_paren_label = False
                naxes = len([x for x in rotgrp if x.exponent == 1])
                for i, rot in enumerate(rotgrp):
                    if i < naxes:
                        if SymmetryOperation.is_same_axis(rot.axis, Vector(0,0,1)):
                            labels.append("(z)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(z)"
                        elif SymmetryOperation.is_same_axis(rot.axis, Vector(0,1,0)):
                            labels.append("(y)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(y)"
                        elif SymmetryOperation.is_same_axis(rot.axis, Vector(1,0,0)):
                            labels.append("(x)")
                            has_paren_label = True
                            rot.name = "S_" + str(order) + "(x)"
                        else:
                            label = "'" * (prime_count + (1 if has_paren_label else 0))
                            labels.append(label)
                            prime_count += 1
                            rot.name = "S_" + str(order) + label
                    else:
                        rot.name = "S_" + str(order) + labels[i % naxes] + "^" + str(rot.exponent)
        prime_count = {'v':0, 'd':0,'h':0}
        has_paren_label = False
        for ref in self.reflections:
            subscript = ''
            if ref.is_principal_reflection():
                subscript = 'h'
            elif ref.is_dihedral():
                subscript = 'd'
            else:
                subscript = 'v'
            if SymmetryOperation.is_same_axis(ref.axis, Vector(0,0,1)):
                ref.name = "sigma_"+ subscript + "(xy)"
                has_paren_label = True
            elif SymmetryOperation.is_same_axis(ref.axis, Vector(0,1,0)):
                ref.name = "sigma_" + subscript + "(xz)"
                has_paren_label = True
            elif SymmetryOperation.is_same_axis(ref.axis, Vector(1,0,0)):
                ref.name = "sigma_" + subscript + "(yz)"
                has_paren_label = True
            else:
                label = "'" * (prime_count[subscript] + (1 if has_paren_label else 0))
                prime_count[subscript] += 1
                ref.name = "sigma_" + subscript + label
        self.classes.sort(key=attrgetter('first_element'))