Пример #1
0
    def create_slab(self, vacuum=12, thickness=10):
        """
        set the vacuum spacing, slab thickness and call sd_flags
        for top 2 layers

        returns the poscar corresponding to the modified structure
        """
        strt_structure = self.input_structure.copy()
        if self.from_ase:
            slab_struct = get_ase_slab(strt_structure,
                                       hkl=self.system['hkl'],
                                       min_thick=thickness,
                                       min_vac=vacuum)
        else:
            slab_struct = SlabGenerator(initial_structure=strt_structure,
                                        miller_index=self.system['hkl'],
                                        min_slab_size=thickness,
                                        min_vacuum_size=vacuum,
                                        lll_reduce=False,
                                        center_slab=True,
                                        primitive=False).get_slab()
        slab_struct.sort()
        sd = self.set_sd_flags(slab_struct)
        comment = 'VAC' + str(vacuum) + 'THICK' + str(thickness)
        return Poscar(slab_struct, comment=comment, selective_dynamics=sd)
Пример #2
0
def create_slap(initial_structure,
                miller_index,
                min_slab_size,
                min_vacuum_size=0,
                lll_reduce=False,
                center_slab=False,
                primitive=False,
                max_normal_search=1,
                reorient_lattice=True):
    """
    wraps the pymatgen slab generator
    """
    # minimum slab size is in Angstroem!!!
    pymat_struc = initial_structure.get_pymatgen_structure()
    slabg = SlabGenerator(pymat_struc,
                          miller_index,
                          min_slab_size,
                          min_vacuum_size,
                          lll_reduce=lll_reduce,
                          center_slab=center_slab,
                          primitive=primitive,
                          max_normal_search=max_normal_search)
    slab = slabg.get_slab()
    #slab2 = slab.get_orthogonal_c_slab()
    film_struc = StructureData(pymatgen_structure=slab)
    film_struc.pbc = (True, True, False)

    # TODO: sort atoms after z-coordinate value,
    # TODO: Move all atoms that the middle atom is at [x,y,0]
    # film_struc2 = move_atoms_incell(film_struc, [0,0, z_of_middle atom])

    return film_struc
Пример #3
0
def get_dimensionality_gorai(structure,
                             max_hkl=2,
                             el_radius_updates=None,
                             min_slab_size=5,
                             min_vacuum_size=5,
                             standardize=True,
                             bonds=None):
    """
    This method returns whether a structure is 3D, 2D (layered), or 1D (linear
    chains or molecules) according to the algorithm published in Gorai, P.,
    Toberer, E. & Stevanovic, V. Computational Identification of Promising
    Thermoelectric Materials Among Known Quasi-2D Binary Compounds. J. Mater.
    Chem. A 2, 4136 (2016).

    Note that a 1D structure detection might indicate problems in the bonding
    algorithm, particularly for ionic crystals (e.g., NaCl)

    Users can change the behavior of bonds detection by passing either
    el_radius_updates to update atomic radii for auto-detection of max bond
    distances, or bonds to explicitly specify max bond distances for atom pairs.
    Note that if you pass both, el_radius_updates are ignored.

    Args:
        structure: (Structure) structure to analyze dimensionality for
        max_hkl: (int) max index of planes to look for layers
        el_radius_updates: (dict) symbol->float to update atomic radii
        min_slab_size: (float) internal surface construction parameter
        min_vacuum_size: (float) internal surface construction parameter
        standardize (bool): whether to standardize the structure before
            analysis. Set to False only if you already have the structure in a
            convention where layers / chains will be along low <hkl> indexes.
        bonds ({(specie1, specie2): max_bond_dist}: bonds are
                specified as a dict of tuples: float of specie1, specie2
                and the max bonding distance. For example, PO4 groups may be
                defined as {("P", "O"): 3}.

    Returns: (int) the dimensionality of the structure - 1 (molecules/chains),
        2 (layered), or 3 (3D)

    """
    if standardize:
        structure = SpacegroupAnalyzer(structure). \
            get_conventional_standard_structure()

    if not bonds:
        bonds = get_max_bond_lengths(structure, el_radius_updates)

    num_surfaces = 0
    for h in range(max_hkl):
        for k in range(max_hkl):
            for l in range(max_hkl):
                if max([h, k, l]) > 0 and num_surfaces < 2:
                    sg = SlabGenerator(structure, (h, k, l),
                                       min_slab_size=min_slab_size,
                                       min_vacuum_size=min_vacuum_size)
                    slabs = sg.get_slabs(bonds)
                    for _ in slabs:
                        num_surfaces += 1

    return 3 - min(num_surfaces, 2)
Пример #4
0
    def test_make_confs_0(self):
        if not os.path.exists(os.path.join(self.equi_path, 'CONTCAR')):
            with self.assertRaises(RuntimeError):
                self.surface.make_confs(self.target_path, self.equi_path)
        shutil.copy(os.path.join(self.source_path, 'mp-141.vasp'),
                    os.path.join(self.equi_path, 'CONTCAR'))
        task_list = self.surface.make_confs(self.target_path, self.equi_path)
        self.assertEqual(len(task_list), 7)
        dfm_dirs = glob.glob(os.path.join(self.target_path, 'task.*'))

        incar0 = Incar.from_file(os.path.join('vasp_input', 'INCAR.rlx'))
        incar0['ISIF'] = 4

        self.assertEqual(
            os.path.realpath(os.path.join(self.equi_path, 'CONTCAR')),
            os.path.realpath(os.path.join(self.target_path, 'POSCAR')))
        ref_st = Structure.from_file(os.path.join(self.target_path, 'POSCAR'))
        dfm_dirs.sort()
        for ii in dfm_dirs:
            st_file = os.path.join(ii, 'POSCAR')
            self.assertTrue(os.path.isfile(st_file))
            st0 = Structure.from_file(st_file)
            st1_file = os.path.join(ii, 'POSCAR.tmp')
            self.assertTrue(os.path.isfile(st1_file))
            st1 = Structure.from_file(st1_file)
            miller_json_file = os.path.join(ii, 'miller.json')
            self.assertTrue(os.path.isfile(miller_json_file))
            miller_json = loadfn(miller_json_file)
            sl = SlabGenerator(ref_st, miller_json,
                               self.prop_param[0]["min_slab_size"],
                               self.prop_param[0]["min_vacuum_size"])
            slb = sl.get_slab()
            st2 = Structure(slb.lattice, slb.species, slb.frac_coords)
            self.assertEqual(len(st1), len(st2))
Пример #5
0
 def apply_transformation(self, structure):
     sg = SlabGenerator(structure, self.miller_index, self.min_slab_size,
                        self.min_vacuum_size, self.lll_reduce, 
                        self.center_slab, self.primitive,
                        self.max_normal_search)
     slab = sg.get_slab(self.shift, self.tol)
     return slab
Пример #6
0
    def generate_slabs(self, film_millers, substrate_millers):
        """
        Generates the film/substrate slab combinations for a set of given
        miller indicies

        Args:
            film_millers(array): all miller indices to generate slabs for
                film
            substrate_millers(array): all miller indicies to generate slabs
                for substrate
        """

        for f in film_millers:
            film_slab = SlabGenerator(self.film, f, 20, 15,
                                      primitive=False).get_slab()
            film_vectors = reduce_vectors(film_slab.lattice.matrix[0],
                                          film_slab.lattice.matrix[1])
            film_area = vec_area(*film_vectors)

            for s in substrate_millers:
                substrate_slab = SlabGenerator(self.substrate,
                                               s,
                                               20,
                                               15,
                                               primitive=False).get_slab()
                substrate_vectors = reduce_vectors(
                    substrate_slab.lattice.matrix[0],
                    substrate_slab.lattice.matrix[1])
                substrate_area = vec_area(*substrate_vectors)

                yield [
                    film_area, substrate_area, film_vectors, substrate_vectors,
                    f, s
                ]
