Ejemplo n.º 1
0
    def test_init(self):
        zno_slab = Slab(self.zno55.lattice, self.zno55.species,
                        self.zno55.frac_coords, self.zno55.miller_index,
                        self.zno55.oriented_unit_cell, 0,
                        self.zno55.scale_factor)
        m = self.zno55.lattice.matrix
        area = np.linalg.norm(np.cross(m[0], m[1]))
        self.assertAlmostEqual(zno_slab.surface_area, area)
        self.assertEqual(zno_slab.lattice.parameters,
                         self.zno55.lattice.parameters)
        self.assertEqual(zno_slab.oriented_unit_cell.composition,
                         self.zno1.composition)
        self.assertEqual(len(zno_slab), 8)

        # check reorient_lattice. get a slab not oriented and check that orientation
        # works even with cartesian coordinates.
        zno_not_or = SlabGenerator(self.zno1, [1, 0, 0],
                                   5,
                                   5,
                                   lll_reduce=False,
                                   center_slab=False,
                                   reorient_lattice=False).get_slab()
        zno_slab_cart = Slab(zno_not_or.lattice,
                             zno_not_or.species,
                             zno_not_or.cart_coords,
                             zno_not_or.miller_index,
                             zno_not_or.oriented_unit_cell,
                             0,
                             zno_not_or.scale_factor,
                             coords_are_cartesian=True,
                             reorient_lattice=True)
        self.assertArrayAlmostEqual(zno_slab.frac_coords,
                                    zno_slab_cart.frac_coords)
        c = zno_slab_cart.lattice.matrix[2]
        self.assertArrayAlmostEqual([0, 0, np.linalg.norm(c)], c)
Ejemplo n.º 2
0
    def test_as_dict(self):
        slabs = generate_all_slabs(
            self.ti,
            1,
            10,
            10,
            bonds=None,
            tol=1e-3,
            max_broken_bonds=0,
            lll_reduce=False,
            center_slab=False,
            primitive=True,
        )
        slab = slabs[0]
        s = json.dumps(slab.as_dict())
        d = json.loads(s)
        self.assertEqual(slab, Slab.from_dict(d))

        # test initialising with a list scale_factor
        slab = Slab(
            self.zno55.lattice,
            self.zno55.species,
            self.zno55.frac_coords,
            self.zno55.miller_index,
            self.zno55.oriented_unit_cell,
            0,
            self.zno55.scale_factor.tolist(),
        )
        s = json.dumps(slab.as_dict())
        d = json.loads(s)
        self.assertEqual(slab, Slab.from_dict(d))
Ejemplo n.º 3
0
 def __init__(self, strt, hkl=[1,1,1], min_thick=10, min_vac=10,
              supercell=[1,1,1], name=None, adsorb_on_species=None,
              adatom_on_lig=None, ligand=None, displacement=1.0,
              surface_coverage=None, scell_nmax=10,
              coverage_tol=0.25, solvent=None, 
              start_from_slab=False, validate_proximity=False,
              to_unit_cell=False, coords_are_cartesian=False,
              primitive=True, from_ase=False,
              x_shift=0, y_shift=0, rot=[0,0,0],
              center_slab=True):
     self.from_ase = from_ase
     vac_extension = 0
     if ligand is not None:
         vac_extension = ligand.max_dist
     if isinstance(strt, Structure) and not isinstance(strt, Slab):
         self.min_vac = min_vac + vac_extension
         if self.from_ase:
             strt = get_ase_slab(strt,
                                 hkl=hkl,
                                 min_thick=min_thick,
                                 min_vac=min_vac + vac_extension, 
                                 center_slab=center_slab)
         else:
             strt = SlabGenerator(strt, hkl, min_thick,
                                  min_vac + vac_extension,
                                  center_slab=center_slab,
                                  primitive = primitive).get_slab()
         strt.make_supercell(supercell)
     else:
         self.min_vac = min_vac
     Slab.__init__(self, strt.lattice, strt.species_and_occu,
                   strt.frac_coords,
                   miller_index=strt.miller_index,
                   oriented_unit_cell=strt.oriented_unit_cell,
                   shift=strt.shift, scale_factor=strt.scale_factor,
                   validate_proximity=validate_proximity,
                   to_unit_cell=to_unit_cell,
                   coords_are_cartesian=coords_are_cartesian,
                   site_properties=strt.site_properties,
                   energy=strt.energy )
     self.strt= strt
     self.name = name
     self.hkl = hkl
     self.min_thick = min_thick
     self.supercell = supercell
     self.ligand = ligand
     self.slab = strt
     self.displacement = displacement
     self.solvent = solvent
     self.surface_coverage = surface_coverage
     self.adsorb_on_species = adsorb_on_species
     self.adatom_on_lig = adatom_on_lig
     self.scell_nmax = scell_nmax
     self.coverage_tol = coverage_tol
     self.x_shift = x_shift
     self.y_shift = y_shift
     self.rot = rot
