Beispiel #1
0
    def init_common(
        self,
        molecules,
        numMols,
        volume_factor,
        select_high,
        allow_inversion,
        orientations,
        group,
        lattice,
        tm,
        sites,
    ):
        # init functionality which is shared by 3D, 2D, and 1D crystals
        self.valid = False
        self.numattempts = 0  # number of attempts to generate the crystal.
        if type(group) == Group:
            self.group = group
            """A pyxtal.symmetry.Group object storing information about the space/layer
            /Rod/point group, and its Wyckoff positions."""
        else:
            self.group = Group(group, dim=self.dim)
        self.number = self.group.number
        """
        The international group number of the crystal:
        1-230 for 3D space groups
        1-80 for 2D layer groups
        1-75 for 1D Rod groups
        1-32 for crystallographic point groups
        None otherwise
        """
        self.Msgs()
        self.factor = volume_factor  # volume factor for the unit cell.
        numMols = np.array(numMols)  # must convert it to np.array
        self.numMols0 = numMols  # in the PRIMITIVE cell
        self.numMols = self.numMols0 * cellsize(
            self.group)  # in the CONVENTIONAL cell

        # boolean numbers
        self.allow_inversion = allow_inversion
        self.select_high = select_high

        # Set the tolerance matrix
        # The Tol_matrix object for checking inter-atomic distances within the structure.
        if type(tm) == Tol_matrix:
            self.tol_matrix = tm
        else:
            try:
                self.tol_matrix = Tol_matrix(prototype=tm)
            # TODO remove bare except
            except:
                msg = "Error: tm must either be a Tol_matrix object +\n"
                msg += "or a prototype string for initializing one."
                printx(msg, priority=1)
                return

        self.molecules = []  # A pyxtal_molecule objects,
        for mol in molecules:
            self.molecules.append(pyxtal_molecule(mol, self.tol_matrix))

        self.sites = {}
        for i, mol in enumerate(self.molecules):
            if sites is not None and sites[i] is not None:
                self.check_consistency(sites[i], self.numMols[i])
                self.sites[i] = sites[i]
            else:
                self.sites[i] = None

        # if seeds, directly parse the structure from cif
        # At the moment, we only support one specie
        if self.seed is not None:
            seed = structure_from_ext(self.seed,
                                      self.molecules[0].mol,
                                      relax_h=self.relax_h)
            if seed.match():
                self.mol_sites = [seed.make_mol_site()]
                self.group = Group(seed.wyc.number)
                self.lattice = seed.lattice
                self.molecules = [pyxtal_molecule(seed.molecule)]
                self.diag = seed.diag
                self.valid = True  # Need to add a check function
            else:
                raise ValueError("Cannot extract the structure from cif")

        # The valid orientations for each molecule and Wyckoff position.
        # May be copied when generating a new molecular_crystal to save a
        # small amount of time

        if orientations is None:
            self.get_orientations()
        else:
            self.valid_orientations = orientations

        if self.seed is None:
            if lattice is not None:
                # Use the provided lattice
                self.lattice = lattice
                self.volume = lattice.volume
                # Make sure the custom lattice PBC axes are correct.
                if lattice.PBC != self.PBC:
                    self.lattice.PBC = self.PBC
                    printx("\n  Warning: converting custom lattice PBC to " +
                           str(self.PBC))
            else:
                # Determine the unique axis
                if self.dim == 2:
                    if self.number in range(3, 8):
                        unique_axis = "c"
                    else:
                        unique_axis = "a"
                elif self.dim == 1:
                    if self.number in range(3, 8):
                        unique_axis = "a"
                    else:
                        unique_axis = "c"
                else:
                    unique_axis = "c"

                # Generate a Lattice instance
                self.volume = self.estimate_volume()
                # The Lattice object used to generate lattice matrices
                if self.dim == 3 or self.dim == 0:
                    self.lattice = Lattice(
                        self.group.lattice_type,
                        self.volume,
                        PBC=self.PBC,
                        unique_axis=unique_axis,
                    )
                elif self.dim == 2:
                    self.lattice = Lattice(
                        self.group.lattice_type,
                        self.volume,
                        PBC=self.PBC,
                        unique_axis=unique_axis,
                        thickness=self.thickness,
                    )
                elif self.dim == 1:
                    self.lattice = Lattice(
                        self.group.lattice_type,
                        self.volume,
                        PBC=self.PBC,
                        unique_axis=unique_axis,
                        area=self.area,
                    )

            self.generate_crystal()