Пример #7
0
    def _create_surface(self):
        '''
        This method will create the surface structure to relax

        Returns:
            surface_atoms_constrained   `ase.Atoms` object of the surface to
                                        submit to Fireworks for relaxation
        '''
        # Get the bulk and convert to `pymatgen.Structure` object
        with open(self.input().path, 'rb') as file_handle:
            bulk_doc = pickle.load(file_handle)
        bulk_atoms = make_atoms_from_doc(bulk_doc)
        bulk_structure = AseAtomsAdaptor.get_structure(bulk_atoms)

        # Use pymatgen to turn the bulk into a surface
        sga = SpacegroupAnalyzer(bulk_structure, symprec=0.1)
        bulk_structure = sga.get_conventional_standard_structure()
        gen = SlabGenerator(initial_structure=bulk_structure,
                            miller_index=self.miller_indices,
                            min_slab_size=self.min_height,
                            **self.slab_generator_settings)
        surface_structure = gen.get_slab(self.shift,
                                         tol=self.get_slab_settings['tol'])

        # Convert the surface back to an `ase.Atoms` object and constrain
        # subsurface atoms
        surface_atoms = AseAtomsAdaptor.get_atoms(surface_structure)
        surface_atoms_constrained = self.__constrain_surface(surface_atoms)
        return surface_atoms_constrained
Пример #8
0
    def generate_slabs(self, film_millers, substrate_millers):
        """
        Generates the film/substrate slab combinations for a set of given
        miller indicies

        Args:
            film_millers(array): all miller indices to generate slabs for
                film
            substrate_millers(array): all miller indicies to generate slabs
                for substrate
        """

        for f in film_millers:
            film_slab = SlabGenerator(self.film, f, 20, 15,
                                      primitive=False).get_slab()
            film_vectors = reduce_vectors(film_slab.lattice_vectors()[0],
                                               film_slab.lattice_vectors()[1])
            film_area = vec_area(*film_vectors)

            for s in substrate_millers:
                substrate_slab = SlabGenerator(self.substrate, s, 20, 15,
                                               primitive=False).get_slab()
                substrate_vectors = reduce_vectors(
                    substrate_slab.lattice_vectors()[0],
                    substrate_slab.lattice_vectors()[1])
                substrate_area = vec_area(*substrate_vectors)

                yield [film_area, substrate_area, film_vectors,
                       substrate_vectors, f, s]
Пример #9
0
    def test_nonstoichiometric_symmetrized_slab(self):
        # For the (111) halite slab, sometimes a nonstoichiometric
        # system is preferred over the stoichiometric Tasker 2.
        slabgen = SlabGenerator(self.MgO, (1, 1, 1),
                                10,
                                10,
                                max_normal_search=1)
        slabs = slabgen.get_slabs(symmetrize=True)

        # We should end up with two terminations, one with
        # an Mg rich surface and another O rich surface
        self.assertEqual(len(slabs), 2)
        for slab in slabs:
            self.assertTrue(slab.is_symmetric())

        # For a low symmetry primitive_elemental system such as
        # R-3m, there should be some nonsymmetric slabs
        # without using nonstoichiometric_symmetrized_slab
        slabs = generate_all_slabs(self.Dy,
                                   1,
                                   30,
                                   30,
                                   center_slab=True,
                                   symmetrize=True)
        for s in slabs:
            self.assertTrue(s.is_symmetric())
            self.assertGreater(len(s), len(self.Dy))
Пример #10
0
    def generate_surface_vectors(self, film_millers, substrate_millers):
        """
        Generates the film/substrate slab combinations for a set of given
        miller indicies

        Args:
            film_millers(array): all miller indices to generate slabs for
                film
            substrate_millers(array): all miller indicies to generate slabs
                for substrate
        """
        vector_sets = []

        for f in film_millers:
            film_slab = SlabGenerator(self.film, f, 20, 15,
                                      primitive=False).get_slab()
            film_vectors = reduce_vectors(film_slab.lattice.matrix[0],
                                          film_slab.lattice.matrix[1])

            for s in substrate_millers:
                substrate_slab = SlabGenerator(self.substrate, s, 20, 15,
                                               primitive=False).get_slab()
                substrate_vectors = reduce_vectors(
                    substrate_slab.lattice.matrix[0],
                    substrate_slab.lattice.matrix[1])

                vector_sets.append((film_vectors, substrate_vectors, f, s))

        return vector_sets
Пример #11
0
    def __calculate_unit_slab(self):
        '''
        Calculates the height of the smallest unit slab from a given bulk and
        Miller cut

        Saved attributes:
            unit                A `pymatgen.Structure` instance for the unit
                                slab
            unit_slab_height    The height of the unit slab in Angstroms
        '''
        # Luigi will probably call this method multiple times. We only need to
        # do it once though.
        if not hasattr(self, 'unit_slab_height'):

            # Delete some slab generator settings that we don't care about for a
            # unit slab
            slab_generator_settings = utils.unfreeze_dict(
                self.slab_generator_settings)
            del slab_generator_settings['min_vacuum_size']
            del slab_generator_settings['min_slab_size']

            # Instantiate a pymatgen `SlabGenerator`
            bulk_structure = AseAtomsAdaptor.get_structure(self.bulk_atoms)
            sga = SpacegroupAnalyzer(bulk_structure, symprec=0.1)
            bulk_structure = sga.get_conventional_standard_structure()
            gen = SlabGenerator(initial_structure=bulk_structure,
                                miller_index=self.miller_indices,
                                min_vacuum_size=0.,
                                min_slab_size=1.,
                                **slab_generator_settings)

            # Generate the unit slab and find its height
            self.unit_slab = gen.get_slab(self.shift,
                                          tol=self.get_slab_settings['tol'])
            self.unit_slab_height = gen._proj_height
Пример #12
0
 def get_tasker2_slabs(self):
     # The uneven distribution of ions on the (111) facets of Halite
     # type slabs are typical examples of Tasker 3 structures. We
     # will test this algo to generate a Tasker 2 structure instead
     lattice = Lattice.cubic(3.010)
     frac_coords = [[0.00000, 0.00000,
                     0.00000], [0.00000, 0.50000, 0.50000],
                    [0.50000, 0.00000,
                     0.50000], [0.50000, 0.50000, 0.00000],
                    [0.50000, 0.00000,
                     0.00000], [0.50000, 0.50000, 0.50000],
                    [0.00000, 0.00000, 0.50000],
                    [0.00000, 0.50000, 0.00000]]
     species = ['Mg', 'Mg', 'Mg', 'Mg', 'O', 'O', 'O', 'O']
     MgO = Structure(lattice, species, frac_coords)
     MgO.add_oxidation_state_by_element({"Mg": 2, "O": -6})
     slabgen = SlabGenerator(MgO, (1, 1, 1), 10, 10, max_normal_search=1)
     # We generate the Tasker 3 structure first
     slab = slabgen.get_slabs()[0]
     self.assertFalse(slab.is_symmetric())
     self.assertTrue(slab.is_polar())
     # Now to generate the Tasker 2 structure, we must
     # ensure there are enough ions on top to move around
     slab.make_supercell([2, 1, 1])
     slabs = slab.get_tasker2_slabs()
     # Check if our Tasker 2 slab is nonpolar and symmetric
     for slab in slabs:
         self.assertTrue(slab.is_symmetric())
         self.assertFalse(slab.is_polar())
Пример #13
0
def make_super_cell_pymatgen (jdata) :
    make_unit_cell(jdata)

    out_dir = jdata['out_dir']
    path_uc = os.path.join(out_dir, global_dirname_02)
    from_path = path_uc
    from_file = os.path.join(from_path, 'POSCAR.unit')
    ss = Structure.from_file(from_file)

    all_millers = jdata['millers']
    path_sc = os.path.join(out_dir, global_dirname_02)
    z_min = jdata['z_min']
    super_cell = jdata['super_cell']

    cwd = os.getcwd()    
    path_work = (path_sc)    
    path_work = os.path.abspath(path_work)
    pcpy_cmd = os.path.join(cwd, 'tools')
    pcpy_cmd = os.path.join(pcpy_cmd, 'poscar_copy.py')
    os.chdir(path_work)
    for miller in all_millers:
        miller_str=""
        for ii in miller :
            miller_str += str(ii)        
        path_cur_surf = create_path('surf-'+miller_str)
        os.chdir(path_cur_surf)
        slabgen = SlabGenerator(ss, miller, z_min, 1e-3)
        all_slabs = slabgen.get_slabs() 
        print("Miller %s: The slab has %s termination, use the first one" %(str(miller), len(all_slabs)))
        all_slabs[0].to('POSCAR', 'POSCAR')
        if super_cell[0] > 1 or super_cell[1] > 1 :
            sp.check_call(pcpy_cmd + ' -n %d %d %d POSCAR POSCAR ' % (super_cell[0], super_cell[1], 1), 
                          shell = True)
        os.chdir(path_work)
    os.chdir(cwd)        
