Пример #1
0
    def from_1D_dicts(cls, dicts):
        from pyxtal.molecule import pyxtal_molecule, Orientation

        mol = pyxtal_molecule(mol=dicts['smile'] + '.smi')
        rdkit_mol = mol.rdkit_mol(mol.smile)
        conf = rdkit_mol.GetConformer(0)
        #print("try")
        #print(conf.GetPositions()[:3])
        #print(dicts["rotor"])
        if dicts['reflect']:
            mol.set_torsion_angles(conf, dicts["rotor"], False)
        #    print(mol.set_torsion_angles(conf, dicts["rotor"], True))
        #    #import sys; sys.exit()
        xyz = mol.set_torsion_angles(conf, dicts["rotor"], dicts['reflect'])
        mol.reset_positions(xyz)
        g = dicts["number"]
        index = dicts["index"]
        dim = dicts["dim"]
        matrix = R.from_euler('zxy', dicts["orientation"],
                              degrees=True).as_matrix()
        orientation = Orientation(matrix)
        #if dicts['reflect']:
        #    print('load'); print(xyz[:3])
        #    print("aaaaaaaaaaaaaa"); print(xyz[:3].dot(orientation.matrix.T))
        #    print("matrix"); print(orientation.matrix)
        wp = Wyckoff_position.from_group_and_index(g, index, dim)
        diag = dicts["diag"]
        lattice = Lattice.from_matrix(dicts["lattice"],
                                      ltype=dicts["lattice_type"])
        position = dicts[
            "center"]  #np.dot(dicts["center"], lattice.inv_matrix)

        return cls(mol, position, orientation, wp, lattice, diag)
Пример #2
0
    def subgroup_by_splitter(self, splitter, eps=0.05):
        lat1 = np.dot(splitter.R[:3, :3].T, self.lattice.matrix)
        multiples = np.linalg.det(splitter.R[:3, :3])
        split_sites = []
        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,
                                                     group=splitter.H.number,
                                                     permutation=False)
                split_sites.append(atom_site(wp, pos0, site.specie))
        new_struc = deepcopy(self)
        new_struc.group = splitter.H
        lattice = Lattice.from_matrix(lat1, ltype=new_struc.group.lattice_type)
        new_struc.lattice = lattice.mutate(degree=0.01, frozen=True)
        new_struc.atom_sites = split_sites
        new_struc.numIons = [
            int(multiples * numIon) for numIon in self.numIons
        ]
        new_struc.source = 'Wyckoff Split'

        return new_struc
Пример #3
0
    def from_pymatgen(self, structure):
        """
        Load the seed structure from Pymatgen/ASE/POSCAR/CIFs
        """
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer as sga
        try:
            # needs to do it twice in order to get the conventional cell
            s = sga(structure)
            structure = s.get_refined_structure()
            s = sga(structure)
            sym_struc = s.get_symmetrized_structure()
            number = s.get_space_group_number()
        except:
            print("Failed to load the Pymatgen structure")
            self.valid = False

        if self.valid:
            d = sym_struc.composition.as_dict()
            species = [key for key in d.keys()]
            numIons = []
            for ele in species:
                numIons.append(int(d[ele]))
            self.numIons = numIons
            self.species = species
            self.group = Group(number)
            atom_sites = []
            for i, site in enumerate(sym_struc.equivalent_sites):
                pos = site[0].frac_coords
                wp = Wyckoff_position.from_group_and_index(
                    number, sym_struc.wyckoff_symbols[i])
                specie = site[0].specie.number
                atom_sites.append(atom_site(wp, pos, specie))
            self.atom_sites = atom_sites
            self.lattice = Lattice.from_matrix(sym_struc.lattice.matrix,
                                               ltype=self.group.lattice_type)
