Exemplo n.º 1
0
    def test_get_lattices(self):
        sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5,
                              primitive_cell=True, scale=True,
                              attempt_supercell=False)
        l1 = Lattice.from_lengths_and_angles([1, 2.1, 1.9], [90, 89, 91])
        l2 = Lattice.from_lengths_and_angles([1.1, 2, 2], [89, 91, 90])
        s1 = Structure(l1, [], [])
        s2 = Structure(l2, [], [])

        lattices = list(sm._get_lattices(s=s1, target_lattice=s2.lattice))
        self.assertEqual(len(lattices), 16)

        l3 = Lattice.from_lengths_and_angles([1.1, 2, 20], [89, 91, 90])
        s3 = Structure(l3, [], [])

        lattices = list(sm._get_lattices(s=s1, target_lattice=s3.lattice))
        self.assertEqual(len(lattices), 0)
Exemplo n.º 2
0
    def from_string(header_str):
        """
        Reads Header string and returns Header object if header was
        generated by pymatgen.
        Note: Checks to see if generated by pymatgen, if not it is impossible
            to generate structure object so it is not possible to generate
            header object and routine ends

        Args:
            header_str: pymatgen generated feff.inp header

        Returns:
            Structure object.
        """
        lines = tuple(clean_lines(header_str.split("\n"), False))
        comment1 = lines[0]
        feffpmg = comment1.find("pymatgen")

        if feffpmg:
            comment2 = ' '.join(lines[1].split()[2:])

            source = ' '.join(lines[2].split()[2:])
            basis_vec = lines[6].split(":")[-1].split()
            # a, b, c
            a = float(basis_vec[0])
            b = float(basis_vec[1])
            c = float(basis_vec[2])
            lengths = [a, b, c]
            # alpha, beta, gamma
            basis_ang = lines[7].split(":")[-1].split()
            alpha = float(basis_ang[0])
            beta = float(basis_ang[1])
            gamma = float(basis_ang[2])
            angles = [alpha, beta, gamma]

            lattice = Lattice.from_lengths_and_angles(lengths, angles)

            natoms = int(lines[8].split(":")[-1].split()[0])

            atomic_symbols = []
            for i in range(9, 9 + natoms):
                atomic_symbols.append(lines[i].split()[2])

            # read the atomic coordinates
            coords = []
            for i in range(natoms):
                toks = lines[i + 9].split()
                coords.append([float(s) for s in toks[3:]])

            struct = Structure(lattice, atomic_symbols, coords, False,
                                        False, False)

            h = Header(struct, source, comment2)

            return h
        else:
            return "Header not generated by pymatgen, cannot return header object"
 def setUp(self):
     self.cubic = Structure(
         Lattice.from_lengths_and_angles(
             [1.0, 1.0, 1.0], [90.0, 90.0, 90.0]),
         ["H"], [[0.0, 0.0, 0.0]], validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=False,
         site_properties=None)
     self.bcc = Structure(
         Lattice.from_lengths_and_angles(
             [1.0, 1.0, 1.0], [90.0, 90.0, 90.0]),
         ["H", "H"], [[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.fcc = Structure(
         Lattice.from_lengths_and_angles(
             [1.0, 1.0, 1.0], [90.0, 90.0, 90.0]),
         ["H", "H", "H", "H"], [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5],
                                [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.hcp = Structure(
         Lattice.from_lengths_and_angles(
             [1.0, 1.0, 1.633], [90.0, 90.0, 120.0]),
         ["H", "H"],
         [[0.3333, 0.6667, 0.25], [0.6667, 0.3333, 0.75]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.diamond = Structure(
         Lattice.from_lengths_and_angles(
             [1.0, 1.0, 1.0], [90.0, 90.0, 90.0]),
         ["H", "H", "H", "H", "H", "H", "H", "H"],
         [[0.0, 0.0, 0.5], [0.75, 0.75, 0.75],
          [0.0, 0.5, 0.0], [0.75, 0.25, 0.25],
          [0.5, 0.0, 0.0], [0.25, 0.75, 0.25],
          [0.5, 0.5, 0.5], [0.25, 0.25, 0.75]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
Exemplo n.º 4
0
 def setUp(self):
     self.silicon = Structure(
             Lattice.from_lengths_and_angles(
                     [5.47, 5.47, 5.47],
                     [90.0, 90.0, 90.0]),
             ["Si", "Si", "Si", "Si", "Si", "Si", "Si", "Si"],
             [[0.000000, 0.000000, 0.500000],
             [0.750000, 0.750000, 0.750000],
             [0.000000, 0.500000, 1.000000],
             [0.750000, 0.250000, 0.250000],
             [0.500000, 0.000000, 1.000000],
             [0.250000, 0.750000, 0.250000],
             [0.500000, 0.500000, 0.500000],
             [0.250000, 0.250000, 0.750000]],
             validate_proximity=False, to_unit_cell=False,
             coords_are_cartesian=False, site_properties=None)
     self.diamond = Structure(
         Lattice([[2.189, 0, 1.264], [0.73, 2.064, 1.264],
                  [0, 0, 2.528]]), ["C0+", "C0+"], [[2.554, 1.806, 4.423],
                                                    [0.365, 0.258, 0.632]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.nacl = Structure(
         Lattice([[3.485, 0, 2.012], [1.162, 3.286, 2.012],
                  [0, 0, 4.025]]), ["Na1+", "Cl1-"], [[0, 0, 0],
                                                      [2.324, 1.643, 4.025]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.cscl = Structure(
         Lattice([[4.209, 0, 0], [0, 4.209, 0], [0, 0, 4.209]]),
         ["Cl1-", "Cs1+"], [[2.105, 2.105, 2.105], [0, 0, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.square_pyramid = Structure(
         Lattice([[100, 0, 0], [0, 100, 0], [0, 0, 100]]),
         ["C", "C", "C", "C", "C", "C"], [
         [0, 0, 0], [1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], \
         [0, 0, 1]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.trigonal_bipyramid = Structure(
         Lattice([[100, 0, 0], [0, 100, 0], [0, 0, 100]]),
         ["P", "Cl", "Cl", "Cl", "Cl", "Cl"], [
         [0, 0, 0], [0, 0, 2.14], [0, 2.02, 0], [1.74937, -1.01, 0], \
         [-1.74937, -1.01, 0], [0, 0, -2.14]], validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
 def setUp(self):
     self.single_bond = Structure(
         Lattice.from_lengths_and_angles(
         [10, 10, 10], [90, 90, 90]),
         ["H", "H", "H"], [[1, 0, 0], [0, 0, 0], [6, 0, 0]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.linear = Structure(
         Lattice.from_lengths_and_angles(
         [10, 10, 10], [90, 90, 90]),
         ["H", "H", "H"], [[1, 0, 0], [0, 0, 0], [2, 0, 0]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.bent45 = Structure(
         Lattice.from_lengths_and_angles(
         [10, 10, 10], [90, 90, 90]), ["H", "H", "H"],
         [[0, 0, 0], [0.707, 0.707, 0], [0.707, 0, 0]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.cubic = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]),
         ["H"], [[0, 0, 0]], validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=False,
         site_properties=None)
     self.bcc = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]),
         ["H", "H"], [[0, 0, 0], [0.5, 0.5, 0.5]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.fcc = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]), ["H", "H", "H", "H"],
         [[0, 0, 0], [0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.hcp = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1.633], [90, 90, 120]), ["H", "H"],
         [[0.3333, 0.6667, 0.25], [0.6667, 0.3333, 0.75]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.diamond = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]), ["H", "H", "H", "H", "H", "H", "H", "H"],
         [[0, 0, 0.5], [0.75, 0.75, 0.75], [0, 0.5, 0], [0.75, 0.25, 0.25],
         [0.5, 0, 0], [0.25, 0.75, 0.25], [0.5, 0.5, 0.5],
         [0.25, 0.25, 0.75]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.trigonal_off_plane = Structure(
         Lattice.from_lengths_and_angles(
         [100, 100, 100], [90, 90, 90]),
         ["H", "H", "H", "H"],
         [[0.50, 0.50, 0.50], [0.25, 0.75, 0.25], \
         [0.25, 0.25, 0.75], [0.75, 0.25, 0.25]], \
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.regular_triangle = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H"],
         [[15, 15.28867, 15.65], [14.5, 15, 15], [15.5, 15, 15], \
         [15, 15.866, 15]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.trigonal_planar = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H"],
         [[15, 15.28867, 15], [14.5, 15, 15], [15.5, 15, 15], \
         [15, 15.866, 15]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.square_planar = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H", "H"],
         [[15, 15, 15], [14.75, 14.75, 15], [14.75, 15.25, 15], \
         [15.25, 14.75, 15], [15.25, 15.25, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.square = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H", "H"],
         [[15, 15, 15.707], [14.75, 14.75, 15], [14.75, 15.25, 15], \
         [15.25, 14.75, 15], [15.25, 15.25, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.T_shape = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H"],
         [[15, 15, 15], [15, 15, 15.5], [15, 15.5, 15],
         [15, 14.5, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.square_pyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H", "H", "H"],
         [[15, 15, 15], [15, 15, 15.3535], [14.75, 14.75, 15],
         [14.75, 15.25, 15], [15.25, 14.75, 15], [15.25, 15.25, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.pentagonal_planar = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["Xe", "F", "F", "F", "F", "F"],
         [[0, -1.6237, 0], [1.17969, 0, 0], [-1.17969, 0, 0], \
         [1.90877, -2.24389, 0], [-1.90877, -2.24389, 0], [0, -3.6307, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.pentagonal_pyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["Xe", "F", "F", "F", "F", "F", "F"],
         [[0, -1.6237, 0], [0, -1.6237, 1.17969], [1.17969, 0, 0], \
         [-1.17969, 0, 0], [1.90877, -2.24389, 0], \
         [-1.90877, -2.24389, 0], [0, -3.6307, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.pentagonal_bipyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]),
         ["Xe", "F", "F", "F", "F", "F", "F", "F"],
         [[0, -1.6237, 0], [0, -1.6237, -1.17969], \
         [0, -1.6237, 1.17969], [1.17969, 0, 0], \
         [-1.17969, 0, 0], [1.90877, -2.24389, 0], \
         [-1.90877, -2.24389, 0], [0, -3.6307, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.hexagonal_pyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), \
         ["H", "Li", "C", "C", "C", "C", "C", "C"],
         [[0, 0, 0], [0, 0, 1.675], [0.71, 1.2298, 0], \
         [-0.71, 1.2298, 0], [0.71, -1.2298, 0], [-0.71, -1.2298, 0], \
         [1.4199, 0, 0], [-1.4199, 0, 0]], \
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.hexagonal_bipyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), \
         ["H", "Li", "Li", "C", "C", "C", "C", "C", "C"],
         [[0, 0, 0], [0, 0, 1.675], [0, 0, -1.675], \
         [0.71, 1.2298, 0], [-0.71, 1.2298, 0], \
         [0.71, -1.2298, 0], [-0.71, -1.2298, 0], \
         [1.4199, 0, 0], [-1.4199, 0, 0]], \
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.trigonal_pyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["P", "Cl", "Cl", "Cl", "Cl"],
         [[0, 0, 0], [0, 0, 2.14], [0, 2.02, 0],
         [1.74937, -1.01, 0], [-1.74937, -1.01, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.trigonal_bipyramidal = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["P", "Cl", "Cl", "Cl", "Cl", "Cl"],
         [[0, 0, 0], [0, 0, 2.14], [0, 2.02, 0],
         [1.74937, -1.01, 0], [-1.74937, -1.01, 0], [0, 0, -2.14]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.cuboctahedron = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]),
         ["H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H", "H"],
         [[15, 15, 15], [15, 14.5, 14.5], [15, 14.5, 15.5],
         [15, 15.5, 14.5], [15, 15.5, 15.5],
         [14.5, 15, 14.5], [14.5, 15, 15.5], [15.5, 15, 14.5], [15.5, 15, 15.5],
         [14.5, 14.5, 15], [14.5, 15.5, 15], [15.5, 14.5, 15], [15.5, 15.5, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.see_saw = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]),
         ["H", "H", "H", "H", "H"],
         [[15, 15, 15], [15, 15, 14], [15, 15, 16], [15, 14, 15], [14, 15, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
Exemplo n.º 6
0
 def setUp(self):
     self.linear = Structure(
         Lattice.from_lengths_and_angles(
         [10, 10, 10], [90, 90, 90]),
         ["H", "H", "H"], [[1, 0, 0], [0, 0, 0], [2, 0, 0]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.bent45 = Structure(
         Lattice.from_lengths_and_angles(
         [10, 10, 10], [90, 90, 90]), ["H", "H", "H"],
         [[0, 0, 0], [0.707, 0.707, 0], [0.707, 0, 0]],
         validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=True,
         site_properties=None)
     self.cubic = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]),
         ["H"], [[0, 0, 0]], validate_proximity=False,
         to_unit_cell=False, coords_are_cartesian=False,
         site_properties=None)
     self.bcc = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]),
         ["H", "H"], [[0, 0, 0], [0.5, 0.5, 0.5]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.fcc = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]), ["H", "H", "H", "H"],
         [[0, 0, 0], [0, 0.5, 0.5], [0.5, 0, 0.5], [0.5, 0.5, 0]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.hcp = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1.633], [90, 90, 120]), ["H", "H"],
         [[0.3333, 0.6667, 0.25], [0.6667, 0.3333, 0.75]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.diamond = Structure(
         Lattice.from_lengths_and_angles(
         [1, 1, 1], [90, 90, 90]), ["H", "H", "H", "H", "H", "H", "H", "H"],
         [[0, 0, 0.5], [0.75, 0.75, 0.75], [0, 0.5, 0], [0.75, 0.25, 0.25],
         [0.5, 0, 0], [0.25, 0.75, 0.25], [0.5, 0.5, 0.5],
         [0.25, 0.25, 0.75]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=False, site_properties=None)
     self.regular_triangle = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H"],
         [[15, 15.28867, 15.65], [14.5, 15, 15], [15.5, 15, 15], \
         [15, 15.866, 15]], validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
     self.square = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H", "H"],
         [[15, 15, 15.707], [14.75, 14.75, 15], [14.75, 15.25, 15], \
         [15.25, 14.75, 15], [15.25, 15.25, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None) 
     self.square_pyramid = Structure(
         Lattice.from_lengths_and_angles(
         [30, 30, 30], [90, 90, 90]), ["H", "H", "H", "H", "H", "H"],
         [[15, 15, 15], [15, 15, 15.3535], [14.75, 14.75, 15],
         [14.75, 15.25, 15], [15.25, 14.75, 15], [15.25, 15.25, 15]],
         validate_proximity=False, to_unit_cell=False,
         coords_are_cartesian=True, site_properties=None)
Exemplo n.º 7
0
def lat_in_to_sqs(atat_lattice_in, rename=True):
    """
    Convert a string-like ATAT-style lattice.in to an abstract SQS.

    Parameters
    ----------
    atat_lattice_in : str
        String-like of a lattice.in in the ATAT format.
    rename : bool
        If True, SQS format element names will be renamed, e.g. `a_B` -> `Xab`. Default is True.

    Returns
    -------
    SQS
        Abstract SQS.
    """
    # TODO: handle numeric species, e.g. 'g1'.
    # Problems: parser has trouble with matching next line and we have to rename it so pymatgen
    # doesn't think it's a charge.
    # parse the data
    parsed_data = _parse_atat_lattice(atat_lattice_in)
    atat_coord_system = parsed_data[0]
    atat_lattice = parsed_data[1]
    atat_atoms = parsed_data[2]
    # create the lattice
    if len(atat_coord_system) == 3:
        # we have a coordinate system matrix
        coord_system = Lattice(list(atat_coord_system)).matrix
    else:
        # we have length and angles
        coord_system = Lattice.from_lengths_and_angles(list(atat_coord_system[0]), list(atat_coord_system[1])).matrix
    direct_lattice = Lattice(list(atat_lattice))
    lattice = coord_system.dot(direct_lattice.matrix)
    # create the list of atoms, converted to the right coordinate system
    species_list = []
    species_positions = []
    subl_model = {} # format {'subl_name': 'atoms_found_in_subl, e.g. "aaabbbb"'}
    for position, atoms in atat_atoms:
        # atoms can be a list of atoms, e.g. for not abstract SQS
        if len(atoms) > 1:
            raise NotImplementedError('Cannot parse atom list {} because the sublattice is unclear.\nParsed data: {}'.format(atoms, atat_atoms))
        atom = atoms[0]
        if rename:
            # change from `a_B` style to `Xab`

            atom = atom.lower().split('_')
        else:
            raise NotImplementedError('Cannot rename because the atom name and sublattice name may be ambigous.')
        # add the abstract atom to the sublattice model
        subl = atom[0]
        subl_atom = atom[1]
        subl_model[subl] = subl_model.get(subl, set()).union({subl_atom})
        # add the species and position to the lists
        species_list.append('X'+subl+subl_atom)
        species_positions.append(list(position))
    # create the structure
    sublattice_model = [[e for e in sorted(list(set(subl_model[s])))] for s in sorted(subl_model.keys())]
    sublattice_names = [s for s in sorted(subl_model.keys())]
    sqs = AbstractSQS(direct_lattice, species_list, species_positions, coords_are_cartesian=True,
              sublattice_model=sublattice_model,
              sublattice_names=sublattice_names)
    sqs.modify_lattice(Lattice(lattice))

    return sqs
Exemplo n.º 8
0
#%%

import math
from pymatgen import Structure, Molecule, Lattice
import os

os.chdir(
    '/home/jinho93/oxides/perobskite/lanthanum-aluminate/slab/gulp/nonstochio/La-vac/two'
)

m = Molecule.from_file('tail.xyz')
l = Lattice.from_lengths_and_angles([11.46615, 15.2882, 50], [90, 90, 90])

s = Structure(l, m.species, m.cart_coords, coords_are_cartesian=True)
s.make_supercell([[4, 0, 0], [0, 3, 0], [0, 0, 1]])
s.make_supercell([[1, 1, 0], [1, -1, 0], [0, 0, 1]])
s.sort()
# ll = Lattice.from_lengths_and_angles([s.lattice.a / 2, s.lattice.b / 2, s.lattice.c], s.lattice.angles)
ll = Lattice.from_lengths_and_angles(s.lattice.abc, s.lattice.angles)
s = Structure(ll, s.species, s.cart_coords, coords_are_cartesian=True)

indi = []
for i, site in enumerate(s.sites):
    if site.x + site.y < ll.b / math.sqrt(2):
        indi.append(i)

# s.remove_sites(indi)

# s = Structure(ll, s.species, s.cart_coords, coords_are_cartesian=True)

# s.to('POSCAR', 'POSCAR')
Exemplo n.º 9
0
    def _parse(self):

        float_patt = re.compile(r"[+-]?\d+\.\d+[EFD]?[+-]?\d+")  # -9.3892E+02
        start_patt = re.compile(r"^\s*EEEEEEEEEE STARTING  DATE \d+")
        coord_patt = re.compile(r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+"
                                r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)"
                                r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)")
        coord_nanotube_patt = re.compile(r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+"
                                         r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)"
                                         r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                         r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                         r"(?P<radius>\d+\.\d+)")
        forces_patt = re.compile(r"^\s+(?P<iat>\d+)\s+(?P<Z>\d+)\s+"
                                 r"(?P<x>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                 r"(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                 r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)")
        max_grad_patt = re.compile(r"^\sMAX GRADIENT\s+(?P<max_grad>\d+\.\d+)"
                                   r"\s+THRESHOLD\s+(?P<max_grad_thr>\d+\.\d+)")
        rms_grad_patt = re.compile(r"^\sRMS GRADIENT\s+(?P<rms_grad>\d+\.\d+)"
                                   r"\s+THRESHOLD\s+(?P<rms_grad_thr>\d+\.\d+)")
        max_displac_patt = re.compile(r"^\sMAX DISPLAC\.\s+(?P<max_displac>\d+\.\d+)"
                                      r"\s+THRESHOLD\s+(?P<max_displac_thr>\d+\.\d+)")
        rms_displac_patt = re.compile(r"^\sRMS DISPLAC\.\s+(?P<rms_displac>\d+\.\d+)"
                                      r"\s+THRESHOLD\s+(?P<rms_displac_thr>\d+\.\d+)")
        norm_grad_patt = re.compile(r"^\s+GRADIENT NORM\s+(?P<norm_grad>\d+\.\d+)"
                                    r"\s+GRADIENT THRESHOLD\s+(?P<norm_grad_thr>\d+\.\d+)")

        self.title = ""
        self.system = ""
        self.group = ""
        self.slab = False
        self.nanotube = False
        self.volumes = list()
        self.energies = list()
        self.forces = list()
        self.convergence_data = list()
        self.geometry_converge = False
        self.scf_converge = False

        external_geometry = False
        with open(self.filename, "r", encoding=self.encoding) as f:

            # look for starting message
            for line in f:
                if start_patt.match(line):
                    self.title = f.readline().strip()
                    break

            # ------------------------------------------------------------------
            # first, read the initial geometry & identify the type of structure
            # ------------------------------------------------------------------
            for line in f:
                if re.match(r"^\sGEOMETRY INPUT FROM EXTERNAL FILE", line):
                    external_geometry = True
                    line = f.readline()
                    if "SLAB" in line:
                        self.slab = True
                    if "NANOTUBE" in line:
                        self.nanotube = True

                    print("WARNING: Geometry from an external file.")
                    break

                if re.match(r"^\sSLAB CALCULATION", line):
                    self.slab = True
                    system_patt = re.compile(r"^\sSYSTEM AND LATTICE")
                    group_patt = re.compile(r" PLANE GROUP N.")
                    break

                if re.match(r"^\sCRYSTAL CALCULATION", line):
                    system_patt = re.compile(r"^\sCRYSTAL FAMILY")
                    group_patt = re.compile(r"^\sSPACE GROUP")
                    break

            # look for initial geometry: GEOMETRY FOR WAVEFUNCTION
            # read group and crystallographic system
            # check if a SLAB or NANOTUBE is built by GEOMETRY EDITING
            geom_for_wf = False
            for line in f:
                if not external_geometry and system_patt.search(line):
                    self.system = line.split(":")[1].strip()

                if not external_geometry and group_patt.search(line):
                    self.group = line.split(":")[1].strip()

                if " SLAB GENERATED " in line:
                    self.slab = True
                    # group and system no more relevant
                    self.group = ""
                    self.system = ""

                if "CONSTRUCTION OF A NANOTUBE FROM A SLAB" in line:
                    self.nanotube = True
                    self.slab = False
                    # group and system no more relevant
                    self.group = ""
                    self.system = ""

                if re.match(r"^\sGEOMETRY FOR WAVE FUNCTION", line):
                    geom_for_wf = True
                    break

                if line == "":
                    # end of file, geometry for wavefunction not found
                    break

            if not geom_for_wf:
                # STOP case, add TESTGEOM to d12
                raise ValueError("GEOMETRY FOR WAVEFUNCTION NOT FOUND.\n"
                                 "Please, add TESTGEOM in the d12 input file.")

            # read until calculation start
            # read starting geometry and look for PRIMITIVE or CRYSTALLOGRAPHIC
            read_geom = False
            while "CRYSTAL - SCF - TYPE OF CALCULATION" not in line:
                line = f.readline()

                if line == "":
                    raise ValueError("End of file.")

                # search PRIMITIVE CELL
                if re.match(r"^\sPRIMITIVE CELL", line):
                    read_geom = True
                    geom_patt = re.compile(r"^\sPRIMITIVE CELL")

                # search CRYSTALLOGRAPHIC CELL if exist
                if re.match(r"^\sCRYSTALLOGRAPHIC CELL", line):
                    read_geom = True
                    geom_patt = re.compile(r"^\sCRYSTALLOGRAPHIC CELL")

                if read_geom:
                    if not self.slab and not self.nanotube:
                        volume = float(line.split("=")[1].split()[0].strip(")"))
                        self.volumes.append(volume)
                    f.readline()

                    # lattice parameters
                    line = f.readline()
                    params = [float(val) for val in re.findall(r"\d+\.\d+", line)]
                    lattice = Lattice.from_lengths_and_angles(params[0:3], params[3:])

                    # step on for 4 lines
                    [f.readline() for _ in range(4)]

                    # read coordinates
                    species = list()    # atom names
                    uniq = list()   # True if atom belong to the asymmetric unit
                    radius = list()  # distance from the axes of the nanotube
                    coords = list()
                    while line != "\n":
                        read = False
                        line = f.readline()
                        if self.nanotube and coord_nanotube_patt.match(line):
                            data = coord_nanotube_patt.match(line).groupdict()
                            read = True
                        elif coord_patt.match(line):
                            data = coord_patt.match(line).groupdict()
                            read = True

                        if read:
                            specie = data["specie"]
                            specie = specie if len(specie) == 1 else specie[0] + specie[1].lower()
                            species.append(specie)
                            coord = [float(data[k]) for k in "xyz"]
                            uniq.append(True if data["aunit"] == "T" else False)

                            if self.slab:
                                coord[2] /= lattice.c
                            elif self.nanotube:
                                coord[1] /= lattice.b
                                coord[2] /= lattice.c
                                radius.append(float(data["radius"]))

                            coords.append(coord)

                    self.structures = [Structure(lattice, species, coords,
                                                 site_properties={"aunit": uniq})]

                    read_geom = False

            # ------------------------------------------------------------------
            # from that point, SCF, or structure optimization start !
            # continue up to the end of file
            # ------------------------------------------------------------------
            n_geom = 0
            cvg_data = dict()
            while line != "":
                line = f.readline()

                if " TOTAL ENERGY" in line:
                    self.energies.append(float(float_patt.findall(line)[0]))
                    self.scf_converge = True

                if "CARTESIAN FORCES IN HARTREE/BOHR" in line:
                    # WARNING: Forces are not printed at each geom step
                    line = f.readline()
                    forces = list()
                    for _ in range(self.initial_structure.num_sites):
                        data = forces_patt.match(f.readline()).groupdict()
                        forces.append([float(data[c]) for c in "xyz"])
                    self.forces.append(np.array(forces))

                if max_grad_patt.match(line):
                    cvg_data.update(max_grad_patt.match(line).groupdict())
                if rms_grad_patt.match(line):
                    cvg_data.update(rms_grad_patt.match(line).groupdict())
                if max_displac_patt.match(line):
                    cvg_data.update(max_displac_patt.match(line).groupdict())
                if rms_displac_patt.match(line):
                    cvg_data.update(rms_displac_patt.match(line).groupdict())
                if norm_grad_patt.match(line):
                    cvg_data.update(norm_grad_patt.match(line).groupdict())

                if line == "":
                    # end of file ?
                    break

                if "COORDINATE AND CELL OPTIMIZATION" in line:
                    cvg_data = {k: float(v) for k, v in cvg_data.items()}
                    # end of optimization cycle
                    self.convergence_data.append(cvg_data)
                    n_geom += 1
                    cvg_data = dict()

                if "FINAL OPTIMIZED GEOMETRY" in line:
                    self.geometry_converge = True
                    n_geom += 1

                # search structure data
                if geom_patt.match(line):
                    # PRIMITVE or CRYSTALLOGRAPHIC depending on what is present
                    read_geom = True

                if read_geom:
                    if not self.slab and not self.nanotube:
                        volume = float(line.split("=")[1].split()[0].strip(")"))
                        self.volumes.append(volume)
                    f.readline()

                    # lattice parameters
                    line = f.readline()
                    params = [float(val) for val in re.findall(r"\d+\.\d+", line)]
                    lattice = Lattice.from_lengths_and_angles(params[0:3], params[3:])

                    # step on for 4 lines
                    [f.readline() for _ in range(4)]

                    # read coordinates
                    species = list()    # atom names
                    uniq = list()   # True if atom belong to the asymmetric unit
                    radius = list()  # distance from the axes of the nanotube
                    coords = list()
                    while line != "\n":
                        read = False
                        line = f.readline()
                        if self.nanotube and coord_nanotube_patt.match(line):
                            data = coord_nanotube_patt.match(line).groupdict()
                            read = True
                        elif coord_patt.match(line):
                            data = coord_patt.match(line).groupdict()
                            read = True

                        if read:
                            specie = data["specie"]
                            specie = specie if len(specie) == 1 else specie[0] + specie[1].lower()
                            species.append(specie)
                            coord = [float(data[k]) for k in "xyz"]
                            uniq.append(True if data["aunit"] == "T" else False)

                            if self.slab:
                                coord[2] /= lattice.c
                            elif self.nanotube:
                                coord[1] /= lattice.b
                                coord[2] /= lattice.c
                                radius.append(float(data["radius"]))

                            coords.append(coord)

                    self.structures.append(Structure(lattice, species, coords,
                                                     site_properties={"aunit": uniq}))

                    read_geom = False
Exemplo n.º 10
0
    def _parse(self):

        float_patt = re.compile(r"[+-]?\d+\.\d+[EFD]?[+-]?\d+")  # -9.3892E+02
        start_patt = re.compile(r"^\s*EEEEEEEEEE STARTING  DATE \d+")
        coord_patt = re.compile(
            r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+"
            r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)"
            r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
            r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)")
        coord_nanotube_patt = re.compile(
            r"^\s+(\d+)\s+(?P<aunit>[TF])\s+(?P<Z>\d+)\s+"
            r"(?P<specie>\w+)\s+(?P<x>[+-]?\d+\.\d+E[+-]?\d+)"
            r"\s+(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
            r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)\s+"
            r"(?P<radius>\d+\.\d+)")
        forces_patt = re.compile(r"^\s+(?P<iat>\d+)\s+(?P<Z>\d+)\s+"
                                 r"(?P<x>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                 r"(?P<y>[+-]?\d+\.\d+E[+-]?\d+)\s+"
                                 r"(?P<z>[+-]?\d+\.\d+E[+-]?\d+)")
        max_grad_patt = re.compile(
            r"^\sMAX GRADIENT\s+(?P<max_grad>\d+\.\d+)"
            r"\s+THRESHOLD\s+(?P<max_grad_thr>\d+\.\d+)")
        rms_grad_patt = re.compile(
            r"^\sRMS GRADIENT\s+(?P<rms_grad>\d+\.\d+)"
            r"\s+THRESHOLD\s+(?P<rms_grad_thr>\d+\.\d+)")
        max_displac_patt = re.compile(
            r"^\sMAX DISPLAC\.\s+(?P<max_displac>\d+\.\d+)"
            r"\s+THRESHOLD\s+(?P<max_displac_thr>\d+\.\d+)")
        rms_displac_patt = re.compile(
            r"^\sRMS DISPLAC\.\s+(?P<rms_displac>\d+\.\d+)"
            r"\s+THRESHOLD\s+(?P<rms_displac_thr>\d+\.\d+)")
        norm_grad_patt = re.compile(
            r"^\s+GRADIENT NORM\s+(?P<norm_grad>\d+\.\d+)"
            r"\s+GRADIENT THRESHOLD\s+(?P<norm_grad_thr>\d+\.\d+)")

        self.title = ""
        self.system = ""
        self.group = ""
        self.slab = False
        self.nanotube = False
        self.volumes = list()
        self.energies = list()
        self.forces = list()
        self.convergence_data = list()
        self.geometry_converge = False
        self.scf_converge = False

        external_geometry = False
        with open(self.filename, "r", encoding=self.encoding) as f:

            # look for starting message
            for line in f:
                if start_patt.match(line):
                    self.title = f.readline().strip()
                    break

            # ------------------------------------------------------------------
            # first, read the initial geometry & identify the type of structure
            # ------------------------------------------------------------------
            for line in f:
                if re.match(r"^\sGEOMETRY INPUT FROM EXTERNAL FILE", line):
                    external_geometry = True
                    line = f.readline()
                    if "SLAB" in line:
                        self.slab = True
                    if "NANOTUBE" in line:
                        self.nanotube = True

                    print("WARNING: Geometry from an external file.")
                    break

                if re.match(r"^\sSLAB CALCULATION", line):
                    self.slab = True
                    system_patt = re.compile(r"^\sSYSTEM AND LATTICE")
                    group_patt = re.compile(r" PLANE GROUP N.")
                    break

                if re.match(r"^\sCRYSTAL CALCULATION", line):
                    system_patt = re.compile(r"^\sCRYSTAL FAMILY")
                    group_patt = re.compile(r"^\sSPACE GROUP")
                    break

            # look for initial geometry: GEOMETRY FOR WAVEFUNCTION
            # read group and crystallographic system
            # check if a SLAB or NANOTUBE is built by GEOMETRY EDITING
            geom_for_wf = False
            for line in f:
                if not external_geometry and system_patt.search(line):
                    self.system = line.split(":")[1].strip()

                if not external_geometry and group_patt.search(line):
                    self.group = line.split(":")[1].strip()

                if " SLAB GENERATED " in line:
                    self.slab = True
                    # group and system no more relevant
                    self.group = ""
                    self.system = ""

                if "CONSTRUCTION OF A NANOTUBE FROM A SLAB" in line:
                    self.nanotube = True
                    self.slab = False
                    # group and system no more relevant
                    self.group = ""
                    self.system = ""

                if re.match(r"^\sGEOMETRY FOR WAVE FUNCTION", line):
                    geom_for_wf = True
                    break

                if line == "":
                    # end of file, geometry for wavefunction not found
                    break

            if not geom_for_wf:
                # STOP case, add TESTGEOM to d12
                raise ValueError("GEOMETRY FOR WAVEFUNCTION NOT FOUND.\n"
                                 "Please, add TESTGEOM in the d12 input file.")

            # read until calculation start
            # read starting geometry and look for PRIMITIVE or CRYSTALLOGRAPHIC
            read_geom = False
            while "CRYSTAL - SCF - TYPE OF CALCULATION" not in line:
                line = f.readline()

                if line == "":
                    raise ValueError("End of file.")

                # search PRIMITIVE CELL
                if re.match(r"^\sPRIMITIVE CELL", line):
                    read_geom = True
                    geom_patt = re.compile(r"^\sPRIMITIVE CELL")

                # search CRYSTALLOGRAPHIC CELL if exist
                if re.match(r"^\sCRYSTALLOGRAPHIC CELL", line):
                    read_geom = True
                    geom_patt = re.compile(r"^\sCRYSTALLOGRAPHIC CELL")

                if read_geom:
                    if not self.slab and not self.nanotube:
                        volume = float(
                            line.split("=")[1].split()[0].strip(")"))
                        self.volumes.append(volume)
                    f.readline()

                    # lattice parameters
                    line = f.readline()
                    params = [
                        float(val) for val in re.findall(r"\d+\.\d+", line)
                    ]
                    lattice = Lattice.from_lengths_and_angles(
                        params[0:3], params[3:])

                    # step on for 4 lines
                    [f.readline() for _ in range(4)]

                    # read coordinates
                    species = list()  # atom names
                    uniq = list()  # True if atom belong to the asymmetric unit
                    radius = list()  # distance from the axes of the nanotube
                    coords = list()
                    while line != "\n":
                        read = False
                        line = f.readline()
                        if self.nanotube and coord_nanotube_patt.match(line):
                            data = coord_nanotube_patt.match(line).groupdict()
                            read = True
                        elif coord_patt.match(line):
                            data = coord_patt.match(line).groupdict()
                            read = True

                        if read:
                            specie = data["specie"]
                            specie = specie if len(
                                specie
                            ) == 1 else specie[0] + specie[1].lower()
                            species.append(specie)
                            coord = [float(data[k]) for k in "xyz"]
                            uniq.append(True if data["aunit"] ==
                                        "T" else False)

                            if self.slab:
                                coord[2] /= lattice.c
                            elif self.nanotube:
                                coord[1] /= lattice.b
                                coord[2] /= lattice.c
                                radius.append(float(data["radius"]))

                            coords.append(coord)

                    self.structures = [
                        Structure(lattice,
                                  species,
                                  coords,
                                  site_properties={"aunit": uniq})
                    ]

                    read_geom = False

            # ------------------------------------------------------------------
            # from that point, SCF, or structure optimization start !
            # continue up to the end of file
            # ------------------------------------------------------------------
            n_geom = 0
            cvg_data = dict()
            while line != "":
                line = f.readline()

                if " TOTAL ENERGY" in line:
                    self.energies.append(float(float_patt.findall(line)[0]))
                    self.scf_converge = True

                if "CARTESIAN FORCES IN HARTREE/BOHR" in line:
                    # WARNING: Forces are not printed at each geom step
                    line = f.readline()
                    forces = list()
                    for _ in range(self.initial_structure.num_sites):
                        data = forces_patt.match(f.readline()).groupdict()
                        forces.append([float(data[c]) for c in "xyz"])
                    self.forces.append(np.array(forces))

                if max_grad_patt.match(line):
                    cvg_data.update(max_grad_patt.match(line).groupdict())
                if rms_grad_patt.match(line):
                    cvg_data.update(rms_grad_patt.match(line).groupdict())
                if max_displac_patt.match(line):
                    cvg_data.update(max_displac_patt.match(line).groupdict())
                if rms_displac_patt.match(line):
                    cvg_data.update(rms_displac_patt.match(line).groupdict())
                if norm_grad_patt.match(line):
                    cvg_data.update(norm_grad_patt.match(line).groupdict())

                if line == "":
                    # end of file ?
                    break

                if "COORDINATE AND CELL OPTIMIZATION" in line:
                    cvg_data = {k: float(v) for k, v in cvg_data.items()}
                    # end of optimization cycle
                    self.convergence_data.append(cvg_data)
                    n_geom += 1
                    cvg_data = dict()

                if "FINAL OPTIMIZED GEOMETRY" in line:
                    self.geometry_converge = True
                    n_geom += 1

                # search structure data
                if geom_patt.match(line):
                    # PRIMITVE or CRYSTALLOGRAPHIC depending on what is present
                    read_geom = True

                if read_geom:
                    if not self.slab and not self.nanotube:
                        volume = float(
                            line.split("=")[1].split()[0].strip(")"))
                        self.volumes.append(volume)
                    f.readline()

                    # lattice parameters
                    line = f.readline()
                    params = [
                        float(val) for val in re.findall(r"\d+\.\d+", line)
                    ]
                    lattice = Lattice.from_lengths_and_angles(
                        params[0:3], params[3:])

                    # step on for 4 lines
                    [f.readline() for _ in range(4)]

                    # read coordinates
                    species = list()  # atom names
                    uniq = list()  # True if atom belong to the asymmetric unit
                    radius = list()  # distance from the axes of the nanotube
                    coords = list()
                    while line != "\n":
                        read = False
                        line = f.readline()
                        if self.nanotube and coord_nanotube_patt.match(line):
                            data = coord_nanotube_patt.match(line).groupdict()
                            read = True
                        elif coord_patt.match(line):
                            data = coord_patt.match(line).groupdict()
                            read = True

                        if read:
                            specie = data["specie"]
                            specie = specie if len(
                                specie
                            ) == 1 else specie[0] + specie[1].lower()
                            species.append(specie)
                            coord = [float(data[k]) for k in "xyz"]
                            uniq.append(True if data["aunit"] ==
                                        "T" else False)

                            if self.slab:
                                coord[2] /= lattice.c
                            elif self.nanotube:
                                coord[1] /= lattice.b
                                coord[2] /= lattice.c
                                radius.append(float(data["radius"]))

                            coords.append(coord)

                    self.structures.append(
                        Structure(lattice,
                                  species,
                                  coords,
                                  site_properties={"aunit": uniq}))

                    read_geom = False
Exemplo n.º 11
0
    def build_gb(self,
                 vacuum=0.0,
                 add_if_dist=0.0,
                 to_primitive=True,
                 delete_layer="0b0t0b0t",
                 tol=0.25):
        """
        Build the GB based on the given crystal, uc of grain A and B, if_model,
        vacuum thickness, distance between two grains and tolerance factor.
        Args:
            vacuum (float), Angstrom: Vacuum thickness for GB.
                Default to 0.0
            add_if_dist (float), Angstrom: Add extra distance at the interface
                between two grains.
                Default to 0.0
            to_primitive (bool): Whether to get primitive structure of GB.
                Default to true.
            delete_layer (str): Delete interface layers on both sides of each grain.
                8 characters in total. The first 4 characters is for grain A and
                the other 4 is for grain B. "b" means bottom layer and "t" means
                top layer. Integer represents the number of layers to be deleted.
                Default to "0b0t0b0t", which means no deletion of layers. The
                direction of top and bottom layers is based on gb_direction.
            tol (float), Angstrom: Tolerance factor to determine whether two
                atoms are at the same plane.
                Default to 0.25
        Returns:
             GB structure (Grain)
        """
        ind = self.gb_direction
        delete_layer = delete_layer.lower()
        delete = re.findall('(\d+)(\w)', delete_layer)
        if len(delete) != 4:
            raise ValueError(
                "'%s' is not supported. Please make sure the format "
                "is 0b0t0b0t.")
        for i, v in enumerate(delete):
            for j in range(int(v[0])):
                if i <= 1:
                    self.grain_a.delete_bt_layer(v[1], tol, ind)
                else:
                    self.grain_b.delete_bt_layer(v[1], tol, ind)
        abc_a = list(self.grain_a.lattice.abc)
        abc_b, angles = self.grain_b.lattice.lengths_and_angles
        if ind == 1:
            l = (abc_a[ind] + add_if_dist) * sin(radians(angles[2]))
        else:
            l = abc_a[ind] + add_if_dist
        abc_a[ind] += abc_b[ind] + 2 * add_if_dist + vacuum
        new_lat = Lattice.from_lengths_and_angles(abc_a, angles)
        a_fcoords = new_lat.get_fractional_coords(self.grain_a.cart_coords)

        grain_a = Grain(new_lat, self.grain_a.species, a_fcoords)
        l_vector = [0, 0]
        l_vector.insert(ind, l)
        b_fcoords = new_lat.get_fractional_coords(self.grain_b.cart_coords +
                                                  l_vector)
        grain_b = Grain(new_lat, self.grain_b.species, b_fcoords)

        gb = Grain.from_sites(grain_a[:] + grain_b[:])
        gb = gb.get_sorted_structure()
        if to_primitive:
            gb = gb.get_primitive_structure()
        return gb