Пример #14
0
    def test_normal_search(self):
        fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"],
                                        [[0, 0, 0]])
        for miller in [(1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)]:
            gen = SlabGenerator(fcc, miller, 10, 10)
            gen_normal = SlabGenerator(fcc, miller, 10, 10,
                                       max_normal_search=max(miller))
            slab = gen_normal.get_slab()
            self.assertAlmostEqual(slab.lattice.alpha, 90)
            self.assertAlmostEqual(slab.lattice.beta, 90)
            self.assertGreaterEqual(len(gen_normal.oriented_unit_cell),
                                    len(gen.oriented_unit_cell))

        graphite = self.get_structure("Graphite")
        for miller in [(1, 0, 0), (1, 1, 0), (0, 0, 1), (2, 1, 1)]:
            gen = SlabGenerator(graphite, miller, 10, 10)
            gen_normal = SlabGenerator(graphite, miller, 10, 10,
                                       max_normal_search=max(miller))
            self.assertGreaterEqual(len(gen_normal.oriented_unit_cell),
                                    len(gen.oriented_unit_cell))

        sc = Structure(Lattice.hexagonal(3.32, 5.15), ["Sc", "Sc"],
                       [[1/3, 2/3, 0.25], [2/3, 1/3, 0.75]])
        gen = SlabGenerator(sc, (1, 1, 1), 10, 10, max_normal_search=1)
        self.assertAlmostEqual(gen.oriented_unit_cell.lattice.angles[1], 90)
Пример #15
0
    def test_surface_sites_and_symmetry(self):
        # test if surfaces are equivalent by using
        # Laue symmetry and surface site equivalence

        for bool in [True, False]:
            # We will also set the slab to be centered and
            # off centered in order to test the center of mass
            slabgen = SlabGenerator(self.agfcc, (3, 1, 0), 10, 10,
                                    center_slab=bool)
            slab = slabgen.get_slabs()[0]
            surf_sites_dict = slab.get_surface_sites()
            self.assertEqual(len(surf_sites_dict["top"]),
                             len(surf_sites_dict["bottom"]))
            total_surf_sites = sum([len(surf_sites_dict[key])
                                    for key in surf_sites_dict.keys()])
            self.assertTrue(slab.is_symmetric())
            self.assertEqual(total_surf_sites / 2, 4)
            self.assertTrue(slab.have_equivalent_surfaces())

            # Test if the ratio of surface sites per area is
            # constant, ie are the surface energies the same
            r1 = total_surf_sites / (2 * slab.surface_area)
            slabgen = SlabGenerator(self.agfcc, (3, 1, 0), 10, 10,
                                    primitive=False)
            slab = slabgen.get_slabs()[0]
            surf_sites_dict = slab.get_surface_sites()
            total_surf_sites = sum([len(surf_sites_dict[key])
                                    for key in surf_sites_dict.keys()])
            r2 = total_surf_sites / (2 * slab.surface_area)
            self.assertArrayEqual(r1, r2)
Пример #16
0
 def apply_transformation(self, structure):
     sg = SlabGenerator(structure, self.miller_index, self.min_slab_size,
                        self.min_vacuum_size, self.lll_reduce,
                        self.center_slab, self.primitive,
                        self.max_normal_search)
     slab = sg.get_slab(self.shift, self.tol)
     return slab
Пример #17
0
 def test_get_orthogonal_c_slab(self):
     TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False)
     trclnc_TeI = SlabGenerator(TeI, (0, 0, 1), 10, 10)
     TeI_slabs = trclnc_TeI.get_slabs()
     slab = TeI_slabs[0]
     norm_slab = slab.get_orthogonal_c_slab()
     self.assertAlmostEqual(norm_slab.lattice.angles[0], 90)
     self.assertAlmostEqual(norm_slab.lattice.angles[1], 90)
Пример #18
0
def create_surface2(st,
                    miller_index,
                    min_slab_size=10,
                    min_vacuum_size=10,
                    surface_i=0,
                    oxidation=None,
                    suf='',
                    primitive=None,
                    symmetrize=False):
    """
    INPUT:
        st (Structure) - Initial input structure. Note that to
                ensure that the miller indices correspond to usual
                crystallographic definitions, you should supply a conventional
                unit cell structure.

        miller_index ([h, k, l]): Miller index of plane parallel to
                        surface. Note that this is referenced to the input structure. If
                        you need this to be based on the conventional cell,
                        you should supply the conventional structure.


        oxidation (dic) - dictionary of effective oxidation states, e. g. {'Y':'Y3+', 'Ba':'Ba2+', 'Co':'Co2.25+', 'O':'O2-'}
                          allows to calculate dipole moment

        surface_i (int) - choose particular surface 

        min_slab_size (float) - minimum slab size

        min_vacuum_size (float) - vacuum thicknes in A

    """

    from pymatgen.core.surface import SlabGenerator
    from pymatgen.io.vasp.inputs import Poscar
    from geo import replic

    pm = st.convert2pymatgen(oxidation=oxidation)
    # pm = st.convert2pymatgen()

    slabgen = SlabGenerator(pm,
                            miller_index,
                            min_slab_size,
                            min_vacuum_size,
                            primitive=primitive)
    # print(slabgen.oriented_unit_cell)
    slabs = slabgen.get_slabs(symmetrize=symmetrize)

    printlog(
        len(slabs),
        'surfaces were generated, choose required surface using *surface_i* argument\nWriting POSCARs to xyz',
        imp='y')

    for i, slab in enumerate(slabs):
        pos = Poscar(slab)
        pos.write_file('xyz/POSCAR_suf' + str(i) + str(suf))

    return slabs
Пример #19
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
Пример #20
0
 def test_dipole_and_is_polar(self):
     self.assertArrayAlmostEqual(self.zno55.dipole, [0, 0, 0])
     self.assertFalse(self.zno55.is_polar())
     cscl = self.get_structure("CsCl")
     cscl.add_oxidation_state_by_element({"Cs": 1, "Cl": -1})
     slab = SlabGenerator(cscl, [1, 0, 0], 5, 5,
                          lll_reduce=False, center_slab=False).get_slab()
     self.assertArrayAlmostEqual(slab.dipole, [-4.209, 0, 0])
     self.assertTrue(slab.is_polar())
def enumerate_surfaces(bulk_atoms, mpid, max_miller=MAX_MILLER):
    '''
    Enumerate all the symmetrically distinct surfaces of a bulk structure. It
    will not enumerate surfaces with Miller indices above the `max_miller`
    argument. Note that we also look at the bottoms of slabs if they are
    distinct from the top. If they are distinct, we flip the slab so the bottom
    is pointing upwards.

    Args:
        bulk_atoms  `ase.Atoms` object of the bulk you want to enumerate
                    surfaces from.
        mpid        String indicating the the Materials Project ID number of
                    the bulk that was selected.
        max_miller  An integer indicating the maximum Miller index of the surfaces
                    you are willing to enumerate. Increasing this argument will
                    increase the number of surfaces, but the surfaces will
                    generally become larger.
    Returns:
        all_slabs_info  A list of 4-tuples containing:  `pymatgen.Structure`
                        objects, 3-tuples for the Miller indices, floats for
                        the shifts, and Booleans for "top".
    '''
    all_slabs = CACHE.get(mpid)
    if all_slabs is None:

        bulk_struct = standardize_bulk(bulk_atoms)

        all_slabs_info = []
        for millers in get_symmetrically_distinct_miller_indices(
                bulk_struct, MAX_MILLER):
            slab_gen = SlabGenerator(initial_structure=bulk_struct,
                                     miller_index=millers,
                                     min_slab_size=7.,
                                     min_vacuum_size=20.,
                                     lll_reduce=False,
                                     center_slab=True,
                                     primitive=True,
                                     max_normal_search=1)
            slabs = slab_gen.get_slabs(tol=0.3,
                                       bonds=None,
                                       max_broken_bonds=0,
                                       symmetrize=False)

            # If the bottoms of the slabs are different than the tops, then we want
            # to consider them, too
            flipped_slabs = [
                flip_struct(slab) for slab in slabs
                if is_structure_invertible(slab) is False
            ]

            # Concatenate all the results together
            slabs_info = [(slab, millers, slab.shift, True) for slab in slabs]
            flipped_slabs_info = [(slab, millers, slab.shift, False)
                                  for slab in flipped_slabs]
            all_slabs_info.extend(slabs_info + flipped_slabs_info)
        CACHE.set(mpid, all_slabs_info)
    return all_slabs_info