Пример #4
0
 def optimize_lattice(self):
     """
     optimize the lattice if the cell has a bad inclination angles
     """
     for i in range(5):
         lattice, trans, opt = self.lattice.optimize()
         if opt:
             for site in self.mol_sites:
                 pos_absolute = np.dot(site.position, self.lattice.matrix)
                 pos_frac = pos_absolute.dot(lattice.inv_matrix)
                 site.position = pos_frac - np.floor(pos_frac)
                 site.lattice = lattice
                 # for P21/c, Pc, C2/c, check if opt the inclination angle
                 if self.group.number in [7, 14, 15]:
                     for j, op in enumerate(site.wp.ops):
                         vec = op.translation_vector.dot(trans)
                         vec -= np.floor(vec)
                         op1 = op.from_rotation_and_translation(
                             op.rotation_matrix, vec)
                         site.wp.ops[j] = op1
             #to do needs to update diag if necessary
             _, perm = Wyckoff_position.from_symops(site.wp.ops,
                                                    self.group.number)
             if not isinstance(perm, list):
                 self.diag = True
             else:
                 self.diag = False
             self.lattice = lattice
         else:
             break
Пример #5
0
 def test_P21n(self):
     strs = [
         "x, y, z",
         "-x, -y, -z",
         "-x+1/2, y+1/2, -z+1/2",
         "x+1/2, -y+1/2, z+1/2",
     ]
     wyc, perm = Wyckoff_position.from_symops(strs)
     self.assertTrue(wyc.number == 14)
Пример #6
0
    def _find_gen_wyckoff_in_subgroup(self, groups=None):
        """
        Symmetry transformation
        group -> subgroup
        At the moment we only consider 
        for multiplicity 2: P-1, P21, P2, Pm and Pc
        to add: for multiplicity 4: P21/c, P212121
        Permutation is allowed
        """
        from pyxtal.symmetry import Wyckoff_position

        pos = self.position
        wp0 = self.wp
        pos0 = apply_ops(pos, wp0)

        if len(wp0) == 2:
            if self.diag:  # P21/n -> Pn
                #print("----------P21n----------")
                wp1 = Wyckoff_position.from_group_and_index(7, 0)
                wp1.diagonalize_symops()
                axes = [[0, 1, 2], [2, 1, 0]]
                for ax in axes:
                    pos1 = apply_ops(pos[ax], wp1)
                    diff = (pos1[:, ax] - pos0)[1]
                    diff -= np.floor(diff)
                    if len(diff[diff == 0]) >= 2:
                        #return wp1, ax, pos[ax] - 0.5*diff
                        return Wyckoff_position.from_group_and_index(
                            7, 0), ax, pos[ax] - 0.5 * diff
            else:
                if groups is None:
                    groups = [4, 3, 6, 7, 2]
                if 15 < wp0.number < 71:
                    axes = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 1, 0]]
                elif wp0.number < 15:
                    axes = [[0, 1, 2], [2, 1, 0]]
                for group in groups:
                    wp1 = Wyckoff_position.from_group_and_index(group, 0)
                    for ax in axes:
                        pos1 = apply_ops(pos[ax], wp1)
                        diff = (pos1[:, ax] - pos0)[1]
                        diff -= np.floor(diff)
                        if len(diff[diff == 0]) >= 2:
                            return wp1, ax, pos[ax] - 0.5 * diff
Пример #7
0
 def load_dict(cls, dicts):
     """
     load the sites from a dictionary
     """
     g = dicts["number"]
     index = dicts["index"]
     dim = dicts["dim"]
     PBC = dicts["PBC"]
     position = dicts["position"]
     specie = dicts["specie"]
     wp = Wyckoff_position.from_group_and_index(g, index, dim, PBC)
     return cls(wp, position, specie)
