Example #1
0
 def transform(self, symop, **kwargs):
     """Returns new model with new basis: b_new = symop*b_old
     and new coordinates: xyz_new = symop.inv()*xyz_old and the
     THE SAME SPACE GROUP ! WARNING! Take care: symmetry operations are not 
     transformed (at the moment) so this function in its current state 
     is to be used for expanding or contracting the unit cell!
     Symop should be either in symbolic form or be an augmented matrix
     of type sympy.Matrix"""
     if isinstance(symop, sympy.Matrix):
         if symop.shape != (4,4):
             raise IndexError("Wrong shape of the matrix. Correct: 4 x 4 !")
         symop_sympy = symop
     elif isinstance(symop, str):
         symop_sympy = core.xyzt2augmat(symop)
     else: 
         raise TypeError("Wrong type of the symmetry operation. See the docstring !")
     scatterers = copy.deepcopy(self._scatterers)
     fragment = Fragment(scatterers)
     fragment.transform(symop_sympy.inv())
     #print self._symmetry.unit_cell().parameters() #unit_cell().__dict__
     lattice = self._symmetry.unit_cell().parameters()
     pars = []
     pars.extend(lattice[0:3])
     angles = lattice[3:]
     pars.append(0)
     latt_old = sympy.Matrix(pars)
     latt_new = list(latt_old.T*symop_sympy)[0:3]
     latt_new.extend(angles)
     symmetry_new = copy.deepcopy(self._symmetry)
     setattr(symmetry_new, "unit_cell", tuple(latt_new))
     return self.__class__(symmetry_new, [fragment])
Example #2
0
    def leftmult(Cls, self, symop):
        """Returns instance of Fragment obtained from the current instance by
        left multiplication with symop. The initialization of the new
        instance is done according to case 2 described in __init__"""
        if str == type(symop):
            sym_mat = core.xyzt2augmat(symop)
        else:
            sym_mat = symop 
        
        #I am not sure how the triple product modulo should be executed!!!!!
        
        #new_stab = map(
        #        core.modulo_n, core.lstab((self.stab, sym_mat))
        #        )
        new_stab = []
        sym_mat_inv = core.modulo_n(sym_mat.inv(), 1)

        for item in self.stab:
            new_elt = core.modulo_n(core.modulo_n(sym_mat*item,1)*sym_mat_inv,1)
            new_stab.append(new_elt)
        
        #new_stab = [core.modulo_n(core.modulo_n(sym_mat*item,1)*sym_mat.inv(),1) for item in  self.stab]


                
        new_coset = map(core.modulo_n, core.lcoset((self.coset, sym_mat)))

        return Cls(new_stab, new_coset)
Example #3
0
 def coset(self, coset = []):
     coset_list = []
     for symop in coset:
         if str == type(symop):
             coset_list.append(core.xyzt2augmat(symop))
         else:
             coset_list.append(symop)
     self._coset = coset_list
Example #4
0
 def stab(self, stab):
     """See doc string for __init__"""
     stab_list = []
     for item in stab:
         if str == type(item):
             stab_list.append(core.xyzt2augmat(item))
         else:
             stab_list.append(item)
     self._stab = stab_list
Example #5
0
    def shift_stab_origin(self, origin_shift):
        """Shifts origin of the stabilizer of the instance
        IMPORTANT!!! origin_shift is not a modulo operation!!!"""
        if str == type(origin_shift):
            originShift = core.xyzt2augmat(origin_shift)
        else:
            originShift = origin_shift

        items = [] 
        for item in self.stab:
            items.append(originShift*item*originShift.inv())
        self.stab = items