Ejemplo n.º 4
0
def slab_from_file(structure, hkl):
    """
    Reads in structure from the file and returns slab object.

    Args:
         structure (str): Structure file in any format supported by pymatgen.
            Will accept a pymatgen.Structure object directly.
         hkl (tuple): Miller index of the slab in the input file.

    Returns:
         Slab object
    """
    if type(structure) == str:
        slab_input = Structure.from_file(structure)
    else:
        slab_input = structure
    return Slab(
        slab_input.lattice,
        slab_input.species_and_occu,
        slab_input.frac_coords,
        hkl,
        Structure.from_sites(slab_input, to_unit_cell=True),
        # this OUC is not correct, need to get it from slabgenerator
        shift=0,
        scale_factor=np.eye(3, dtype=np.int),
        site_properties=slab_input.site_properties)
Ejemplo n.º 5
0
def get_ase_slab(pmg_struct, hkl=(1, 1, 1), min_thick=10, min_vac=10):
    """
    takes in the intial structure as pymatgen Structure object
    uses ase to generate the slab
    returns pymatgen Slab object
    
    Args:
	pmg_struct: pymatgen structure object
	hkl: hkl index of surface of slab to be created
	min_thick: minimum thickness of slab in Angstroms
	min_vac: minimum vacuum spacing 
    """
    ase_atoms = AseAtomsAdaptor().get_atoms(pmg_struct)
    pmg_slab_gen = SlabGenerator(pmg_struct, hkl, min_thick, min_vac)
    h = pmg_slab_gen._proj_height
    nlayers = int(math.ceil(pmg_slab_gen.min_slab_size / h))
    ase_slab = surface(ase_atoms, hkl, nlayers)
    ase_slab.center(vacuum=min_vac / 2, axis=2)
    pmg_slab_structure = AseAtomsAdaptor().get_structure(ase_slab)
    return Slab(lattice=pmg_slab_structure.lattice,
                species=pmg_slab_structure.species_and_occu,
                coords=pmg_slab_structure.frac_coords,
                site_properties=pmg_slab_structure.site_properties,
                miller_index=hkl,
                oriented_unit_cell=pmg_slab_structure,
                shift=0.,
                scale_factor=None,
                energy=None)
Ejemplo n.º 6
0
    def apply_transformation(self, structure, matrix):
        """
        Make a supercell of structure using matrix

        Args:
            structure (Slab): Slab to make supercell of
            matrix (3x3 np.ndarray): supercell matrix

        Returns:
            (Slab) The supercell of structure
        """
        modified_substrate_structure = structure.copy()
        # Apply scaling
        modified_substrate_structure.make_supercell(matrix)

        # Reduce vectors
        new_lattice = modified_substrate_structure.lattice.matrix.copy()
        new_lattice[:2, :] = reduce_vectors(
            *modified_substrate_structure.lattice.matrix[:2, :])
        modified_substrate_structure = Slab(
            lattice=Lattice(new_lattice),
            species=modified_substrate_structure.species,
            coords=modified_substrate_structure.cart_coords,
            miller_index=modified_substrate_structure.miller_index,
            oriented_unit_cell=modified_substrate_structure.oriented_unit_cell,
            shift=modified_substrate_structure.shift,
            scale_factor=modified_substrate_structure.scale_factor,
            coords_are_cartesian=True,
            energy=modified_substrate_structure.energy,
            reorient_lattice=modified_substrate_structure.reorient_lattice,
            to_unit_cell=True)

        return modified_substrate_structure