Beispiel #2
0
import pymatgen.analysis.structure_matcher as sm
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
import numpy as np
from pyxtal.lattice import cellsize

for G in range(1, 231):
    #for G in [90, 99, 105, 107, 203, 210, 224, 226, 227, 228]:
    g = Group(G)
    subs = g.get_max_t_subgroup()
    indices = subs['index']
    hs = subs['subgroup']
    relations = subs['relations']
    tran = subs['transformation']
    letter = str(g[0].multiplicity) + g[0].letter
    print(G)
    C1 = random_crystal(G, ['C'], [int(g[0].multiplicity / cellsize(g))],
                        sites=[[letter]])
    pmg_s1 = C1.to_pymatgen()
    sga1 = SpacegroupAnalyzer(pmg_s1).get_space_group_symbol()
    # each subgroup
    for i in range(len(relations)):
        C2 = C1.subgroup(eps=0, idx=[i], once=True)
        pmg_s2 = C2.to_pymatgen()
        try:
            sga2 = SpacegroupAnalyzer(pmg_s2,
                                      symprec=1e-4).get_space_group_symbol()
        except:
            #print("unable to find the space group")
            sga2 = None
        print(G, hs[i], g.symbol, sga1, Group(hs[i]).symbol, sga2, i)
        if not sm.StructureMatcher().fit(pmg_s1, pmg_s2):