Пример #22
0
 def test_get_orthogonal_c_slab(self):
     TeI = Structure.from_file(get_path("icsd_TeI.cif"),
                               primitive=False)
     trclnc_TeI = SlabGenerator(TeI, (0, 0, 1), 10, 10)
     TeI_slabs = trclnc_TeI.get_slabs()
     slab = TeI_slabs[0]
     norm_slab = slab.get_orthogonal_c_slab()
     self.assertAlmostEqual(norm_slab.lattice.angles[0], 90)
     self.assertAlmostEqual(norm_slab.lattice.angles[1], 90)
Пример #23
0
 def test_dipole_and_is_polar(self):
     self.assertArrayAlmostEqual(self.zno55.dipole, [0, 0, 0])
     self.assertFalse(self.zno55.is_polar())
     cscl = self.get_structure("CsCl")
     cscl.add_oxidation_state_by_element({"Cs": 1, "Cl": -1})
     slab = SlabGenerator(cscl, [1, 0, 0], 5, 5, reorient_lattice=False,
                          lll_reduce=False, center_slab=False).get_slab()
     self.assertArrayAlmostEqual(slab.dipole, [-4.209, 0, 0])
     self.assertTrue(slab.is_polar())
Пример #24
0
def generate_selected_slab(structs,fnames,miller_index,min_slab_size,min_vac_size):
    for struct,fname in zip(structs,fnames):
        slab=SlabGenerator(struct,miller_index,min_slab_size=min_slab_size,min_vacuum_size=min_vac_size,lll_reduce=True)
        slab_struct=slab.get_slab()
        slab_struct.sort()
        miller_str=[str(i) for i in miller_index]
    
        filename='_'.join(miller_str)+"_"+fname+'.vasp'
        slab_struct.to(filename=filename,fmt='POSCAR')
Пример #25
0
def get_dimensionality(structure, max_hkl=2, el_radius_updates=None,
                       min_slab_size=5, min_vacuum_size=5,
                       standardize=True, bonds=None):
    """
    This method returns whether a structure is 3D, 2D (layered), or 1D (linear 
    chains or molecules) according to the algorithm published in Gorai, P., 
    Toberer, E. & Stevanovic, V. Computational Identification of Promising 
    Thermoelectric Materials Among Known Quasi-2D Binary Compounds. J. Mater. 
    Chem. A 2, 4136 (2016).
    
    Note that a 1D structure detection might indicate problems in the bonding
    algorithm, particularly for ionic crystals (e.g., NaCl)
    
    Users can change the behavior of bonds detection by passing either
    el_radius_updates to update atomic radii for auto-detection of max bond 
    distances, or bonds to explicitly specify max bond distances for atom pairs.
    Note that if you pass both, el_radius_updates are ignored.
    
    Args:
        structure: (Structure) structure to analyze dimensionality for 
        max_hkl: (int) max index of planes to look for layers
        el_radius_updates: (dict) symbol->float to update atomic radii
        min_slab_size: (float) internal surface construction parameter
        min_vacuum_size: (float) internal surface construction parameter
        standardize (bool): whether to standardize the structure before 
            analysis. Set to False only if you already have the structure in a 
            convention where layers / chains will be along low <hkl> indexes.
        bonds ({(specie1, specie2): max_bond_dist}: bonds are
                specified as a dict of tuples: float of specie1, specie2
                and the max bonding distance. For example, PO4 groups may be
                defined as {("P", "O"): 3}.

    Returns: (int) the dimensionality of the structure - 1 (molecules/chains), 
        2 (layered), or 3 (3D)

    """
    if standardize:
        structure = SpacegroupAnalyzer(structure). \
            get_conventional_standard_structure()

    if not bonds:
        bonds = get_max_bond_lengths(structure, el_radius_updates)

    num_surfaces = 0
    for h in range(max_hkl):
        for k in range(max_hkl):
            for l in range(max_hkl):
                if max([h, k, l]) > 0 and num_surfaces < 2:
                    sg = SlabGenerator(structure, (h, k, l),
                                       min_slab_size=min_slab_size,
                                       min_vacuum_size=min_vacuum_size)
                    slabs = sg.get_slabs(bonds)
                    for _ in slabs:
                        num_surfaces += 1

    return 3 - min(num_surfaces, 2)
Пример #26
0
def pmg_surfer(mpid='', vacuum=15, mat=None, max_index=1, min_slab_size=15):
    if mat == None:
        with MPRester() as mp:
            mat = mp.get_structure_by_material_id(mpid)
        if mpid == '':
            print('Provide structure')

    sg_mat = SpacegroupAnalyzer(mat)
    mat_cvn = sg_mat.get_conventional_standard_structure()
    mat_cvn.sort()
    indices = get_symmetrically_distinct_miller_indices(mat_cvn, max_index)
    #ase_atoms = AseAtomsAdaptor().get_atoms(mat_cvn)

    structures = []
    pos = Poscar(mat_cvn)
    try:
        pos.comment = str('sbulk') + str('@') + str('vac') + str(vacuum) + str(
            '@') + str('size') + str(min_slab_size)
    except:
        pass
    structures.append(pos)
    mat_cvn.to(fmt='poscar',
               filename=str('POSCAR-') + str('cvn') + str('.vasp'))
    for i in indices:
        slab = SlabGenerator(initial_structure=mat_cvn,
                             miller_index=i,
                             min_slab_size=min_slab_size,
                             min_vacuum_size=vacuum,
                             lll_reduce=False,
                             center_slab=True,
                             primitive=False).get_slab()
        normal_slab = slab.get_orthogonal_c_slab()
        slab_pymatgen = Poscar(normal_slab).structure
        #ase_slab.center(vacuum=vacuum, axis=2)
        #slab_pymatgen = AseAtomsAdaptor().get_structure(ase_slab)
        xy_size = min_slab_size
        dim1 = int((float(xy_size) /
                    float(max(abs(slab_pymatgen.lattice.matrix[0]))))) + 1
        dim2 = int(
            float(xy_size) /
            float(max(abs(slab_pymatgen.lattice.matrix[1])))) + 1
        slab_pymatgen.make_supercell([dim1, dim2, 1])
        slab_pymatgen.sort()
        surf_name = '_'.join(map(str, i))
        pos = Poscar(slab_pymatgen)
        try:
            pos.comment = str("Surf-") + str(surf_name) + str('@') + str(
                'vac') + str(vacuum) + str('@') + str('size') + str(
                    min_slab_size)
        except:
            pass
        pos.write_file(filename=str('POSCAR-') + str("Surf-") +
                       str(surf_name) + str('.vasp'))
        structures.append(pos)

    return structures
def make_surface(file, facet=(1, 1, 1), verbose=True):
    # read in structure
    st = Structure.from_file(file)
    # generate slabs with the given facet
    slabgen = SlabGenerator(st, facet, 6, 16, center_slab=True)
    all_slabs = slabgen.get_slabs(symmetrize=True)
    if verbose:
        print("The slab has %s termination." % (len(all_slabs)))
    # save surfaces
    for i, slab in enumerate(all_slabs):
        slab.to('POSCAR', 'POSCAR_SURF_' + str(i).zfill(2))
Пример #28
0
    def test_from_slabs(self):
        si_struct = self.get_structure("Si")
        sio2_struct = self.get_structure("SiO2")
        si_conventional = SpacegroupAnalyzer(si_struct).get_conventional_standard_structure()
        sio2_conventional = SpacegroupAnalyzer(sio2_struct).get_conventional_standard_structure()

        si_slab = SlabGenerator(si_conventional, (1, 1, 1), 5, 10, reorient_lattice=True).get_slab()
        sio2_slab = SlabGenerator(sio2_conventional, (1, 0, 0), 5, 10, reorient_lattice=True).get_slab()

        interface = Interface.from_slabs(film_slab=si_slab, substrate_slab=sio2_slab)
        assert isinstance(interface, Interface)
Пример #29
0
 def test_normal_search(self):
     fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"],
                                     [[0, 0, 0]])
     for miller in [(1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)]:
         gen = SlabGenerator(fcc, miller, 10, 10)
         gen_normal = SlabGenerator(fcc, miller, 10, 10,
                                    max_normal_search=max(miller))
         slab = gen_normal.get_slab()
         self.assertAlmostEqual(slab.lattice.alpha, 90)
         self.assertAlmostEqual(slab.lattice.beta, 90)
         self.assertGreaterEqual(len(gen_normal.oriented_unit_cell),
                                 len(gen.oriented_unit_cell))