Ejemplo n.º 7
0
def get_shear_reduced_slab(slab):
    """
    Reduce the vectors of the slab plane according to the algorithm in
    substrate_analyzer, then make a new Slab with a Lattice with those
    reduced vectors.

    Args:
        slab (Slab): Slab to reduce

    Returns:
        Slab object of identical structure to the input slab
        but rduced in-plane lattice vectors
    """
    original_vectors = [slab.lattice.matrix[0], slab.lattice.matrix[1]]
    reduced_vectors = reduce_vectors(slab.lattice.matrix[0],
                                     slab.lattice.matrix[1])
    new_lattice = Lattice(
        [reduced_vectors[0], reduced_vectors[1], slab.lattice.matrix[2]])
    return Slab(lattice=new_lattice,
                species=slab.species,
                coords=slab.cart_coords,
                miller_index=slab.miller_index,
                oriented_unit_cell=slab.oriented_unit_cell,
                shift=slab.shift,
                scale_factor=slab.scale_factor,
                coords_are_cartesian=True,
                energy=slab.energy,
                reorient_lattice=slab.reorient_lattice,
                to_unit_cell=True)
Ejemplo n.º 8
0
    def test_add_adsorbate_atom(self):
        zno_slab = Slab(self.zno55.lattice, self.zno55.species,
                        self.zno55.frac_coords, self.zno55.miller_index,
                        self.zno55.oriented_unit_cell, 0,
                        self.zno55.scale_factor)
        zno_slab.add_adsorbate_atom([1], 'H', 1)

        self.assertEqual(len(zno_slab), 9)
        self.assertEqual(str(zno_slab[8].specie), 'H')
        self.assertAlmostEqual(zno_slab.get_distance(1, 8), 1.0)
        self.assertTrue(zno_slab[8].c > zno_slab[0].c)
        m = self.zno55.lattice.matrix
        area = np.linalg.norm(np.cross(m[0], m[1]))
        self.assertAlmostEqual(zno_slab.surface_area, area)
        self.assertEqual(zno_slab.lattice.lengths_and_angles,
                         self.zno55.lattice.lengths_and_angles)
Ejemplo n.º 9
0
 def test_as_dict(self):
     slabs = generate_all_slabs(self.ti, 1, 10, 10, bonds=None,
                                tol=1e-3, max_broken_bonds=0, lll_reduce=False, center_slab=False,
                                primitive=True)
     slab = slabs[0]
     s = json.dumps(slab.as_dict())
     d = json.loads(s)
     self.assertEqual(slab, Slab.from_dict(d))
Ejemplo n.º 10
0
    def test_add_adsorbate_atom(self):
        zno_slab = Slab(self.zno55.lattice, self.zno55.species,
                        self.zno55.frac_coords,
                        self.zno55.miller_index,
                        self.zno55.oriented_unit_cell,
                        0, self.zno55.scale_factor)
        zno_slab.add_adsorbate_atom([1], 'H', 1)

        self.assertEqual(len(zno_slab), 9)
        self.assertEqual(str(zno_slab[8].specie), 'H')
        self.assertAlmostEqual(zno_slab.get_distance(1, 8), 1.0)
        self.assertTrue(zno_slab[8].c > zno_slab[0].c)
        m = self.zno55.lattice.matrix
        area = np.linalg.norm(np.cross(m[0], m[1]))
        self.assertAlmostEqual(zno_slab.surface_area, area)
        self.assertEqual(zno_slab.lattice.lengths_and_angles,
                         self.zno55.lattice.lengths_and_angles)
