Example #1
0
    def _generate_orientation(self, pyxtal_mol, pt, oris, wp):
        # Use a Wyckoff_site object for the current site
        self.numattempts += 1
        #ensure that the orientation is good
        count = 0
        while count < 100:
            ori = random.choice(oris).copy()
            ori.change_orientation(flip=True)
            if self._check_ori_dist(ori):
                #print("===good orientation", count, self._check_ori_dist(ori))
                break
            count += 1
            #print(count, self.molecules[0].axes.T[0].dot(ori.r.as_matrix().T))
        #print(ori.r.as_matrix())
        ms0 = mol_site(pyxtal_mol, pt, ori, wp, self.lattice, self.diag)
        # Check distances within the WP
        if ms0.check_distances():
            return ms0
        else:
            # Maximize the smallest distance for the general
            # positions if needed
            if len(pyxtal_mol.mol) > 1 and ori.degrees > 0:
                # bisection method
                def fun_dist(angle, ori, mo, pt):
                    ori0 = ori.copy()
                    ori.change_orientation(angle)
                    ms0 = mol_site(
                        mo,
                        pt,
                        ori,
                        wp,
                        self.lattice,
                        self.diag,
                    )
                    d = ms0.compute_distances()
                    return d

                angle_lo = ori.angle
                angle_hi = angle_lo + np.pi
                fun_lo = fun_dist(angle_lo, ori, pyxtal_mol, pt)
                fun_hi = fun_dist(angle_hi, ori, pyxtal_mol, pt)
                fun = fun_hi
                for it in range(self.ori_attempts):
                    self.numattempts += 1
                    if (fun > 0.8) & (ms0.check_distances()):
                        return ms0
                    angle = (angle_lo + angle_hi) / 2
                    fun = fun_dist(angle, ori, pyxtal_mol, pt)
                    #print('Bisection: ', it, fun)
                    if fun_lo > fun_hi:
                        angle_hi, fun_hi = angle, fun
                    else:
                        angle_lo, fun_lo = angle, fun

        return None
Example #2
0
File: io.py Project: Virts/PyXtal
 def make_mol_site(self, ref=False):
     if ref:
         mol = self.ref_mol
         ori = self.ori
     else:
         mol = self.molecule
         ori = Orientation(np.eye(3))
     mol = self.add_site_props(mol)
     pmol = pyxtal_molecule(mol, symmetrize=False)
     site = mol_site(pmol, self.position, ori, self.wyc, self.lattice, self.diag)
     return site
Example #3
0
 def fun_dist(angle, ori, mo, pt):
     ori0 = ori.copy()
     ori.change_orientation(angle)
     ms0 = mol_site(
         mo,
         pt,
         ori,
         wp,
         self.lattice,
         self.diag,
     )
     d = ms0.compute_distances()
     return d
Example #4
0
 def make_mol_sites(self):
     """
     generate the molecular wyckoff sites
     """
     ori = Orientation(np.eye(3))
     sites = []
     for mol, pos, wp in zip(self.p_mols, self.positions, self.wps):
         site = mol_site(mol, pos, ori, wp, self.lattice, self.diag)
         #print(pos)
         #print(self.lattice.matrix)
         #print([a.value for a in site.molecule.mol.species])
         #print(site.molecule.mol.cart_coords)
         #print(site._get_coords_and_species(absolute=True)[0][:10])
         sites.append(site)
     return sites
