Ejemplo n.º 1
0
def compare_wyckoffs(num1, num2, dim=3):
    """Given 2 groups, return whether the second point
    group has equal or greater symmetry than the first group."""
    from numpy import allclose

    if num1 == "???":
        print("Error: invalid value for num1 passed to compare_wyckoffs")
        return
    if num2 == "???":
        return False
    # Get general positions for both groups
    if dim == 3:
        from pyxtal.symmetry import get_wyckoffs

        g1 = get_wyckoffs(num1)[0]
        g2 = get_wyckoffs(num2)[0]
    elif dim == 2:
        from pyxtal.symmetry import get_layer

        g1 = get_layer(num1)[0]
        g2 = get_layer(num2)[0]
    elif dim == 1:
        from pyxtal.symmetry import get_rod

        g1 = get_rod(num1)[0]
        g2 = get_rod(num2)[0]
    elif dim == 0:
        from pyxtal.symmetry import get_point

        g1 = get_point(num1)[0]
        g2 = get_point(num2)[0]
    # If group 2 has higher symmetry
    if len(g2) > len(g1):
        return True
    # Compare point group operations
    for i, op2 in enumerate(g2):
        op1 = g1[i]
        m1 = op1.rotation_matrix
        m2 = op2.rotation_matrix
        if not allclose(m1, m2):
            return False
    return True
Ejemplo n.º 2
0
def check_struct_group(crystal, group, dim=3, tol=1e-2):
    # Supress pymatgen/numpy complex casting warnings
    from pyxtal.crystal import random_crystal
    from pyxtal.molecular_crystal import molecular_crystal
    from copy import deepcopy
    import warnings

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        """Given a pymatgen structure, group number, and dimension, return
        whether or not the structure matches the group number."""
        if isinstance(crystal, (random_crystal, molecular_crystal)):
            lattice = crystal.struct.lattice.matrix
            if dim != 0:
                old_coords = deepcopy(crystal.struct.frac_coords)
                old_species = deepcopy(crystal.struct.atomic_numbers)
            elif dim == 0:
                old_coords = deepcopy(crystal.cart_coords)
                old_species = deepcopy(crystal.species)
        else:
            lattice = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
            old_coords = np.array(crystal)
            old_species = ["C"] * len(old_coords)

        from pyxtal.symmetry import distance
        from pyxtal.symmetry import filtered_coords
        from copy import deepcopy

        PBC = [1, 1, 1]

        # Obtain the generators for the group
        if dim == 3:
            from pyxtal.symmetry import get_wyckoffs

            generators = get_wyckoffs(group)[0]

        elif dim == 2:
            from pyxtal.symmetry import get_layer

            generators = get_layer(group)[0]
            PBC = [1, 1, 0]
        elif dim == 1:
            from pyxtal.symmetry import get_rod

            generators = get_rod(group)[0]
            PBC = [0, 0, 1]
        elif dim == 0:
            from pyxtal.symmetry import Group

            generators = Group(group, dim=0)[0]
            PBC = [0, 0, 0]

        # TODO: Add check for lattice symmetry

        # Apply SymmOps to generate new points
        # old_coords = filtered_coords(struct.frac_coords,PBC=PBC)

        new_coords = []
        new_species = []
        for i, point in enumerate(old_coords):
            for j, op in enumerate(generators):
                if j != 0:
                    new_coords.append(op.operate(point))
                    new_species.append(old_species[i])
        # new_coords = filtered_coords(new_coords,PBC=PBC)

        # Check that all points in new list are still in old
        failed = False
        i_list = list(range(len(new_coords)))
        for i, point1 in enumerate(new_coords):
            found = False
            for j, point2 in enumerate(old_coords):
                if new_species[i] == old_species[j]:
                    difference = filtered_coords(point2 - point1, PBC=PBC)
                    if distance(difference, lattice, PBC=PBC) <= tol:
                        found = True
                        break
            if found is False:
                failed = True
                break

        if failed is False:
            return True
        else:
            return False
Ejemplo n.º 3
0
def test_molecular_1D():
    global outstructs
    global outstrings
    print(
        "=== Testing generation of molecular 1D crystals. This may take some time. ==="
    )
    from time import time
    from spglib import get_symmetry_dataset
    from pyxtal.symmetry import get_rod
    from pyxtal.molecular_crystal import molecular_crystal_1D
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

    slow = []
    failed = []
    print("    Rod group   | Gen sg. (SPG) | Gen. sg (PMG) |Time Elapsed")
    skip = []  # slow to generate
    for num in range(1, 76):
        if num not in skip:
            multiplicity = len(
                get_rod(num)[0])  # multiplicity of the general position
            start = time()
            rand_crystal = molecular_crystal_1D(num, ["H2O"], [multiplicity],
                                                4.0)
            end = time()
            timespent = np.around((end - start), decimals=2)
            t = str(timespent)
            if len(t) == 3:
                t += "0"
            t += " s"
            if timespent >= 1.0:
                t += " ~"
            if timespent >= 3.0:
                t += "~"
            if timespent >= 10.0:
                t += "~"
            if timespent >= 60.0:
                t += "~"
                slow.append(num)
            if rand_crystal.valid:
                try:
                    ans1 = get_symmetry_dataset(rand_crystal.spg_struct,
                                                symprec=1e-1)
                except:
                    ans1 = "???"
                if ans1 is None or ans1 == "???":
                    ans1 = "???"
                else:
                    ans1 = ans1["number"]
                sga = SpacegroupAnalyzer(rand_crystal.struct)
                try:
                    ans2 = sga.get_space_group_number()
                except:
                    ans2 = "???"
                if ans2 is None:
                    ans2 = "???"

                check = True

                # output cif files for incorrect space groups
                if check is True:
                    if check_struct_group(rand_crystal, num, dim=1):
                        pass
                    else:
                        t += " xxxxx"
                        outstructs.append(rand_crystal.struct)
                        outstrings.append(
                            str("1D_Molecular_" + str(num) + ".vasp"))
                print("\t" + str(num) + "\t|\t" + str(ans1) + "\t|\t" +
                      str(ans2) + "\t|\t" + t)
            else:
                print("~~~~ Error: Could not generate layer group " +
                      str(num) + " after " + t)
                failed.append(num)
    if slow != []:
        print(
            "~~~~ The following layer groups took more than 60 seconds to generate:"
        )
        for i in slow:
            print("     " + str(i))
    if failed != []:
        print("~~~~ The following layer groups failed to generate:")
        for i in failed:
            print("     " + str(i))