Ejemplo n.º 11
0
 def test_init(self):
     zno_slab = Slab(self.zno55.lattice, self.zno55.species,
                     self.zno55.frac_coords,
                     self.zno55.miller_index,
                     self.zno55.oriented_unit_cell,
                     0, self.zno55.scale_factor)
     m = self.zno55.lattice.matrix
     area = np.linalg.norm(np.cross(m[0], m[1]))
     self.assertAlmostEqual(zno_slab.surface_area, area)
     self.assertEqual(zno_slab.lattice.parameters, self.zno55.lattice.parameters)
     self.assertEqual(zno_slab.oriented_unit_cell.composition, self.zno1.composition)
     self.assertEqual(len(zno_slab), 8)
Ejemplo n.º 12
0
 def trajToMG(self):
     from pymatgen.io.ase import AseAtomsAdaptor
     from pymatgen.core.surface import Slab
     atoms = self.trajInput()
     struct = AseAtomsAdaptor.get_structure(atoms)
     return Slab(struct.lattice,
                 struct.species,
                 struct.cart_coords, (1, 1, 0),
                 struct,
                 3, (1, 1, 1),
                 coords_are_cartesian=True,
                 to_unit_cell=True)
Ejemplo n.º 13
0
def merge_slabs(substrate, film, slab_offset, x_offset, y_offset, vacuum=20, **kwargs):
    """
    Given substrate and film supercells (oriented to match as closely as possible),
    strain the film to match the substrate lattice and combine the slabs.

    Args:
        slab_offset: spacing between the substrate and film
        x_offset y_offset: in-plane displacement of the film in Cartesian coordinates
        vacuum: vacuum buffer above the film

    Returns:
        combined_structure (Slab): A structure with the strained film and substrate
            combined into one structure
    """
    # strain film to match substrate
    new_latt = film.lattice.matrix.copy()
    new_latt[:2, :2] = substrate.lattice.matrix[:2, :2]
    film.lattice = Lattice(new_latt)

    combined_species = [*substrate.species, *film.species]
    if kwargs.get('cell_height'):
        height = kwargs.get('cell_height')
    else:
        added_height = vacuum + slab_offset + film.lattice.c
        height = added_height + substrate.lattice.matrix[2, 2]
    combined_lattice = substrate.lattice.matrix.copy()
    combined_lattice[2, :] *= height / substrate.lattice.matrix[2, 2]

    max_substrate = np.max(substrate.cart_coords[:, 2])
    min_substrate = np.min(film.cart_coords[:, 2])
    offset = max_substrate - min_substrate + slab_offset
    offset_film_coords = [np.add(coord, [x_offset, y_offset, offset]) for coord in film.cart_coords]
    combined_coords = [*substrate.cart_coords, *offset_film_coords]
    combined_site_properties = {}
    for key, item in substrate.site_properties.items():
        combined_site_properties[key] = [*substrate.site_properties[key], *film.site_properties[key]]
    labels = ['substrate'] * len(substrate) + ['film'] * len(film)
    combined_site_properties['interface_label'] = labels

    combined_structure = Slab(lattice=Lattice(combined_lattice), species=combined_species,
                              coords=combined_coords,
                              miller_index=substrate.miller_index,
                              oriented_unit_cell=substrate,
                              shift=substrate.shift,
                              scale_factor=substrate.scale_factor,
                              coords_are_cartesian=True, energy=substrate.energy,
                              reorient_lattice=False, to_unit_cell=True,
                              site_properties=combined_site_properties)
    return combined_structure
Ejemplo n.º 14
0
def makePMGSlabFromASE(a, facet):
    lattice = a.get_cell()
    species = a.get_chemical_symbols()
    coords = a.get_positions()
    miller_index = facet
    oriented_unit_cell = AseAtomsAdaptor.get_structure(a)
    shift = 0
    scale_factor = None  #???????
    return Slab(lattice,
                species,
                coords,
                miller_index,
                oriented_unit_cell,
                shift,
                scale_factor,
                coords_are_cartesian=True)