Пример #8
0
    def optimize_lattice(self, iterations=3):
        """
        optimize the lattice if the cell has a bad inclination angles
        """
        #if self.molecular:
        count = 0
        for i in range(iterations):
            lattice, trans, opt = self.lattice.optimize()
            #print(self.lattice, "->", lattice)
            if opt:
                if self.molecular:
                    sites = self.mol_sites
                else:
                    sites = self.atom_sites

                for j, site in enumerate(sites):
                    count += 1
                    pos_abs = np.dot(site.position, self.lattice.matrix)
                    pos_frac = pos_abs.dot(lattice.inv_matrix)
                    pos_frac -= np.floor(pos_frac)
                    if self.molecular:
                        site.lattice = lattice
                    # for P21/c, Pc, C2/c, check if opt the inclination angle
                    ops = site.wp.ops.copy()
                    diag = False
                    if self.group.number in [7, 14, 15]:
                        for k, op in enumerate(ops):
                            vec = op.translation_vector.dot(trans)
                            #print(vec)
                            vec -= np.floor(vec)
                            op1 = op.from_rotation_and_translation(
                                op.rotation_matrix, vec)
                            ops[k] = op1
                        wp, perm = Wyckoff_position.from_symops(
                            ops, self.group.number)

                        if not isinstance(perm, list):
                            diag = True
                        else:
                            diag = False
                            pos_frac = pos_frac[perm]
                        sites[j] = atom_site(wp, pos_frac, site.specie, diag)
                        #print(sites[j].wp)
                    #site.update()

                self.lattice = lattice
                self.diag = diag
            else:
                break
Пример #9
0
    def load_dict(cls, dicts):
        """
        load the sites from a dictionary
        """
        from pyxtal.molecule import pyxtal_molecule, Orientation

        g = dicts["number"]
        index = dicts["index"]
        dim = dicts["dim"]
        mol = pyxtal_molecule.load_dict(dicts["molecule"])
        position = dicts["position"]
        orientation = Orientation.load_dict(dicts['orientation'])
        wp = Wyckoff_position.from_group_and_index(g, index, dim)
        diag = dicts["diag"]
        lattice = Lattice.from_matrix(dicts["lattice"])
        return cls(mol, position, orientation, wp, lattice, diag)
Пример #10
0
    def _from_pymatgen(self, struc, tol=1e-3, a_tol=5.0):
        """
        Load structure from Pymatgen
        should not be used directly
        """
        from pyxtal.util import get_symmetrized_pmg
        #import pymatgen.analysis.structure_matcher as sm

        self.valid = True
        try:
            sym_struc, number = get_symmetrized_pmg(struc, tol, a_tol)
            #print(sym_struc)
            #import sys; sys.exit()
        except TypeError:
            print("Failed to load the Pymatgen structure")
        #    print(struc)
        #    self.valid = False

        if self.valid:
            d = sym_struc.composition.as_dict()
            species = [key for key in d.keys()]
            numIons = []
            for ele in species:
                numIons.append(int(d[ele]))
            self.numIons = numIons
            self.species = species
            self.group = Group(number)
            matrix, ltype = sym_struc.lattice.matrix, self.group.lattice_type
            self.lattice = Lattice.from_matrix(matrix, ltype=ltype)
            atom_sites = []
            for i, site in enumerate(sym_struc.equivalent_sites):
                pos = site[0].frac_coords
                wp = Wyckoff_position.from_group_and_index(number, sym_struc.wyckoff_symbols[i])
                specie = site[0].specie.number
                pos1 = search_matched_position(self.group, wp, pos)
                if pos1 is not None:
                    atom_sites.append(atom_site(wp, pos1, specie))
                else:
                    break

            if len(atom_sites) != len(sym_struc.equivalent_sites):
                raise RuntimeError("Cannot extract the right mapping from spglib")
            else:
                self.atom_sites = atom_sites