Ejemplo n.º 4
0
def check_struct_group(struct, group, dim=3, tol=1e-2):
    """Given a pymatgen structure, group number, and dimension, return
    whether or not the structure matches the group number."""

    from pyxtal.symmetry import distance
    from pyxtal.symmetry import filtered_coords
    from copy import deepcopy
    lattice = struct.lattice.matrix
    PBC = [1,1,1]

    #Obtain the generators for the group
    if dim == 3:
        from pyxtal.symmetry import get_wyckoffs
        generators = get_wyckoffs(group)[0]

    elif dim == 2:
        from pyxtal.symmetry import get_layer
        generators = get_layer(group)[0]
        PBC = [1,1,0]
    elif dim == 1:
        from pyxtal.symmetry import get_rod
        generators = get_rod(group)[0]
        PBC = [0,0,1]
    elif dim == 0:
        from pyxtal.symmetry import get_point
        generators = get_point(group)[0]
        PBC = [0,0,0]

    #TODO: Add check for lattice symmetry

    #Apply SymmOps to generate new points
    #old_coords = filtered_coords(struct.frac_coords,PBC=PBC)
    old_coords = deepcopy(struct.frac_coords)
    if dim == 0:
        old_coords = old_coords - 0.5
    old_species = deepcopy(struct.atomic_numbers)

    new_coords = []
    new_species = []
    for i, point in enumerate(old_coords):
        for j, op in enumerate(generators):
            if j != 0:
                new_coords.append(op.operate(point))
                new_species.append(old_species[i])
    #new_coords = filtered_coords(new_coords,PBC=PBC)

    #Check that all points in new list are still in old
    failed = False
    i_list = list(range(len(new_coords)))
    for i, point1 in enumerate(new_coords):
        found = False
        for j, point2 in enumerate(old_coords):
            if new_species[i] == old_species[j]:
                difference = filtered_coords(point2 - point1, PBC=PBC)
                if distance(difference, lattice, PBC=PBC) <= tol:
                    found = True
                    break
        if found is False:
            failed = True
            break

    if failed is False:
        return True
    else:
        return False
Ejemplo n.º 5
0
def test_atomic_1D():
    global outstructs
    global outstrings
    fprint("=== Testing generation of atomic 1D crystals. This may take some time. ===")

    slow = []
    failed = []
    fprint("    Rod group   | Gen sg. (SPG) | Gen. sg (PMG) |Time Elapsed")
    skip = []  # slow to generate
    for num in range(1, 76):
        if num not in skip:
            multiplicity = len(get_rod(num)[0])  # multiplicity of the general position
            start = time()
            rand_crystal = pyxtal()
            rand_crystal.from_random(1, num, ["H"], [multiplicity], 4.0)
            end = time()
            timespent = np.around((end - start), decimals=2)
            t = str(timespent)
            if len(t) == 3:
                t += "0"
            t += " s"
            if timespent >= 1.0:
                t += " ~"
            if timespent >= 3.0:
                t += "~"
            if timespent >= 10.0:
                t += "~"
            if timespent >= 60.0:
                t += "~"
                slow.append(num)
            if rand_crystal.valid:
                try:
                    ans1 = get_symmetry_dataset(rand_crystal.to_ase(), symprec=1e-1)
                except:
                    ans1 = "???"
                if ans1 is None or ans1 == "???":
                    ans1 = "???"
                else:
                    ans1 = ans1["number"]
                sga = SpacegroupAnalyzer(rand_crystal.to_pymatgen())
                try:
                    ans2 = sga.get_space_group_number()
                except:
                    ans2 = "???"
                if ans2 is None:
                    ans2 = "???"

                check = True

                # output cif files for incorrect space groups
                if check is True:
                    if check_struct_group(rand_crystal, num, dim=1):
                        pass
                    else:
                        t += " xxxxx"
                        outstructs.append(rand_crystal.to_pymatgen)
                        outstrings.append(str("1D_Atomic_" + str(num) + ".vasp"))
                fprint("\t{}\t|\t{}\t|\t{}\t|\t{}".format(num, ans1, ans2, t))
            else:
                fprint(
                    "~~~~ Error: Could not generate layer group {} after {}".format(
                        num, t
                    )
                )
                failed.append(num)
    if slow != []:
        fprint("~~~~ The following layer groups took more than 60 seconds to generate:")
        for i in slow:
            fprint("     " + str(i))
    if failed != []:
        fprint("~~~~ The following layer groups failed to generate:")
        for i in failed:
            fprint("     " + str(i))