Ejemplo n.º 15
0
def slab_from_file(structure, hkl):
    """
    Reads in structure from the file and returns slab object.

    Args:
         structure (str): structure file in any format supported by pymatgen
         hkl (tuple): Miller index of the slab in the input file.

    Returns:
         Slab object
    """
    slab_input = Structure.from_file(structure)
    return Slab(slab_input.lattice,
                slab_input.species_and_occu,
                slab_input.frac_coords,
                hkl,
                Structure.from_sites(slab_input, to_unit_cell=True),
                shift=0,
                scale_factor=np.eye(3, dtype=np.int),
                site_properties=slab_input.site_properties)
Ejemplo n.º 16
0
def slab_from_file(hkl, filename):
    """
    reads in structure from the file and returns slab object.
    useful for reading in 2d/substrate structures from file.
    Args:
         hkl: miller index of the slab in the input file.
         filename: structure file in any format 
                   supported by pymatgen
    Returns:
         Slab object
    """
    slab_input = Structure.from_file(filename)
    return Slab(slab_input.lattice,
                slab_input.species_and_occu,
                slab_input.frac_coords,
                hkl,
                Structure.from_sites(slab_input, to_unit_cell=True),
                shift=0,
                scale_factor=np.eye(3, dtype=np.int),
                site_properties=slab_input.site_properties)
Ejemplo n.º 17
0
def add_vacuum_padding(slab, vacuum, hkl=[0, 0, 1]):
    """
    add vacuum spacing to the given structure
    Args:
        slab: sructure/slab object to be padded 
        vacuum: in angstroms
        hkl: miller index
    Returns:
         Structure object
    """
    min_z = np.min([fcoord[2] for fcoord in slab.frac_coords])
    slab.translate_sites(list(range(len(slab))), [0, 0, -min_z])
    a, b, c = slab.lattice.matrix
    z = [coord[2] for coord in slab.cart_coords]
    zmax = np.max(z)
    zmin = np.min(z)
    thickness = zmax - zmin
    new_c = c / np.linalg.norm(c) * (thickness + vacuum)
    new_lattice = Lattice(np.array([a, b, new_c]))
    new_sites = []
    for site in slab:
        new_sites.append(
            PeriodicSite(site.species_and_occu,
                         site.coords,
                         new_lattice,
                         properties=site.properties,
                         coords_are_cartesian=True))
    new_struct = Structure.from_sites(new_sites)
    # center the slab
    avg_z = np.average([fcoord[2] for fcoord in new_struct.frac_coords])
    new_struct.translate_sites(list(range(len(new_struct))),
                               [0, 0, 0.5 - avg_z])
    return Slab(new_struct.lattice,
                new_struct.species_and_occu,
                new_struct.frac_coords,
                hkl,
                Structure.from_sites(new_struct, to_unit_cell=True),
                shift=0,
                scale_factor=np.eye(3, dtype=np.int),
                site_properties=new_struct.site_properties)