Пример #30
0
 def test_triclinic_TeI(self):
     # Test case for a triclinic structure of TeI. Only these three
     # Miller indices are used because it is easier to identify which
     # atoms should be in a surface together. The closeness of the sites
     # in other Miller indices can cause some ambiguity when choosing a
     # higher tolerance.
     numb_slabs = {(0, 0, 1): 5, (0, 1, 0): 3, (1, 0, 0): 7}
     TeI = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False)
     for k, v in numb_slabs.items():
         trclnc_TeI = SlabGenerator(TeI, k, 10, 10)
         TeI_slabs = trclnc_TeI.get_slabs()
         self.assertEqual(v, len(TeI_slabs))
Пример #31
0
 def test_triclinic_TeI(self):
     # Test case for a triclinic structure of TeI. Only these three
     # Miller indices are used because it is easier to identify which
     # atoms should be in a surface together. The closeness of the sites
     # in other Miller indices can cause some ambiguity when choosing a
     # higher tolerance.
     numb_slabs = {(0, 0, 1): 5, (0, 1, 0): 3, (1, 0, 0): 7}
     TeI = Structure.from_file(get_path("icsd_TeI.cif"),
                               primitive=False)
     for k, v in numb_slabs.items():
         trclnc_TeI = SlabGenerator(TeI, k, 10, 10)
         TeI_slabs = trclnc_TeI.get_slabs()
         self.assertEqual(v, len(TeI_slabs))
Пример #32
0
    def enumerate_surfaces(self, max_miller=MAX_MILLER):
        '''
        Enumerate all the symmetrically distinct surfaces of a bulk structure. It
        will not enumerate surfaces with Miller indices above the `max_miller`
        argument. Note that we also look at the bottoms of surfaces if they are
        distinct from the top. If they are distinct, we flip the surface so the bottom
        is pointing upwards.

        Args:
            bulk_atoms  `ase.Atoms` object of the bulk you want to enumerate
                        surfaces from.
            max_miller  An integer indicating the maximum Miller index of the surfaces
                        you are willing to enumerate. Increasing this argument will
                        increase the number of surfaces, but the surfaces will
                        generally become larger.
        Returns:
            all_slabs_info  A list of 4-tuples containing:  `pymatgen.Structure`
                            objects for surfaces we have enumerated, the Miller
                            indices, floats for the shifts, and Booleans for "top".
        '''
        bulk_struct = self.standardize_bulk(self.bulk_atoms)

        all_slabs_info = []
        for millers in get_symmetrically_distinct_miller_indices(bulk_struct, MAX_MILLER):
            slab_gen = SlabGenerator(initial_structure=bulk_struct,
                                     miller_index=millers,
                                     min_slab_size=7.,
                                     min_vacuum_size=20.,
                                     lll_reduce=False,
                                     center_slab=True,
                                     primitive=True,
                                     max_normal_search=1)
            slabs = slab_gen.get_slabs(tol=0.3,
                                       bonds=None,
                                       max_broken_bonds=0,
                                       symmetrize=False)

            # Additional filtering for the 2D materials' slabs
            if self.mpid in COVALENT_MATERIALS_MPIDS:
                slabs = [slab for slab in slabs if is_2D_slab_reasonsable(slab) is True]

            # If the bottoms of the slabs are different than the tops, then we want
            # to consider them, too
            if len(slabs) != 0:
                flipped_slabs_info = [(self.flip_struct(slab), millers, slab.shift, False)
                                      for slab in slabs if self.is_structure_invertible(slab) is False]

                # Concatenate all the results together
                slabs_info = [(slab, millers, slab.shift, True) for slab in slabs]
                all_slabs_info.extend(slabs_info + flipped_slabs_info)
        return all_slabs_info
Пример #33
0
    def setUp(self):

        if "PMG_VASP_PSP_DIR" not in os.environ:
            os.environ["PMG_VASP_PSP_DIR"] = test_dir
        s = PymatgenTest.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell

        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
        vis = MVLSlabSet(self.slab)

        self.d_bulk = vis_bulk.all_input
        self.d_slab = vis.all_input
Пример #34
0
    def nonstoichiometric_symmetrized_slab(self):
        # For the (111) halite slab, sometimes a nonstoichiometric
        # system is preferred over the stoichiometric Tasker 2.
        slabgen = SlabGenerator(self.MgO, (1, 1, 1),
                                10,
                                10,
                                max_normal_search=1)
        slabs = slabgen.get_slabs(symmetrize=True)

        # We should end up with two terminations, one with
        # an Mg rich surface and another O rich surface
        self.assertEqual(len(slabs), 2)
        for slab in slabs:
            self.assertTrue(slab.is_symmetric())
Пример #35
0
    def setUp(self):

        if "PMG_VASP_PSP_DIR" not in os.environ:
            os.environ["PMG_VASP_PSP_DIR"] = test_dir
        s = PymatgenTest.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell

        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
        vis = MVLSlabSet(self.slab)

        self.d_bulk = vis_bulk.all_input
        self.d_slab = vis.all_input
Пример #36
0
    def test_normal_search(self):
        fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"],
                                        [[0, 0, 0]])
        for miller in [(1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)]:
            gen = SlabGenerator(fcc, miller, 10, 10)
            gen_normal = SlabGenerator(fcc,
                                       miller,
                                       10,
                                       10,
                                       max_normal_search=max(miller))
            slab = gen_normal.get_slab()
            self.assertAlmostEqual(slab.lattice.alpha, 90)
            self.assertAlmostEqual(slab.lattice.beta, 90)
            self.assertGreaterEqual(len(gen_normal.oriented_unit_cell),
                                    len(gen.oriented_unit_cell))

        graphite = self.get_structure("Graphite")
        for miller in [(1, 0, 0), (1, 1, 0), (0, 0, 1), (2, 1, 1)]:
            gen = SlabGenerator(graphite, miller, 10, 10)
            gen_normal = SlabGenerator(graphite,
                                       miller,
                                       10,
                                       10,
                                       max_normal_search=max(miller))
            self.assertGreaterEqual(len(gen_normal.oriented_unit_cell),
                                    len(gen.oriented_unit_cell))

        sc = Structure(Lattice.hexagonal(3.32, 5.15), ["Sc", "Sc"],
                       [[1 / 3, 2 / 3, 0.25], [2 / 3, 1 / 3, 0.75]])
        gen = SlabGenerator(sc, (1, 1, 1), 10, 10, max_normal_search=1)
        self.assertAlmostEqual(gen.oriented_unit_cell.lattice.angles[1], 90)
Пример #37
0
    def setUp(self):
        s = self.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell

        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
        vis = MVLSlabSet(self.slab)
        vis_dipole = MVLSlabSet(self.slab, auto_dipole=True)

        self.d_bulk = vis_bulk.get_vasp_input()
        self.d_slab = vis.get_vasp_input()
        self.d_dipole = vis_dipole.get_vasp_input()
        self.vis = vis
        warnings.simplefilter("ignore")
Пример #38
0
    def setUp(self):

        if "VASP_PSP_DIR" not in os.environ:
            os.environ["VASP_PSP_DIR"] = test_dir
        s = PymatgenTest.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        vis_bulk = MVLSlabSet(bulk=True)
        vis = MVLSlabSet()
        vis_bulk_gpu = MVLSlabSet(bulk=True, gpu=True)

        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell
        self.d_bulk = vis_bulk.get_all_vasp_input(self.bulk)
        self.d_slab = vis.get_all_vasp_input(self.slab)
        self.d_bulk_gpu = vis_bulk_gpu.get_all_vasp_input(self.bulk)
Пример #39
0
 def generate_selected_slab(in_str):
     tmp_list = in_str.split('|')
     miller_index = [int(x) for x in tmp_list[0].strip().split()]
     min_slab_size = float(tmp_list[1])
     min_vac_size = float(tmp_list[2])
     slab = SlabGenerator(struct,
                          miller_index,
                          min_slab_size=min_slab_size,
                          min_vacuum_size=min_vac_size,
                          lll_reduce=True)
     slab_struct = slab.get_slab()
     slab_struct.sort()
     miller_str = [str(i) for i in miller_index]
     filename = '_'.join(miller_str) + '.vasp'
     slab_struct.to(filename=filename, fmt='POSCAR')