Beispiel #3
0
    def init_common(self, species, numIons, factor, group, lattice, sites,
                    conventional, tm):
        """
        Common init functionality for 0D-3D cases of random_crystal.
        """
        self.source = 'Random'
        self.valid = False
        # Check that numIons are integers greater than 0
        for num in numIons:
            if int(num) != num or num < 1:
                printx("Error: composition must be positive integers.",
                       priority=1)
                return False
        if type(group) == Group:
            self.group = group
        else:
            self.group = Group(group, dim=self.dim)
        self.number = self.group.number
        """
        The international group number of the crystal:
        1-230 for 3D space groups
        1-80 for 2D layer groups
        1-75 for 1D Rod groups
        1-32 for crystallographic point groups
        None otherwise
        """

        # The number of attempts to generate the crystal
        # number of atoms
        # volume factor for the unit cell.
        # The number of atom in the PRIMITIVE cell
        # The number of each type of atom in the CONVENTIONAL cell.
        # A list of atomic symbols for the types of atoms
        # A list of warning messages

        self.numattempts = 0
        numIons = np.array(numIons)
        self.factor = factor
        if not conventional:
            mul = cellsize(self.group)
        else:
            mul = 1
        self.numIons = numIons * mul

        formula = ""
        for i, s in zip(self.numIons, species):
            formula += "{:s}{:d}".format(s, int(i))
        self.formula = formula

        self.species = species

        # Use the provided lattice
        if lattice is not None:
            self.lattice = lattice
            self.volume = lattice.volume
            # Make sure the custom lattice PBC axes are correct.
            if lattice.PBC != self.PBC:
                self.lattice.PBC = self.PBC
                printx("\n  Warning: converting custom lattice PBC to " +
                       str(self.PBC))

        # Generate a Lattice instance based on a given volume estimation
        elif lattice is None:

            # Determine the unique axis
            if self.dim == 2:
                if self.number in range(3, 8):
                    unique_axis = "c"
                else:
                    unique_axis = "a"
            elif self.dim == 1:
                if self.number in range(3, 8):
                    unique_axis = "a"
                else:
                    unique_axis = "c"
            else:
                unique_axis = "c"

            self.volume = self.estimate_volume()

            if self.dim == 3 or self.dim == 0:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                )
            elif self.dim == 2:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                    # NOTE self.thickness is part of 2D class
                    thickness=self.thickness,
                )
            elif self.dim == 1:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                    # NOTE self.area is part of 1D class
                    area=self.area,
                )
        # Set the tolerance matrix for checking inter-atomic distances
        if type(tm) == Tol_matrix:
            self.tol_matrix = tm
        else:
            try:
                self.tol_matrix = Tol_matrix(prototype=tm)
            # TODO Remove bare except
            except:
                printx(
                    ("Error: tm must either be a Tol_matrix object or "
                     "a prototype string for initializing one."),
                    priority=1,
                )
                self.valid = False
                return

        self.sites = {}
        for i, specie in enumerate(self.species):
            if sites is not None and sites[i] is not None:
                self.check_consistency(sites[i], self.numIons[i])
                self.sites[specie] = sites[i]
            else:
                self.sites[specie] = None
        # QZ: needs to check if it is compatible

        self.generate_crystal()
    def init_common(
        self,
        molecules,
        numMols,
        volume_factor,
        select_high,
        allow_inversion,
        orientations,
        group,
        lattice,
        sites,
        conventional,
        tm,
    ):
        # init functionality which is shared by 3D, 2D, and 1D crystals
        self.valid = False
        self.numattempts = 0 # number of attempts to generate the crystal.
        if type(group) == Group:
            self.group = group
        else:
            self.group = Group(group, dim=self.dim)
        self.number = self.group.number
        """
        The international group number of the crystal:
        1-230 for 3D space groups
        1-80 for 2D layer groups
        1-75 for 1D Rod groups
        1-32 for crystallographic point groups
        None otherwise
        """
        self.factor = volume_factor  # volume factor for the unit cell.
        numMols = np.array(numMols)  # must convert it to np.array
        if not conventional:
            mul = cellsize(self.group)
        else:
            mul = 1
        self.numMols = numMols * mul

        # boolean numbers
        self.allow_inversion = allow_inversion
        self.select_high = select_high

        # Set the tolerance matrix
        # The Tol_matrix object for checking inter-atomic distances within the structure.
        if type(tm) == Tol_matrix:
            self.tol_matrix = tm
        else:
            try:
                self.tol_matrix = Tol_matrix(prototype=tm)
            # TODO remove bare except
            except:
                msg = "Error: tm must either be a Tol_matrix object +\n"
                msg += "or a prototype string for initializing one."
                printx(msg, priority=1)
                return

        self.molecules = []  # A pyxtal_molecule objects,
        for mol in molecules:
            self.molecules.append(pyxtal_molecule(mol, self.tol_matrix))

        self.sites = {}
        for i, mol in enumerate(self.molecules):
            if sites is not None and sites[i] is not None:
                self.check_consistency(sites[i], self.numMols[i])
                self.sites[i] = sites[i]
            else:
                self.sites[i] = None

        # The valid orientations for each molecule and Wyckoff position.
        # May be copied when generating a new molecular_crystal to save a
        # small amount of time

        if orientations is None:
            self.get_orientations()
        else:
            self.valid_orientations = orientations

        if lattice is not None:
            # Use the provided lattice
            self.lattice = lattice
            self.volume = lattice.volume
            # Make sure the custom lattice PBC axes are correct.
            if lattice.PBC != self.PBC:
                self.lattice.PBC = self.PBC
                printx("\n  Warning: converting custom lattice PBC to " + str(self.PBC))
        else:
            # Determine the unique axis
            if self.dim == 2:
                if self.number in range(3, 8):
                    unique_axis = "c"
                else:
                    unique_axis = "a"
            elif self.dim == 1:
                if self.number in range(3, 8):
                    unique_axis = "a"
                else:
                    unique_axis = "c"
            else:
                unique_axis = "c"

            # Generate a Lattice instance
            self.volume = self.estimate_volume()
            # The Lattice object used to generate lattice matrices
            if self.dim == 3 or self.dim == 0:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                )
            elif self.dim == 2:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                    thickness=self.thickness,
                )
            elif self.dim == 1:
                self.lattice = Lattice(
                    self.group.lattice_type,
                    self.volume,
                    PBC=self.PBC,
                    unique_axis=unique_axis,
                    area=self.area,
                )


        self.generate_crystal()