Пример #11
0
    def _from_pymatgen(self, struc, tol=1e-3):
        """
        Load structure from Pymatgen
        should not be used directly
        """
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer as sga
        from pyxtal.util import symmetrize
        #import pymatgen.analysis.structure_matcher as sm

        self.valid = True
        try:
            # needs to do it twice in order to get the conventional cell
            pmg = symmetrize(struc, tol)
            s = sga(pmg, symprec=tol)
            sym_struc = s.get_symmetrized_structure()
            number = s.get_space_group_number()
            #print(sym_struc)

        except:
            print("Failed to load the Pymatgen structure")
            self.valid = False

        if self.valid:
            d = sym_struc.composition.as_dict()
            species = [key for key in d.keys()]
            numIons = []
            for ele in species:
                numIons.append(int(d[ele]))
            self.numIons = numIons
            self.species = species
            self.group = Group(number)
            atom_sites = []
            for i, site in enumerate(sym_struc.equivalent_sites):
                pos = site[0].frac_coords
                wp = Wyckoff_position.from_group_and_index(
                    number, sym_struc.wyckoff_symbols[i])
                specie = site[0].specie.number
                atom_sites.append(atom_site(wp, pos, specie, search=True))
            self.atom_sites = atom_sites
            matrix, ltype = sym_struc.lattice.matrix, self.group.lattice_type
            self.lattice = Lattice.from_matrix(matrix, ltype=ltype)
Пример #12
0
    def _get_alternative(self, wyc_set, index):
        """
        get alternative structure representations

        Args:
            tran: affine matrix
            index: the list of transformed wps

        Returns:
            a new pyxtal structure after transformation
        """
        new_struc = self.copy()

        # xyz_string like 'x+1/4,y+1/4,z+1/4'
        xyz_string = wyc_set['Coset Representative'][index]
        op = get_inverse(SymmOp.from_xyz_string(xyz_string))
        #op = SymmOp.from_xyz_string(xyz_string)

        ids = []
        for i, site in enumerate(new_struc.atom_sites):
            id = len(self.group) - site.wp.index - 1
            letter = wyc_set['Transformed WP'][index].split()[id]
            ids.append(letters.index(letter))
            wp = Wyckoff_position.from_group_and_index(self.group.number, letter)
            pos = op.operate(site.position)
            pos1 = search_matched_position(self.group, wp, pos)
            if pos1 is not None:
                new_struc.atom_sites[i] = atom_site(wp, pos1, site.specie)
            else:
                print(pos)
                print(wp)
                raise RuntimeError("Cannot find the right pos")

        # switch lattice
        R = op.affine_matrix[:3,:3] #rotation
        matrix = np.dot(R, self.lattice.matrix)
        new_struc.lattice = Lattice.from_matrix(matrix, ltype=self.group.lattice_type)
        new_struc.source = "Alt. Wyckoff Set: " + xyz_string
        return new_struc, ids