Пример #40
0
    def setUp(self):

        if "VASP_PSP_DIR" not in os.environ:
            os.environ["VASP_PSP_DIR"] = test_dir
        s = PymatgenTest.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        vis_bulk = MVLSlabSet(bulk=True)
        vis = MVLSlabSet()
        vis_bulk_gpu = MVLSlabSet(bulk=True, gpu=True)

        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell
        self.d_bulk = vis_bulk.get_all_vasp_input(self.bulk)
        self.d_slab = vis.get_all_vasp_input(self.slab)
        self.d_bulk_gpu = vis_bulk_gpu.get_all_vasp_input(self.bulk)
Пример #41
0
    def setUp(self):
        s = self.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell

        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
        vis = MVLSlabSet(self.slab)
        vis_dipole = MVLSlabSet(self.slab, auto_dipole=True)

        self.d_bulk = vis_bulk.get_vasp_input()
        self.d_slab = vis.get_vasp_input()
        self.d_dipole = vis_dipole.get_vasp_input()
        self.vis = vis
        warnings.simplefilter("ignore")
Пример #42
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)
Пример #43
0
    def setUp(self):
        zno1 = Structure.from_file(get_path("ZnO-wz.cif"), primitive=False)
        zno55 = SlabGenerator(zno1, [1, 0, 0],
                              5,
                              5,
                              lll_reduce=False,
                              center_slab=False).get_slab()

        Ti = Structure(
            Lattice.hexagonal(4.6, 2.82), ["Ti", "Ti", "Ti"],
            [[0.000000, 0.000000, 0.000000], [0.333333, 0.666667, 0.500000],
             [0.666667, 0.333333, 0.500000]])

        Ag_fcc = Structure(
            Lattice.cubic(4.06), ["Ag", "Ag", "Ag", "Ag"],
            [[0.000000, 0.000000, 0.000000], [0.000000, 0.500000, 0.500000],
             [0.500000, 0.000000, 0.500000], [0.500000, 0.500000, 0.000000]])

        self.ti = Ti
        self.agfcc = Ag_fcc
        self.zno1 = zno1
        self.zno55 = zno55
        self.h = Structure(Lattice.cubic(3), ["H"], [[0, 0, 0]])
        self.libcc = Structure(Lattice.cubic(3.51004), ["Li", "Li"],
                               [[0, 0, 0], [0.5, 0.5, 0.5]])
Пример #44
0
    def setUp(self):
        if "PMG_VASP_PSP_DIR" not in os.environ:
            os.environ["PMG_VASP_PSP_DIR"] = test_dir
        s = PymatgenTest.get_structure("Li2O")
        gen = SlabGenerator(s, (1, 0, 0), 10, 10)
        self.slab = gen.get_slab()
        self.bulk = self.slab.oriented_unit_cell

        vis_bulk = MVLSlabSet(self.bulk, bulk=True)
        vis = MVLSlabSet(self.slab)
        vis_dipole = MVLSlabSet(self.slab, auto_dipole=True)

        self.d_bulk = vis_bulk.all_input
        self.d_slab = vis.all_input
        self.d_dipole = vis_dipole.all_input
        self.vis = vis
        warnings.simplefilter("ignore")
Пример #45
0
    def test_get_orthogonal_c_slab_site_props(self):
        TeI = Structure.from_file(get_path("icsd_TeI.cif"),
                                  primitive=False)
        trclnc_TeI = SlabGenerator(TeI, (0, 0, 1), 10, 10)
        TeI_slabs = trclnc_TeI.get_slabs()
        slab = TeI_slabs[0]
        # Add site property to slab
        sd_list = [[True, True, True] for site in slab.sites]
        new_sp = slab.site_properties
        new_sp['selective_dynamics'] = sd_list
        slab_with_site_props = slab.copy(site_properties=new_sp)

        # Get orthogonal slab
        norm_slab = slab_with_site_props.get_orthogonal_c_slab()

        # Check if site properties is consistent (or kept)
        self.assertEqual(slab_with_site_props.site_properties, norm_slab.site_properties)
Пример #46
0
    def test_get_slab(self):
        s = self.get_structure("LiFePO4")
        gen = SlabGenerator(s, [0, 0, 1], 10, 10)
        s = gen.get_slab(0.25)
        self.assertAlmostEqual(s.lattice.abc[2], 20.820740000000001)

        fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"],
                                        [[0, 0, 0]])
        gen = SlabGenerator(fcc, [1, 1, 1], 10, 10)
        slab = gen.get_slab()
        gen = SlabGenerator(fcc, [1, 1, 1], 10, 10, primitive=False)
        slab_non_prim = gen.get_slab()
        self.assertEqual(len(slab), 6)
        self.assertEqual(len(slab_non_prim), len(slab) * 4)

        #Some randomized testing of cell vectors
        for i in range(1, 231):
            i = random.randint(1, 230)
            sg = SpaceGroup.from_int_number(i)
            if sg.crystal_system == "hexagonal" or (sg.crystal_system == \
                    "trigonal" and sg.symbol.endswith("H")):
                latt = Lattice.hexagonal(5, 10)
            else:
                #Cubic lattice is compatible with all other space groups.
                latt = Lattice.cubic(5)
            s = Structure.from_spacegroup(i, latt, ["H"], [[0, 0, 0]])
            miller = (0, 0, 0)
            while miller == (0, 0, 0):
                miller = (random.randint(0, 6), random.randint(0, 6),
                          random.randint(0, 6))
            gen = SlabGenerator(s, miller, 10, 10)
            a, b, c = gen.oriented_unit_cell.lattice.matrix
            self.assertAlmostEqual(np.dot(a, gen._normal), 0)
            self.assertAlmostEqual(np.dot(b, gen._normal), 0)
Пример #47
0
 def test_get_tasker2_slabs(self):
     # The uneven distribution of ions on the (111) facets of Halite
     # type slabs are typical examples of Tasker 3 structures. We
     # will test this algo to generate a Tasker 2 structure instead
     slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10,
                             max_normal_search=1)
     # We generate the Tasker 3 structure first
     slab = slabgen.get_slabs()[0]
     self.assertFalse(slab.is_symmetric())
     self.assertTrue(slab.is_polar())
     # Now to generate the Tasker 2 structure, we must
     # ensure there are enough ions on top to move around
     slab.make_supercell([2, 1, 1])
     slabs = slab.get_tasker2_slabs()
     # Check if our Tasker 2 slab is nonpolar and symmetric
     for slab in slabs:
         self.assertTrue(slab.is_symmetric())
         self.assertFalse(slab.is_polar())
Пример #48
0
    def test_get_slab_regions(self):

        # If a slab layer in the slab cell is not completely inside
        # the cell (noncontiguous), check that get_slab_regions will
        # be able to identify where the slab layers are located

        s = self.get_structure("LiFePO4")
        slabgen = SlabGenerator(s, (0, 0, 1), 15, 15)
        slab = slabgen.get_slabs()[0]
        slab.translate_sites([i for i, site in enumerate(slab)], [0, 0, -0.25])
        bottom_c, top_c = [], []
        for site in slab:
            if site.frac_coords[2] < 0.5:
                bottom_c.append(site.frac_coords[2])
            else:
                top_c.append(site.frac_coords[2])
        ranges = get_slab_regions(slab)
        self.assertEqual(tuple(ranges[0]), (0, max(bottom_c)))
        self.assertEqual(tuple(ranges[1]), (min(top_c), 1))
Пример #49
0
    def test_move_to_other_side(self):

        # Tests to see if sites are added to opposite side
        s = self.get_structure("LiFePO4")
        slabgen = SlabGenerator(s, (0, 0, 1), 10, 10, center_slab=True)
        slab = slabgen.get_slab()
        surface_sites = slab.get_surface_sites()

        # check if top sites are moved to the bottom
        top_index = [ss[1] for ss in surface_sites["top"]]
        slab = slabgen.move_to_other_side(slab, top_index)
        all_bottom = [slab[i].frac_coords[2] < slab.center_of_mass[2]
                      for i in top_index]
        self.assertTrue(all(all_bottom))

        # check if bottom sites are moved to the top
        bottom_index = [ss[1] for ss in surface_sites["bottom"]]
        slab = slabgen.move_to_other_side(slab, bottom_index)
        all_top = [slab[i].frac_coords[2] > slab.center_of_mass[2]
                   for i in bottom_index]
        self.assertTrue(all(all_top))