Example #6
0
    def stab(self):
        """Computing stabilizer of a bilayer(or any 2 fragments).
        self.layers must contain 2 Layers L_0 and L_1. 

        IMPORTANT: L_1 = g*L_0 so that if  S_0 = stab(L_0) => L_1 = g*S_0*L_0. 
        The latter means tha coset g*S_O contains all symops to generate L_1
        from L_0.

        The stabilizer of the bilayer is then a union of 2 sets:
            1. set1 contains all common symmetry elements of S_0 and S_1. 
                El-ts of this set simply transform each of the layers into
                itself
            2. set2 contains symmetry elements that transform L_0 into L_1
               and at the same time L_1 into L_0. El-ts that transform L_0
               into L_1 are in the coset:
                g*S_0       (that's why it is important
                            that L_1 = g*L_O, that the corresponding coset
                            attributes of the layers are set correctly)
               so g' from g*S_0 applied to L_1 should yield L_0:
                g'*L_1=L_0 and since g'L_0 = L_1 =>g'*g'L_0 = L_0 => g'*g'
                or g'^2 should belong to S_0.
                Hence set2 contains elements of coset g*S_0 (or L_1.coset)
                which squares belong to S_0.
                """
        if self._stab:
            return self._stab
        #finding overlap between stabilizers of the constituent layers
        stab_overlap = \
                [item for item in self.layers[1].stab
                        if item in self.layers[0].stab]
        #for a layer that is generated from the other one by a stacking oper:
        #finding coset members whose 2 orders belong to stabilizer of the basic
        #layer
        unit_element = core.xyzt2augmat('x,y,z')
        sec_ord_elts = []
        for nr,layer in enumerate(self.layers):
            if unit_element not in layer.coset:
                for symop in layer.coset:
                    if core.modulo_n(symop*symop,1) in self.layers[1-nr].stab \
                            and symop not in stab_overlap:
                            sec_ord_elts.append(symop)

        self._stab = stab_overlap + sec_ord_elts
        #performing some basic checks
        coset_union = self.layers[0].coset + self.layers[1].coset
        #print len(self.layers[0].coset)
        assert core.cosets_are_disjoint([self.layers[0].coset,
            self.layers[1].coset]), "Cosets are not disjoint!"
        
        assert len(self.layers[1].coset) == len(self.layers[0].coset),\
          "Coset attributes for the constituent layers are of different order!"
        return self._stab
Example #7
0
    def build_shift_classes(self):
        """ IMPORTANT: THIS METHOD IS PARTLY HARDCODED, FOR IT ONLY
        ACCOUNTS FOR SHIFTS WITHIN XY PLANE REQUIRED FOR MODELLING
        DISORDER IN ZEOLITE-BETA. IT CAN HOWEVER BE EASILY MODIFIED!!!
        --------------------------------------------------------------
        This method will group fragments into shift classes(which will
        be stored in self.__shift_classes)  in the
        following way:
            1. Find basic fragment within the layer
            2. Find fragments that are obtained from the basic one without
                applying shifts and put them into
                one class, shift_class_0. This is achieved by sear-
                ching for symops in self.stab that have zero shift component,
                applying them to basic_fragment.stab and locating indices of 
                the corresponding fragements within self.
            3.Shift_class_i is produced by applying one of all the possible
              shift vectors (symops of self.stab that have unit rotation
              matrix as their rotation part) to the fragments in 
              zero_group_0, locating so obtained fragments within the layer
              and storing them within as a single group.
            4.The total number of shift_classes so obtained will be equal
              to the number of the possible pure shifts.
            5.Those shift_classes are later employed for the computation of 
              shift vector between two fragments 
            """
            
        self.__shift_classes = []
        shift_class_0 = set()
        basic_fragment = self.basicFragment
        basic_stab = basic_fragment.stab
        all_shifts = set()

        unitAugMat = core.xyzt2augmat('x,y,z')
        zero_shift_xy = unitAugMat[0:2,-1] 
        unit_rot_part = unitAugMat[0:3,0:3]
        
        #Constructing shift_class_0 and filling all_shfits with indices
        #of pure shift symops in self.symop 
        for nr,symop in enumerate(self.stab):
            if symop[0:2,-1] == zero_shift_xy:
                coset = map(core.modulo_n, core.lcoset((basic_stab, symop)))
                index = self.fragment_index(coset)
                shift_class_0.add(index)
            elif symop[0:3, 0:3] == unit_rot_part:
                all_shifts.add(nr)

        self.__shift_classes.append(shift_class_0)
Example #8
0
    def leftmult(Cls, self, symop):
        """to be filled"""
        if str == type(symop):
            sym_mat = core.xyzt2augmat(symop)
        else:
            sym_mat = symop 
        temp = super(Layer,Cls).leftmult(self, symop)
        
        fragments = []

        if self.fragments:
            for fragment in self.fragments:
                fragments.append(Fragment.leftmult(fragment, sym_mat))

        kwargs = {
                    "stab": temp.stab,
                    "coset": temp.coset,
                    "fragments": fragments
                }
                                
        return Cls(**kwargs)
Example #9
0
 def is_basic(self):
     """Basic fragment is the one whose coset contains 'x,y,z' operation
     for it is used to generate other fragments"""
     return core.xyzt2augmat("x,y,z") in self.coset