Ejemplo n.º 18
0
def adsorb_both_surfaces(slab,
                         molecule,
                         selective_dynamics=False,
                         height=0.9,
                         mi_vec=None,
                         repeat=None,
                         min_lw=5.0,
                         reorient=True,
                         find_args={}):
    """
    Function that generates all adsorption structures for a given
    molecular adsorbate on both surfaces of a slab.

    Args:
        slab (Slab): slab object for which to find adsorbate sites
        selective_dynamics (bool): flag for whether to assign
            non-surface sites as fixed for selective dynamics
        molecule (Molecule): molecule corresponding to adsorbate
        selective_dynamics (bool): flag for whether to assign
            non-surface sites as fixed for selective dynamics
        height (float): height criteria for selection of surface sites
        mi_vec (3-D array-like): vector corresponding to the vector
            concurrent with the miller index, this enables use with
            slabs that have been reoriented, but the miller vector
            must be supplied manually
        repeat (3-tuple or list): repeat argument for supercell generation
        min_lw (float): minimum length and width of the slab, only used
            if repeat is None
        reorient (bool): flag on whether or not to reorient adsorbate
            along the miller index
        find_args (dict): dictionary of arguments to be passed to the
            call to self.find_adsorption_sites, e.g. {"distance":2.0}
    """

    matcher = StructureMatcher()

    # Get adsorption on top
    adsgen_top = AdsorbateSiteFinder(slab,
                                     selective_dynamics=selective_dynamics,
                                     height=height,
                                     mi_vec=mi_vec,
                                     top_surface=True)
    structs = adsgen_top.generate_adsorption_structures(molecule,
                                                        repeat=repeat,
                                                        min_lw=min_lw,
                                                        reorient=reorient,
                                                        find_args=find_args)
    adslabs = [g[0] for g in matcher.group_structures(structs)]
    # Get adsorption on bottom
    adsgen_bottom = AdsorbateSiteFinder(slab,
                                        selective_dynamics=selective_dynamics,
                                        height=height,
                                        mi_vec=mi_vec,
                                        top_surface=False)
    structs = adsgen_bottom.generate_adsorption_structures(molecule,
                                                           repeat=repeat,
                                                           min_lw=min_lw,
                                                           reorient=reorient,
                                                           find_args=find_args)
    adslabs.extend([g[0] for g in matcher.group_structures(structs)])

    # Group symmetrically similar slabs
    adsorbed_slabs = []
    for group in matcher.group_structures(adslabs):
        # Further group each group by which surface adsorbed
        top_ads, bottom_ads = [], []
        for s in group:
            sites = sorted(s, key=lambda site: site.frac_coords[2])
            if sites[0].surface_properties == "adsorbate":
                bottom_ads.append(s)
            else:
                top_ads.append(s)
        if not top_ads or not bottom_ads:
            warnings.warn("There are not enough sites at the bottom or "
                          "top to generate a symmetric adsorbed slab")
            continue

        # Combine the adsorbates of both top and bottom slabs
        # into one slab with one adsorbate on each side
        coords = list(top_ads[0].frac_coords)
        species = top_ads[0].species
        lattice = top_ads[0].lattice
        coords.extend([
            site.frac_coords for site in bottom_ads[0]
            if site.surface_properties == "adsorbate"
        ])
        species.extend([
            site.specie for site in bottom_ads[0]
            if site.surface_properties == "adsorbate"
        ])

        slab = Slab(lattice, species, coords, slab.miller_index,
                    slab.oriented_unit_cell, slab.shift, slab.scale_factor)
        adsorbed_slabs.append(slab)

    return adsorbed_slabs
Ejemplo n.º 19
0
 def test_as_from_dict(self):
     d = self.zno55.as_dict()
     obj = Slab.from_dict(d)
     self.assertEqual(obj.miller_index, (1, 0, 0))
Ejemplo n.º 20
0
with open(orgdir + 'structure_collection_bulk.json') as f:
    st_bulk_json = json.load(f)
    f.close()
bulkkeys = list(st_bulk_json.keys())