Example #5
0
    def subgroup_by_splitter(self, splitter, eps=0.05):
        """
        transform the crystal to subgroup symmetry from a splitter object
        """
        lat1 = np.dot(splitter.R[:3, :3].T, self.lattice.matrix)
        multiples = np.linalg.det(splitter.R[:3, :3])
        new_struc = deepcopy(self)
        new_struc.group = splitter.H
        lattice = Lattice.from_matrix(lat1, ltype=new_struc.group.lattice_type)
        lattice = lattice.mutate(degree=eps, frozen=True)

        h = splitter.H.number
        split_sites = []
        if self.molecular:
            # below only works when the cell does not change
            for i, site in enumerate(self.mol_sites):
                pos = site.position
                mol = site.molecule
                ori = site.orientation
                coord0 = mol.mol.cart_coords.dot(ori.matrix.T)
                wp1 = site.wp
                ori.reset_matrix(np.eye(3))
                for ops1, ops2 in zip(splitter.G2_orbits[i],
                                      splitter.H_orbits[i]):
                    #reset molecule
                    coord1 = np.dot(coord0, ops1[0].affine_matrix[:3, :3].T)
                    _mol = mol.copy()
                    _mol.reset_positions(coord1)

                    pos0 = apply_ops(pos, ops1)[0]
                    pos0 -= np.floor(pos0)
                    pos0 += eps * (np.random.sample(3) - 0.5)

                    wp, _ = Wyckoff_position.from_symops(ops2,
                                                         h,
                                                         permutation=False)
                    split_sites.append(mol_site(_mol, pos0, ori, wp, lattice))
            new_struc.mol_sites = split_sites
            new_struc.numMols = [
                int(multiples * numMol) for numMol in self.numMols
            ]

        else:
            for i, site in enumerate(self.atom_sites):
                pos = site.position
                for ops1, ops2 in zip(splitter.G2_orbits[i],
                                      splitter.H_orbits[i]):
                    pos0 = apply_ops(pos, ops1)[0]
                    pos0 -= np.floor(pos0)
                    pos0 += eps * (np.random.sample(3) - 0.5)
                    wp, _ = Wyckoff_position.from_symops(ops2,
                                                         h,
                                                         permutation=False)
                    split_sites.append(atom_site(wp, pos0, site.specie))

            new_struc.atom_sites = split_sites
            new_struc.numIons = [
                int(multiples * numIon) for numIon in self.numIons
            ]
        new_struc.lattice = lattice
        new_struc.source = 'Wyckoff Split'

        return new_struc
Example #6
0
    def _subgroup_by_splitter(self, splitter, eps=0.05, mut_lat=True):
        """
        transform the crystal to subgroup symmetry from a splitter object

        Args:
            splitter: wyckoff splitter object
            eps (float): maximum atomic displacement in Angstrom
            mut_lat (bool): whether or not mutate the lattice
        """
        lat1 = np.dot(splitter.R[:3,:3].T, self.lattice.matrix)
        multiples = np.linalg.det(splitter.R[:3,:3])
        new_struc = self.copy()
        new_struc.group = splitter.H
        lattice = Lattice.from_matrix(lat1, ltype=new_struc.group.lattice_type)
        if mut_lat:
            lattice=lattice.mutate(degree=eps, frozen=True)

        h = splitter.H.number
        split_sites = []
        if self.molecular:
            # below only works when the cell does not change
            for i, site in enumerate(self.mol_sites):
                pos = site.position
                mol = site.molecule
                ori = site.orientation
                coord0 = mol.mol.cart_coords.dot(ori.matrix.T)
                coord0 = np.dot(coord0, splitter.R[:3,:3])

                wp1 = site.wp
                ori.reset_matrix(np.eye(3))
                id = 0
                for ops1, ops2 in zip(splitter.G2_orbits[i], splitter.H_orbits[i]):
                    #reset molecule
                    rot = wp1.generators_m[id].affine_matrix[:3,:3].T
                    coord1 = np.dot(coord0, rot)
                    _mol = mol.copy()
                    _mol.reset_positions(coord1)

                    pos0 = apply_ops(pos, ops1)[0]
                    pos0 -= np.floor(pos0)
                    dis = (np.random.sample(3) - 0.5).dot(self.lattice.matrix)
                    dis /= np.linalg.norm(dis)
                    pos0 += eps*dis*(np.random.random()-0.5)
                    wp, _ = Wyckoff_position.from_symops(ops2, h, permutation=False)
                    if h in [7, 14] and self.group.number == 31:
                        diag = True
                    else:
                        diag = self.diag
                    split_sites.append(mol_site(_mol, pos0, ori, wp, lattice, diag))
                    id += wp.multiplicity
            new_struc.mol_sites = split_sites
            new_struc.numMols = [int(multiples*numMol) for numMol in self.numMols]

        else:
            for i, site in enumerate(self.atom_sites):
                pos = site.position
                for ops1, ops2 in zip(splitter.G2_orbits[i], splitter.H_orbits[i]):
                    pos0 = apply_ops(pos, ops1)[0]
                    pos0 -= np.floor(pos0)
                    dis = (np.random.sample(3) - 0.5).dot(self.lattice.matrix)
                    dis /= np.linalg.norm(dis)
                    pos0 += np.dot(eps*dis*(np.random.random()-0.5), self.lattice.inv_matrix)
                    wp, _ = Wyckoff_position.from_symops(ops2, h, permutation=False)
                    split_sites.append(atom_site(wp, pos0, site.specie))

            new_struc.atom_sites = split_sites
            new_struc.numIons = [int(multiples*numIon) for numIon in self.numIons]
        new_struc.lattice = lattice
        new_struc.source = 'subgroup'

        return new_struc