예제 #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
예제 #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
예제 #3
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
예제 #4
0
def test_molecular_2D():
    global outstructs
    global outstrings
    print("=== Testing generation of molecular 2D crystals. This may take some time. ===")
    from time import time
    from spglib import get_symmetry_dataset
    from pyxtal.symmetry import get_layer
    from pyxtal.crystal import cellsize
    from pyxtal.molecular_crystal import molecular_crystal_2D
    from pyxtal.database.layergroup import Layergroup
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
    slow = []
    failed = []
    print("   Layergroup   | sg # Expected |Generated (SPG)|Generated (PMG)|Time Elapsed")
    skip = []#12, 64, 65, 80] #slow to generate
    for num in range(1, 81):
        if num not in skip:
            sg = Layergroup(num).sgnumber
            multiplicity = len(get_layer(num)[0]) / cellsize(sg) #multiplicity of the general position
            start = time()
            rand_crystal = molecular_crystal_2D(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:
                check = False
                ans1 = get_symmetry_dataset(rand_crystal.spg_struct, symprec=1e-1)
                if ans1 is None:
                    ans1 = "???"
                else:
                    ans1 = ans1['number']
                sga = SpacegroupAnalyzer(rand_crystal.struct)
                ans2 = "???"
                if sga is not None:
                    try:
                        ans2 = sga.get_space_group_number()
                    except: ans2 = "???"
                if ans2 is None:
                    ans2 = "???"

                #Compare expected and detected groups
                if ans1 == "???" and ans2 == "???":
                    check = True
                elif ans1 == "???":
                    if int(ans2) > sg: pass
                elif ans2 == "???":
                    if int(ans1) > sg: pass
                else:
                    if ans1 < sg and ans2 < sg:
                        if compare_wyckoffs(sg, ans1) or compare_wyckoffs(sg, ans2): pass
                        else: check = True

                #output cif files for incorrect space groups
                if check is True:
                    if check_struct_group(rand_crystal.struct, num, dim=2):
                        pass
                    else:
                        t += " xxxxx"
                        outstructs.append(rand_crystal.struct)
                        outstrings.append(str("2D_Molecular_"+str(num)+".vasp"))
                print("\t"+str(num)+"\t|\t"+str(sg)+"\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))