surface_sites_dict = {}
for matkey in st_json.keys():
    tmp_st = st_json[matkey]
    st = Structure.from_dict(tmp_st['st_after'])
    bulkkey = ext_bulk_soap(matkey, bulkkeys)
    st_bulk = Structure.from_dict(st_bulk_json[bulkkey])

    slab = Slab(lattice=st.lattice,
                species=st.species,
                coords=st.frac_coords,
                miller_index=[1, 1, 1],
                oriented_unit_cell=st_bulk,
                shift=0,
                scale_factor=1,
                reorient_lattice=False)

    print(slab.is_symmetric(), slab.have_equivalent_surfaces())

    surface_sites = []
    surface_sites_prop = []
    for tol in [0.0, 0.25, 0.5]:
        tmp_surface_sites = get_surface_sites(slab, tol=tol)
        surface_sites_prop.append(slab.site_properties['is_surf_site'])
    surface_sites_prop = np.asarray(surface_sites_prop)
    surface_sites_prop = np.any(surface_sites_prop, axis=0)
    surface_sites = np.arange(0, slab.num_sites, 1)[surface_sites_prop]
    surface_sites = [
Ejemplo n.º 21
0
 def __init__(self,
              strt,
              hkl=[1, 1, 1],
              min_thick=10,
              min_vac=10,
              supercell=[1, 1, 1],
              name=None,
              adsorb_on_species=None,
              adatom_on_lig=None,
              ligand=None,
              displacement=1.0,
              surface_coverage=None,
              scell_nmax=10,
              coverage_tol=0.25,
              solvent=None,
              start_from_slab=False,
              validate_proximity=False,
              to_unit_cell=False,
              coords_are_cartesian=False,
              primitive=True,
              from_ase=False,
              lll_reduce=False,
              center_slab=True,
              max_normal_search=None,
              force_normalize=False,
              x_shift=0,
              y_shift=0,
              rot=[0, 0, 0]):
     self.from_ase = from_ase
     vac_extension = 0
     if ligand is not None:
         vac_extension = ligand.max_dist
     if isinstance(strt, Structure) and not isinstance(strt, Slab):
         self.min_vac = min_vac + vac_extension
         if self.from_ase:
             strt = get_ase_slab(strt,
                                 hkl=hkl,
                                 min_thick=min_thick,
                                 min_vac=min_vac + vac_extension)
         else:
             slab = SlabGenerator(strt,
                                  hkl,
                                  min_thick,
                                  min_vac + vac_extension,
                                  center_slab=center_slab,
                                  lll_reduce=lll_reduce,
                                  max_normal_search=max_normal_search,
                                  primitive=primitive).get_slab()
             if force_normalize:
                 strt = slab.get_orthogonal_c_slab()
             else:
                 strt = slab
         strt.make_supercell(supercell)
     else:
         self.min_vac = min_vac
     Slab.__init__(self,
                   strt.lattice,
                   strt.species_and_occu,
                   strt.frac_coords,
                   miller_index=strt.miller_index,
                   oriented_unit_cell=strt.oriented_unit_cell,
                   shift=strt.shift,
                   scale_factor=strt.scale_factor,
                   validate_proximity=validate_proximity,
                   to_unit_cell=to_unit_cell,
                   coords_are_cartesian=coords_are_cartesian,
                   site_properties=strt.site_properties,
                   energy=strt.energy)
     self.strt = strt
     self.name = name
     self.hkl = hkl
     self.min_thick = min_thick
     self.supercell = supercell
     self.ligand = ligand
     self.slab = strt
     self.displacement = displacement
     self.solvent = solvent
     self.surface_coverage = surface_coverage
     self.adsorb_on_species = adsorb_on_species
     self.adatom_on_lig = adatom_on_lig
     self.scell_nmax = scell_nmax
     self.coverage_tol = coverage_tol
     self.x_shift = x_shift
     self.y_shift = y_shift
     self.rot = rot
Ejemplo n.º 22
0
 def set_slab(self):
     """ set the slab on to which the ligand is adsorbed"""
     self.slab = Slab.from_dict(super(Interface, self).as_dict())
Ejemplo n.º 23
0
 def set_slab(self):
     """ set the slab on to which the ligand is adsorbed"""
     self.slab = Slab.from_dict(super(Interface, self).as_dict())
Ejemplo n.º 24
0
 def test_as_from_dict(self):
     d = self.zno55.as_dict()
     obj = Slab.from_dict(d)
     self.assertEqual(obj.miller_index, (1, 0, 0))
Ejemplo n.º 25
0
    def from_slabs(
        cls,
        substrate_slab: Slab,
        film_slab: Slab,
        in_plane_offset: Tuple[float, float] = (0, 0),
        gap: float = 1.6,
        vacuum_over_film: float = 0.0,
        interface_properties: Optional[Dict] = None,
        center_slab: bool = True,
    ) -> "Interface":
        """
        Makes an interface structure by merging a substrate and film slabs
        The film a- and b-vectors will be forced to be the substrate slab's
        a- and b-vectors.

        For now, it's suggested to use a factory method that will ensure the
        appropriate interface structure is already met.

        Args:
            sub_slab: slab for the substrate
            film_slab: slab for the film
            in_plane_offset: fractional shift in plane
                for the film with respect to the substrate
            gap: gap between substrate and film in Angstroms
            vacuum_over_film: vacuum space above the film in Angstroms
            structure_properties: dictionary of misc properties for this structure
            center_slab: center the slab
        """
        interface_properties = interface_properties or {}

        # Ensure c-axis is orthogonal to a/b plane
        if isinstance(substrate_slab, Slab):
            substrate_slab = substrate_slab.get_orthogonal_c_slab()
        if isinstance(film_slab, Slab):
            film_slab = film_slab.get_orthogonal_c_slab()
        assert np.allclose(film_slab.lattice.alpha, 90, 0.1)
        assert np.allclose(film_slab.lattice.beta, 90, 0.1)
        assert np.allclose(substrate_slab.lattice.alpha, 90, 0.1)
        assert np.allclose(substrate_slab.lattice.beta, 90, 0.1)

        # Ensure sub is right-handed
        # IE sub has surface facing "up"
        sub_vecs = substrate_slab.lattice.matrix.copy()
        if np.dot(np.cross(*sub_vecs[:2]), sub_vecs[2]) < 0:
            sub_vecs[2] *= -1.0
            substrate_slab.lattice = Lattice(sub_vecs)

        # Find the limits of C-coords
        sub_coords = substrate_slab.frac_coords
        film_coords = film_slab.frac_coords
        sub_min_c = np.min(sub_coords[:, 2]) * substrate_slab.lattice.c
        sub_max_c = np.max(sub_coords[:, 2]) * substrate_slab.lattice.c
        film_min_c = np.min(film_coords[:, 2]) * film_slab.lattice.c
        film_max_c = np.max(film_coords[:, 2]) * film_slab.lattice.c
        min_height = np.abs(film_max_c - film_min_c) + np.abs(sub_max_c -
                                                              sub_min_c)

        # construct new lattice
        abc = substrate_slab.lattice.abc[:2] + (min_height + gap +
                                                vacuum_over_film, )
        angles = substrate_slab.lattice.angles
        lattice = Lattice.from_parameters(*abc, *angles)

        # Get the species
        species = substrate_slab.species + film_slab.species

        # Get the coords
        # Shift substrate to bottom in new lattice
        sub_coords = np.subtract(sub_coords, [0, 0, np.min(sub_coords[:, 2])])
        sub_coords[:, 2] *= substrate_slab.lattice.c / lattice.c

        # Flip the film over
        film_coords[:, 2] *= -1.0
        film_coords[:, 2] *= film_slab.lattice.c / lattice.c

        # Shift the film coords to right over the substrate + gap
        film_coords = np.subtract(film_coords,
                                  [0, 0, np.min(film_coords[:, 2])])
        film_coords = np.add(
            film_coords, [0, 0, gap / lattice.c + np.max(sub_coords[:, 2])])

        # Build coords
        coords = np.concatenate([sub_coords, film_coords])

        # Shift coords to center
        if center_slab:
            coords = np.add(coords, [0, 0, 0.5 - np.average(coords[:, 2])])

        # Only merge site properties in both slabs
        site_properties = {}
        site_props_in_both = set(substrate_slab.site_properties.keys()) & set(
            film_slab.site_properties.keys())

        for key in site_props_in_both:
            site_properties[key] = [
                *substrate_slab.site_properties[key],
                *film_slab.site_properties[key],
            ]

        site_properties["interface_label"] = ["substrate"] * len(
            substrate_slab) + ["film"] * len(film_slab)

        iface = cls(
            lattice=lattice,
            species=species,
            coords=coords,
            to_unit_cell=False,
            coords_are_cartesian=False,
            site_properties=site_properties,
            validate_proximity=False,
            in_plane_offset=in_plane_offset,
            gap=gap,
            vacuum_over_film=vacuum_over_film,
            interface_properties=interface_properties,
        )

        iface.sort()
        return iface