Пример #50
0
    def test_nonstoichiometric_symmetrized_slab(self):
        # For the (111) halite slab, sometimes a nonstoichiometric
        # system is preferred over the stoichiometric Tasker 2.
        slabgen = SlabGenerator(self.MgO, (1, 1, 1), 10, 10,
                                max_normal_search=1)
        slabs = slabgen.get_slabs(symmetrize=True)

        # We should end up with two terminations, one with
        # an Mg rich surface and another O rich surface
        self.assertEqual(len(slabs), 2)
        for slab in slabs:
            self.assertTrue(slab.is_symmetric())

        # For a low symmetry primitive_elemental system such as
        # R-3m, there should be some nonsymmetric slabs
        # without using nonstoichiometric_symmetrized_slab
        slabs = generate_all_slabs(self.Dy, 1, 30, 30,
                                   center_slab=True, symmetrize=True)
        for s in slabs:
            self.assertTrue(s.is_symmetric())
            self.assertGreater(len(s), len(self.Dy))
    def test_apply_transformation(self):
        s = self.get_structure("LiFePO4")
        trans = SlabTransformation([0, 0, 1], 10, 10, shift = 0.25)
        gen = SlabGenerator(s, [0, 0, 1], 10, 10)
        slab_from_gen = gen.get_slab(0.25)
        slab_from_trans = trans.apply_transformation(s)
        self.assertArrayAlmostEqual(slab_from_gen.lattice.matrix, 
                                    slab_from_trans.lattice.matrix)
        self.assertArrayAlmostEqual(slab_from_gen.cart_coords, 
                                    slab_from_trans.cart_coords)

        fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"],
                                        [[0, 0, 0]])
        trans = SlabTransformation([1, 1, 1], 10, 10)
        slab_from_trans = trans.apply_transformation(fcc)
        gen = SlabGenerator(fcc, [1, 1, 1], 10, 10)
        slab_from_gen = gen.get_slab()
        self.assertArrayAlmostEqual(slab_from_gen.lattice.matrix,
                                    slab_from_trans.lattice.matrix)
        self.assertArrayAlmostEqual(slab_from_gen.cart_coords, 
                                    slab_from_trans.cart_coords)
Пример #52
0
    def test_get_slabs(self):
        gen = SlabGenerator(self.get_structure("CsCl"), [0, 0, 1], 10, 10)

        #Test orthogonality of some internal variables.
        a, b, c = gen.oriented_unit_cell.lattice.matrix
        self.assertAlmostEqual(np.dot(a, gen._normal), 0)
        self.assertAlmostEqual(np.dot(b, gen._normal), 0)

        self.assertEqual(len(gen.get_slabs()), 1)

        s = self.get_structure("LiFePO4")
        gen = SlabGenerator(s, [0, 0, 1], 10, 10)
        self.assertEqual(len(gen.get_slabs()), 5)

        self.assertEqual(len(gen.get_slabs(bonds={("P", "O"): 3})), 2)

        # There are no slabs in LFP that does not break either P-O or Fe-O
        # bonds for a miller index of [0, 0, 1].
        self.assertEqual(len(gen.get_slabs(
            bonds={("P", "O"): 3, ("Fe", "O"): 3})), 0)

        #If we allow some broken bonds, there are a few slabs.
        self.assertEqual(len(gen.get_slabs(
            bonds={("P", "O"): 3, ("Fe", "O"): 3},
            max_broken_bonds=2)), 2)

        # At this threshold, only the origin and center Li results in
        # clustering. All other sites are non-clustered. So the of
        # slabs is of sites in LiFePO4 unit cell - 2 + 1.
        self.assertEqual(len(gen.get_slabs(tol=1e-4)), 15)

        LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"),
                                          primitive=False)
        gen = SlabGenerator(LiCoO2, [0, 0, 1], 10, 10)
        lco = gen.get_slabs(bonds={("Co", "O"): 3})
        self.assertEqual(len(lco), 1)
        a, b, c = gen.oriented_unit_cell.lattice.matrix
        self.assertAlmostEqual(np.dot(a, gen._normal), 0)
        self.assertAlmostEqual(np.dot(b, gen._normal), 0)
Пример #53
0
    def create_slab(self, vacuum=12, thickness=10):
        """
        set the vacuum spacing, slab thickness and call sd_flags
        for top 2 layers

        returns the poscar corresponding to the modified structure
        """ 
        strt_structure = self.input_structure.copy()
        if self.from_ase:
            slab_struct = get_ase_slab(strt_structure, hkl=self.system['hkl'],
                                        min_thick=thickness, min_vac=vacuum)
        else:
            slab_struct= SlabGenerator(initial_structure= strt_structure,
                                       miller_index= self.system['hkl'], 
                                       min_slab_size= thickness,
                                       min_vacuum_size=vacuum, 
                                       lll_reduce=False, center_slab=True,
                                       primitive=False).get_slab()
        slab_struct.sort()
        sd = self.set_sd_flags(slab_struct)
        comment = 'VAC'+str(vacuum)+'THICK'+str(thickness)
        return Poscar(slab_struct, comment=comment,
                      selective_dynamics=sd)    