Пример #13
0
def test_modules():
    print("====== Testing functionality for pyXtal version 0.1dev ======")

    global failed_package
    failed_package = False  # Record if errors occur at any level

    reset()

    print("Importing sys...")
    try:
        import sys

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    print("Importing numpy...")
    try:
        import numpy as np

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    I = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

    print("Importing pymatgen...")
    try:
        import pymatgen

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    try:
        from pymatgen.core.operations import SymmOp
    except Exception as e:
        fail(e)
        sys.exit(0)

    print("Importing pandas...")
    try:
        import pandas

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    print("Importing spglib...")
    try:
        import spglib

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    print("Importing openbabel...")
    try:
        import ase

        print("Success!")
    except:
        print(
            "Error: could not import openbabel. Try reinstalling the package.")

    print("Importing pyxtal...")
    try:
        import pyxtal

        print("Success!")
    except Exception as e:
        fail(e)
        sys.exit(0)

    print("=== Testing modules ===")

    # =====database.element=====
    print("pyxtal.database.element")
    reset()
    try:
        import pyxtal.database.element
    except Exception as e:
        fail(e)

    print("  class Element")
    try:
        from pyxtal.database.element import Element
    except Exception as e:
        fail(e)
    if passed():
        for i in range(1, 95):
            if passed():
                try:
                    ele = Element(i)
                except:
                    fail("Could not access Element # " + str(i))
                try:
                    y = ele.sf
                    y = ele.z
                    y = ele.short_name
                    y = ele.long_name
                    y = ele.valence
                    y = ele.valence_electrons
                    y = ele.covalent_radius
                    y = ele.vdw_radius
                    y = ele.get_all(0)
                except:
                    fail("Could not access attribute for element # " + str(i))
                try:
                    ele.all_z()
                    ele.all_short_names()
                    ele.all_long_names()
                    ele.all_valences()
                    ele.all_valence_electrons()
                    ele.all_covalent_radii()
                    ele.all_vdw_radii()
                except:
                    fail("Could not access class methods")

    check()

    # =====database.hall=====
    print("pyxtal.database.hall")
    reset()
    try:
        import pyxtal.database.hall
    except Exception as e:
        fail(e)

    print("  hall_from_hm")
    try:
        from pyxtal.database.hall import hall_from_hm
    except Exception as e:
        fail(e)

    if passed():
        for i in range(1, 230):
            if passed():
                try:
                    hall_from_hm(i)
                except:
                    fail("Could not access hm # " + str(i))

    check()

    # =====database.collection=====
    print("pyxtal.database.collection")
    reset()
    try:
        import pyxtal.database.collection
    except Exception as e:
        fail(e)

    print("  Collection")
    try:
        from pyxtal.database.collection import Collection
    except Exception as e:
        fail(e)

    if passed():
        for i in range(1, 230):
            if passed():
                try:
                    molecule_collection = Collection("molecules")
                except:
                    fail("Could not access hm # " + str(i))

    check()

    # =====operations=====
    print("pyxtal.operations")
    reset()
    try:
        import pyxtal.operations
    except Exception as e:
        fail(e)

    print("  random_vector")
    try:
        from pyxtal.operations import random_vector
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                random_vector()
        except Exception as e:
            fail(e)

    check()

    print("  angle")
    try:
        from pyxtal.operations import angle
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                v1 = random_vector()
                v2 = random_vector()
                angle(v1, v2)
        except Exception as e:
            fail(e)

    check()

    print("  random_shear_matrix")
    try:
        from pyxtal.operations import random_shear_matrix
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                random_shear_matrix()
        except Exception as e:
            fail(e)

    check()

    print("  is_orthogonal")
    try:
        from pyxtal.operations import is_orthogonal
    except Exception as e:
        fail(e)

    if passed():
        try:
            a = is_orthogonal([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
            b = is_orthogonal([[0, 0, 1], [1, 0, 0], [1, 0, 0]])
            if a is True and b is False:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  aa2matrix")
    try:
        from pyxtal.operations import aa2matrix
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                aa2matrix(1, 1, random=True)
        except Exception as e:
            fail(e)

    check()

    print("  matrix2aa")
    try:
        from pyxtal.operations import matrix2aa
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                m = aa2matrix(1, 1, random=True)
                aa = matrix2aa(m)
        except Exception as e:
            fail(e)

    check()

    print("  rotate_vector")
    try:
        from pyxtal.operations import rotate_vector
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                v1 = random_vector()
                v2 = random_vector()
                rotate_vector(v1, v2)
        except Exception as e:
            fail(e)

    check()

    print("  are_equal")
    try:
        from pyxtal.operations import are_equal
    except Exception as e:
        fail(e)

    if passed():
        try:
            op1 = SymmOp.from_xyz_string("x,y,z")
            op2 = SymmOp.from_xyz_string("x,y,z+1")
            a = are_equal(op1, op2, PBC=[0, 0, 1])
            b = are_equal(op1, op2, PBC=[1, 0, 0])
            if a is True and b is False:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  class OperationAnalyzer")
    try:
        from pyxtal.operations import OperationAnalyzer
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                m = aa2matrix(1, 1, random=True)
                t = random_vector()
                op1 = SymmOp.from_rotation_and_translation(m, t)
                OperationAnalyzer(op1)
        except Exception as e:
            fail(e)

    check()

    print("  class Orientation")
    try:
        from pyxtal.operations import Orientation
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in range(10):
                v1 = random_vector()
                c1 = random_vector()
                o = Orientation.from_constraint(v1, c1)
        except Exception as e:
            fail(e)

    check()

    # =====symmetry=====
    print("pyxtal.symmetry")
    reset()
    try:
        import pyxtal.symmetry
    except Exception as e:
        fail(e)

    print("  get_wyckoffs (may take a moment)")
    try:
        from pyxtal.symmetry import get_wyckoffs
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in [1, 2, 229, 230]:
                get_wyckoffs(i)
                get_wyckoffs(i, organized=True)
        except:
            fail(" Could not access Wyckoff positions for space group # " +
                 str(i))

    check()

    print("  get_wyckoff_symmetry (may take a moment)")
    try:
        from pyxtal.symmetry import get_wyckoff_symmetry
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in [1, 2, 229, 230]:
                get_wyckoff_symmetry(i)
                get_wyckoff_symmetry(i, molecular=True)
        except:
            fail("Could not access Wyckoff symmetry for space group # " +
                 str(i))

    check()

    print("  get_wyckoffs_generators (may take a moment)")
    try:
        from pyxtal.symmetry import get_wyckoff_generators
    except Exception as e:
        fail(e)

    if passed():
        try:
            for i in [1, 2, 229, 230]:
                get_wyckoff_generators(i)
        except:
            fail("Could not access Wyckoff generators for space group # " +
                 str(i))

    check()

    print("  letter_from_index")
    try:
        from pyxtal.symmetry import letter_from_index
    except Exception as e:
        fail(e)

    if passed():
        try:
            if letter_from_index(0, get_wyckoffs(47)) == "A":
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  index_from_letter")
    try:
        from pyxtal.symmetry import index_from_letter
    except Exception as e:
        fail(e)

    if passed():
        try:
            if index_from_letter("A", get_wyckoffs(47)) == 0:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  jk_from_i")
    try:
        from pyxtal.symmetry import jk_from_i
    except Exception as e:
        fail(e)

    if passed():
        try:
            w = get_wyckoffs(2, organized=True)
            j, k = jk_from_i(1, w)
            if j == 1 and k == 0:
                pass
            else:
                print(j, k)
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  i_from_jk")
    try:
        from pyxtal.symmetry import i_from_jk
    except Exception as e:
        fail(e)

    if passed():
        try:
            w = get_wyckoffs(2, organized=True)
            j, k = jk_from_i(1, w)
            i = i_from_jk(j, k, w)
            if i == 1:
                pass
            else:
                print(j, k)
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  ss_string_from_ops")
    try:
        from pyxtal.symmetry import ss_string_from_ops
    except Exception as e:
        fail(e)

    if passed():
        try:
            strings = ["1", "4 . .", "2 3 ."]
            for i, sg in enumerate([1, 75, 195]):
                ops = get_wyckoffs(sg)[0]
                ss_string_from_ops(ops, sg, dim=3)
        except Exception as e:
            fail(e)

    check()

    print("  Wyckoff_position")
    try:
        from pyxtal.symmetry import Wyckoff_position
    except Exception as e:
        fail(e)

    if passed():
        try:
            wp = Wyckoff_position.from_group_and_index(20, 1)
        except Exception as e:
            fail(e)

    check()

    print("  Group")
    try:
        from pyxtal.symmetry import Group
    except Exception as e:
        fail(e)

    if passed():
        try:
            g3 = Group(230)
            g2 = Group(80, dim=2)
            g1 = Group(75, dim=1)
        except Exception as e:
            fail(e)

    check()

    # =====crystal=====
    print("pyxtal.crystal")
    reset()
    try:
        import pyxtal.crystal
    except Exception as e:
        fail(e)

    print("  random_crystal")
    try:
        from pyxtal.crystal import random_crystal
    except Exception as e:
        fail(e)

    if passed():
        try:
            c = random_crystal(1, ["H"], [1], 10.0)
            if c.valid is True:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  random_crystal_2D")
    try:
        from pyxtal.crystal import random_crystal_2D
    except Exception as e:
        fail(e)

    if passed():
        try:
            c = random_crystal_2D(1, ["H"], [1], 10.0)
            if c.valid is True:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    # =====molecule=====
    print("pyxtal.molecule")
    reset()
    try:
        import pyxtal.molecule
    except Exception as e:
        fail(e)

    check()

    print("  Collections")
    try:
        from pyxtal.molecule import mol_from_collection
    except Exception as e:
        fail(e)

    if passed():
        try:
            h2o = mol_from_collection("H2O")
            ch4 = mol_from_collection("CH4")
        except Exception as e:
            fail(e)

    print("  get_inertia_tensor")
    try:
        from pyxtal.molecule import get_inertia_tensor
    except Exception as e:
        fail(e)

    if passed():
        try:
            get_inertia_tensor(h2o)
            get_inertia_tensor(ch4)
        except Exception as e:
            fail(e)

    check()

    print("  get_moment_of_inertia")
    try:
        from pyxtal.molecule import get_moment_of_inertia
    except Exception as e:
        fail(e)

    if passed():
        try:
            v = random_vector()
            get_moment_of_inertia(h2o, v)
            get_moment_of_inertia(ch4, v)
        except Exception as e:
            fail(e)

    check()

    print("  reoriented_molecule")
    try:
        from pyxtal.molecule import reoriented_molecule
    except Exception as e:
        fail(e)

    if passed():
        try:
            reoriented_molecule(h2o)
            reoriented_molecule(ch4)
        except Exception as e:
            fail(e)

    check()

    print("  orientation_in_wyckoff_position")
    try:
        from pyxtal.molecule import orientation_in_wyckoff_position
    except Exception as e:
        fail(e)

    if passed():
        try:
            w = get_wyckoffs(20)
            ws = get_wyckoff_symmetry(20, molecular=True)
            wp = Wyckoff_position.from_group_and_index(20, 1)
            orientation_in_wyckoff_position(h2o, wp)
            orientation_in_wyckoff_position(ch4, wp)
        except Exception as e:
            fail(e)

    check()

    # =====molecular_crystal=====
    print("pyxtal.molecular_crystal")
    reset()
    try:
        import pyxtal.crystal
    except Exception as e:
        fail(e)

    print("  molecular_crystal")
    try:
        from pyxtal.molecular_crystal import molecular_crystal
    except Exception as e:
        fail(e)

    if passed():
        try:
            c = molecular_crystal(1, ["H2O"], [1], 10.0)
            if c.valid is True:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    print("  molecular_crystal_2D")
    try:
        from pyxtal.molecular_crystal import molecular_crystal_2D
    except Exception as e:
        fail(e)

    if passed():
        try:
            c = molecular_crystal_2D(1, ["H2O"], [1], 10.0)
            if c.valid is True:
                pass
            else:
                fail()
        except Exception as e:
            fail(e)

    check()

    end(condition=2)
Пример #14
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
Пример #15
0
    def __init__(self, struc, ref_mol=None, tol=0.2, relax_h=False):
        """
        extract the mol_site information from the give cif file 
        and reference molecule
    
        Args: 
            struc: cif/poscar file or a Pymatgen Structure object
            ref_mol: xyz file or a reference Pymatgen molecule object
            tol: scale factor for covalent bond distance
            relax_h: whether or not relax the position for hydrogen atoms in structure
        
    """
        if isinstance(ref_mol, str):
            ref_mol = Molecule.from_file(ref_mol)
        elif isinstance(ref_mol, Molecule):
            ref_mol = ref_mol
        else:
            print(type(ref_mol))
            raise NameError("reference molecule cannot be defined")

        if isinstance(struc, str):
            pmg_struc = Structure.from_file(struc)
        elif isinstance(struc, Structure):
            pmg_struc = struc
        else:
            print(type(struc))
            raise NameError("input structure cannot be intepretted")

        self.props = ref_mol.site_properties
        self.ref_mol = ref_mol.get_centered_molecule()
        self.tol = tol
        self.diag = False
        self.relax_h = relax_h

        sga = SpacegroupAnalyzer(pmg_struc)
        ops = sga.get_space_group_operations()
        self.wyc, perm = Wyckoff_position.from_symops(
            ops, sga.get_space_group_number())

        if self.wyc is not None:
            self.group = Group(self.wyc.number)
            if isinstance(perm, list):
                if perm != [0, 1, 2]:
                    lattice = Lattice.from_matrix(pmg_struc.lattice.matrix,
                                                  self.group.lattice_type)
                    latt = lattice.swap_axis(ids=perm,
                                             random=False).get_matrix()
                    coor = pmg_struc.frac_coords[:, perm]
                    pmg_struc = Structure(latt, pmg_struc.atomic_numbers, coor)
            else:
                self.diag = True
                self.perm = perm

            coords, numbers = search_molecule_in_crystal(pmg_struc, self.tol)
            #coords -= np.mean(coords, axis=0)
            if self.relax_h:
                self.molecule = self.addh(Molecule(numbers, coords))
            else:
                self.molecule = Molecule(numbers, coords)
            self.pmg_struc = pmg_struc
            self.lattice = Lattice.from_matrix(pmg_struc.lattice.matrix,
                                               self.group.lattice_type)
        else:
            raise ValueError(
                "Cannot find the space group matching the symmetry operation")
Пример #16
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
Пример #17
0
# import gemmi as gm
# import spglib

from pyxtal.symmetry import Group
from pyxtal.symmetry import Wyckoff_position as wp
#################

#####################################################
#####################################################
# Testing pyxtal.symmetry Module:

g = Group(19)

sym_Ops = g.Wyckoff_positions[0]

sym_Ops2 = wp.from_group_and_index(19, 0)

# temp_dat=str(sym_Ops2)
# temp_dat_split=temp_dat.split()[14:]
# symm_Ops_lst=[]
# for i in temp_dat_split:
# 	i.replace('x','X')
# 	x=re.sub('x','X',i)
# 	x=re.sub('y','Y',x)
# 	x=re.sub('z','Z',x)
# 	symm_Ops_lst.append(x)

# # print(symm_Ops_lst)

# index=0
# lenList=len(symm_Ops_lst)
Пример #18
0
 def test_Pmn21(self):
     strs = ["x, y, z", "-x+1/2, -y, z+1/2", "-x, y, z", "x+1/2, -y, z+1/2"]
     wyc, perm = Wyckoff_position.from_symops(strs)
     self.assertTrue(wyc.number == 31)
Пример #19
0
 def test_P21(self):
     strs = ["x, y, z", "-x, y+1/2, -z"]
     wyc, perm = Wyckoff_position.from_symops(strs)
     self.assertTrue(wyc.number == 4)
Пример #20
0
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.core.operations import SymmOp

from pyxtal import pyxtal
from pyxtal.lattice import Lattice
from pyxtal.symmetry import Group, Wyckoff_position, get_wyckoffs
from pyxtal.wyckoff_site import WP_merge
from pyxtal.XRD import Similarity
from pyxtal.operations import get_inverse

cif_path = resource_filename("pyxtal", "database/cifs/")
l0 = Lattice.from_matrix([[4.08, 0, 0], [0, 9.13, 0], [0, 0, 5.50]])
l1 = Lattice.from_matrix([[4.08, 0, 0], [0, 9.13, 0], [0, 0, 5.50]])
l2 = Lattice.from_para(4.08, 9.13, 5.50, 90, 90, 90)
l3 = Lattice.from_para(4.08, 7.13, 5.50, 90, 38, 90, ltype="monoclinic")
wp1 = Wyckoff_position.from_group_and_index(36, 0)
wp2 = Wyckoff_position.from_group_and_index(36, "4a")


class TestGroup(unittest.TestCase):
    def test_list_wyckoff_combinations(self):
        g = Group(64)
        a1, _ = g.list_wyckoff_combinations([4, 2])
        self.assertTrue(a1 is None)
        a2, _ = g.list_wyckoff_combinations([4, 8], quick=False)
        self.assertTrue(len(a2) == 8)


class TestOptLat(unittest.TestCase):
    def test_atomic(self):
        c1 = pyxtal()