Пример #54
0
    def run_task(self, fw_spec):

        """
            Required Parameters:
                folder (str path): Location where vasp inputs
                    are to be written
                custodian_params (dict **kwargs): Contains the job and the
                    scratch directory for a custodian run
                vaspdbinsert_parameters (dict **kwargs): Contains
                    informations needed to acess a DB, eg, host,
                    port, password etc.
            Optional Parameters:
                min_vac_size (float): Size of vacuum layer of slab in Angstroms
                min_slab_size (float): Size of slab layer of slab in Angstroms
                angle_tolerance (int): See SpaceGroupAnalyzer in analyzer.py
                user_incar_settings (dict): See launch_workflow() method in
                    CreateSurfaceWorkflow class
                k_product (dict): See launch_workflow() method in
                    CreateSurfaceWorkflow class
                potcar_functional (dict): See launch_workflow() method in
                    CreateSurfaceWorkflow class
                symprec (float): See SpaceGroupAnalyzer in analyzer.py
                terminations (bool): Determines whether or not to consider
                    different terminations in a slab. If true, each slab with a
                    specific shift value will have its own Firework and each of the
                    slab calculations will run in parallel. Defaults to false which
                    sets the shift value to 0.
        """
        dec = MontyDecoder()
        folder = dec.process_decoded(self.get("folder"))
        cwd = dec.process_decoded(self.get("cwd"))
        symprec = dec.process_decoded(self.get("symprec", 0.001))
        angle_tolerance = dec.process_decoded(self.get("angle_tolerance", 5))
        terminations = dec.process_decoded(self.get("terminations", False))
        custodian_params = dec.process_decoded(self.get("custodian_params"))
        vaspdbinsert_parameters = \
            dec.process_decoded(self.get("vaspdbinsert_parameters"))

        user_incar_settings = \
            dec.process_decoded(self.get("user_incar_settings",
                                         MPSlabVaspInputSet().incar_settings))
        k_product = \
            dec.process_decoded(self.get("k_product", 50))
        potcar_functional = \
            dec.process_decoded(self.get("potcar_fuctional", 'PBE'))
        min_slab_size = dec.process_decoded(self.get("min_slab_size", 10))
        min_vacuum_size = dec.process_decoded(self.get("min_vacuum_size", 10))
        miller_index = dec.process_decoded(self.get("miller_index"))

        print 'about to make mplb'

        mplb = MPSlabVaspInputSet(user_incar_settings=user_incar_settings,
                                  k_product=k_product,
                                  potcar_functional=potcar_functional,
                                  ediff_per_atom=False)

        # Create slabs from the relaxed oriented unit cell. Since the unit
        # cell is already oriented with the miller index, entering (0,0,1)
        # into SlabGenerator is the same as obtaining a slab in the
        # orienetation of the original miller index.
        print 'about to copy contcar'
        contcar = Poscar.from_file("%s/CONTCAR.relax2.gz" %(cwd+folder))
        relax_orient_uc = contcar.structure
        print 'made relaxed oriented structure'
        print relax_orient_uc
        print 'making slab'

        slabs = SlabGenerator(relax_orient_uc, (0,0,1),
                              min_slab_size=min_slab_size,
                              min_vacuum_size=min_vacuum_size,
                              max_normal_search=max(miller_index))

        # Whether or not to create a list of Fireworks
        # based on different slab terminations
        print 'deciding terminations'
        slab_list = slabs.get_slabs() if terminations else [slabs.get_slab()]

        qe = QueryEngine(**vaspdbinsert_parameters)
        optional_data = ["state"]
        print 'query bulk entry for job completion'
        bulk_entry =  qe.get_entries({'chemsys': relax_orient_uc.composition.reduced_formula,
                                     'structure_type': 'oriented_unit_cell', 'miller_index': miller_index},
                                     optional_data=optional_data)
        print 'chemical formula', relax_orient_uc.composition.reduced_formula
        print 'fomular data type is ', type(relax_orient_uc.composition.reduced_formula)
        print 'checking job completion'
        print bulk_entry
        for entry in bulk_entry:
            print 'for loop'
            print entry.data['state']
            if entry.data['state'] != 'successful':
                print "%s bulk calculations were incomplete, cancelling FW" \
                      %(relax_orient_uc.composition.reduced_formula)
                return FWAction()
            else:

                print entry.data['state']

                FWs = []
                for slab in slab_list:

                    print slab

                    new_folder = folder.replace('bulk', 'slab')+'_shift%s' \
                                                                %(slab.shift)

                    # Will continue an incomplete job from a previous contcar file if it exists
                    print 'cwd is %s' %(os.getcwd())
                    print 'the folder is %s' %(new_folder)
                    print os.path.join(os.getcwd(), new_folder)
                    print cwd+'/'+new_folder
                    path = cwd+'/'+new_folder

                    # path = os.path.join(os.getcwd(), folder)
                    newfolder = os.path.join(path, 'prev_run')

                    # print 'check if conditions for continuing calculations have been satisfied'
                    # print 'check for the following path: %s' %(path)
                    # print os.path.exists(path)
                    # print os.path.exists(os.path.join(path, 'CONTCAR.gz'))
                    # print os.stat(os.path.join(path, 'CONTCAR.gz')).st_size !=0

                    def continue_vasp(contcar):
                        print folder, 'already exists, will now continue calculation'
                        print 'making prev_run folder'
                        os.system('mkdir %s' %(newfolder))
                        print 'moving outputs to prev_run'
                        os.system('mv %s/* %s/prev_run' %(path, path))
                        print 'moving outputs as inputs for next calculation'
                        os.system('cp %s/%s %s/INCAR %s/POTCAR %s/KPOINTS %s'
                                  %(newfolder, contcar, newfolder, newfolder, newfolder, path))
                        print 'unzipping new inputs'
                        os.system('gunzip %s/*' %(path))
                        print 'copying contcar as new poscar'
                        if contcar == 'CONTCAR.relax1.gz':
                            os.system('mv %s/CONTCAR.relax1 %s/POSCAR' %(path , path))
                        else:
                            os.system('mv %s/CONTCAR %s/POSCAR' %(path , path))


                    if os.path.exists(path) and \
                            os.path.exists(os.path.join(path, 'CONTCAR')) and \
                                    os.stat(os.path.join(path, 'CONTCAR')).st_size !=0:
                        continue_vasp('CONTCAR')
                    elif os.path.exists(path) and \
                            os.path.exists(os.path.join(path, 'CONTCAR.gz')) \
                            and os.stat(os.path.join(path, 'CONTCAR.gz')).st_size !=0:
                        continue_vasp('CONTCAR.gz')
                    elif os.path.exists(path) and \
                            os.path.exists(os.path.join(path, 'CONTCAR.relax1.gz')) and \
                                    os.stat(os.path.join(path, 'CONTCAR.relax1.gz')).st_size !=0:
                        continue_vasp('CONTCAR.relax1.gz')

                    else:
                        mplb.write_input(slab, cwd+new_folder)

                        # Writes new INCAR file based on changes made by custodian on the bulk's INCAR.
                        # Only change in parameters between slab and bulk should be MAGMOM and ISIF
                        if os.path.exists("%s/INCAR.relax2.gz" %(cwd+folder)):
                            incar = Incar.from_file(cwd+folder +'/INCAR.relax2.gz')
                        else:
                            incar = Incar.from_file(cwd+folder +'/INCAR.relax2')
                        if os.path.exists("%s/OUTCAR.relax2.gz" %(cwd+folder)):
                            out = Outcar(cwd+folder+'/OUTCAR.relax2.gz')
                        else:
                            out = Outcar(cwd+folder+'/OUTCAR.relax2')
                        out_mag = out.magnetization
                        tot_mag = [mag['tot'] for mag in out_mag]
                        magmom = np.mean(tot_mag)
                        mag= [magmom for i in slab]
                        incar.__setitem__('MAGMOM', mag)
                        incar.__setitem__('ISIF', 2)
                        incar.__setitem__('AMIN', 0.01)
                        incar.__setitem__('AMIX', 0.2)
                        incar.__setitem__('BMIX', 0.001)
                        incar.__setitem__('NELMIN', 8)
                        incar.__setitem__('ISTART', 0)
                        incar.write_file(cwd+new_folder+'/INCAR')

                    fw = Firework([RunCustodianTask(dir=new_folder, cwd=cwd,
                                                    **custodian_params),
                                   VaspSlabDBInsertTask(struct_type="slab_cell",
                                                        loc=new_folder, cwd=cwd, shift=slab.shift,
                                                        surface_area=slab.surface_area,
                                                        vsize=slabs.min_vac_size,
                                                        ssize=slabs.min_slab_size,
                                                        miller_index=miller_index,
                                                        **vaspdbinsert_parameters)],
                                  name=new_folder)
                    FWs.append(fw)

                return FWAction(additions=FWs)
Пример #55
0
    def test_get_slabs(self):
        gen = SlabGenerator(self.get_structure("CsCl"), [0, 0, 1], 10, 10)

        # Test orthogonality of some internal variables.
        a, b, c = gen.oriented_unit_cell.lattice.matrix
        self.assertAlmostEqual(np.dot(a, gen._normal), 0)
        self.assertAlmostEqual(np.dot(b, gen._normal), 0)

        self.assertEqual(len(gen.get_slabs()), 1)

        s = self.get_structure("LiFePO4")
        gen = SlabGenerator(s, [0, 0, 1], 10, 10)
        self.assertEqual(len(gen.get_slabs()), 5)

        self.assertEqual(len(gen.get_slabs(bonds={("P", "O"): 3})), 2)

        # There are no slabs in LFP that does not break either P-O or Fe-O
        # bonds for a miller index of [0, 0, 1].
        self.assertEqual(len(gen.get_slabs(
            bonds={("P", "O"): 3, ("Fe", "O"): 3})), 0)

        # If we allow some broken bonds, there are a few slabs.
        self.assertEqual(len(gen.get_slabs(
            bonds={("P", "O"): 3, ("Fe", "O"): 3},
            max_broken_bonds=2)), 2)

        # At this threshold, only the origin and center Li results in
        # clustering. All other sites are non-clustered. So the of
        # slabs is of sites in LiFePO4 unit cell - 2 + 1.
        self.assertEqual(len(gen.get_slabs(tol=1e-4, ftol=1e-4)), 15)

        LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"),
                                     primitive=False)
        gen = SlabGenerator(LiCoO2, [0, 0, 1], 10, 10)
        lco = gen.get_slabs(bonds={("Co", "O"): 3})
        self.assertEqual(len(lco), 1)
        a, b, c = gen.oriented_unit_cell.lattice.matrix
        self.assertAlmostEqual(np.dot(a, gen._normal), 0)
        self.assertAlmostEqual(np.dot(b, gen._normal), 0)

        scc = Structure.from_spacegroup("Pm-3m", Lattice.cubic(3), ["Fe"],
                                        [[0, 0, 0]])
        gen = SlabGenerator(scc, [0, 0, 1], 10, 10)
        slabs = gen.get_slabs()
        self.assertEqual(len(slabs), 1)
        gen = SlabGenerator(scc, [1, 1, 1], 10, 10, max_normal_search=1)
        slabs = gen.get_slabs()
        self.assertEqual(len(slabs), 1)

        # Test whether using units of hkl planes instead of Angstroms for
        # min_slab_size and min_vac_size will give us the same number of atoms
        natoms = []
        for a in [1, 1.4, 2.5, 3.6]:
            s = Structure.from_spacegroup("Im-3m", Lattice.cubic(a), ["Fe"],
                                          [[0, 0, 0]])
            slabgen = SlabGenerator(s, (1, 1, 1), 10, 10, in_unit_planes=True,
                                    max_normal_search=2)
            natoms.append(len(slabgen.get_slab()))
        n = natoms[0]
        for i in natoms:
            self.assertEqual(n, i)