def test_bandfilling_SOC_calc(self):
        v = Vasprun(os.path.join(PymatgenTest.TEST_FILES_DIR, "vasprun.xml.int_Te_SOC.gz"))
        struc = v.structures[0]
        interstitial = Interstitial(struc, struc.sites[-1], charge=-2)
        eigenvalues = v.eigenvalues.copy()
        kptweights = v.actual_kpoints_weights
        potalign = -0.1
        defect_incar = v.incar

        bandfill_params = {
            "eigenvalues": eigenvalues,
            "kpoint_weights": kptweights,
            "potalign": potalign,
            "vbm": 1.6465,  # bulk VBM
            "cbm": 3.1451,  # bulk CBM
            "run_metadata": {"defect_incar": defect_incar},
        }

        soc_dentry = DefectEntry(
            interstitial,
            0.0,
            corrections={},
            parameters=bandfill_params,
            entry_id=None,
        )
        dc = DefectCompatibility()
        soc_dentry = dc.process_entry(soc_dentry)

        self.assertAlmostEqual(soc_dentry.corrections["bandfilling_correction"], -1.9628402187500003)
Example #2
0
    def __init__(self, structure, element):
        """
        Initializes an Interstitial generator using structure motifs
        Args:
            structure (Structure): pymatgen structure object
            element (str or Element or Species): element for the interstitial
        """
        self.structure = structure
        self.element = element
        interstitial_finder = StructureMotifInterstitial(
            self.structure, self.element)

        self.unique_defect_seq = []
        # eliminate sublattice equivalent defects which may
        # have slipped through interstitial finder
        pdc = PointDefectComparator()

        for poss_site in interstitial_finder.enumerate_defectsites():
            now_defect = Interstitial(self.structure, poss_site)
            append_defect = True
            for unique_defect in self.unique_defect_seq:
                if pdc.are_equal(now_defect, unique_defect):
                    append_defect = False
            if append_defect:
                self.unique_defect_seq.append(now_defect)

        self.count_def = 0  # for counting the index of the generated defect
def convert_cd_to_de( cd, b_cse):
    """
    As of pymatgen v2.0, ComputedDefect objects were deprecated in favor
    of DefectEntry objects in pymatgen.analysis.defects.core
    This function takes a ComputedDefect (either as a dict or object) and
    converts it into a DefectEntry object in order to handle legacy
    PyCDT creation within the current paradigm of PyCDT.

    :param cd (dict or ComputedDefect object): ComputedDefect as an object or as a dictionary
    :params b_cse (dict or ComputedStructureEntry object): ComputedStructureEntry of bulk entry
        associated with the ComputedDefect.
    :return: de (DefectEntry): Resulting DefectEntry object
    """
    if type(cd) != dict:
        cd = cd.as_dict()
    if type(b_cse) != dict:
        b_cse = b_cse.as_dict()

    bulk_sc_structure = Structure.from_dict( b_cse["structure"])

    #modify defect_site as required for Defect object, confirming site exists in bulk structure
    site_cls = cd["site"]
    defect_site = PeriodicSite.from_dict( site_cls)
    def_nom = cd["name"].lower()
    if "sub_" in def_nom or "as_" in def_nom:
        #modify site object for substitution site of Defect object
        site_cls["species"][0]["element"] = cd["name"].split("_")[2]
        defect_site = PeriodicSite.from_dict( site_cls)

    poss_deflist = sorted(
        bulk_sc_structure.get_sites_in_sphere(defect_site.coords, 0.1, include_index=True), key=lambda x: x[1])
    if len(poss_deflist) != 1:
        raise ValueError("ComputedDefect to DefectEntry conversion failed. "
                         "Could not determine periodic site position in bulk supercell.")

    # create defect object
    if "vac_" in def_nom:
        defect_obj = Vacancy(bulk_sc_structure, defect_site, charge=cd["charge"])
    elif "as_" in def_nom or "sub_" in def_nom:
        defect_obj = Substitution(bulk_sc_structure, defect_site, charge=cd["charge"])
    elif "int_" in def_nom:
        defect_obj = Interstitial(bulk_sc_structure, defect_site, charge=cd["charge"])
    else:
        raise ValueError("Could not recognize defect type for {}".format( cd["name"]))


    # assign proper energy and parameter metadata
    uncorrected_energy = cd["entry"]["energy"] - b_cse["energy"]
    def_path = os.path.split( cd["entry"]["data"]["locpot_path"])[0]
    bulk_path = os.path.split( b_cse["data"]["locpot_path"])[0]
    p = {"defect_path": def_path,
         "bulk_path": bulk_path,
         "encut": cd["entry"]["data"]["encut"]}

    de = DefectEntry( defect_obj, uncorrected_energy, parameters = p)

    return de
Example #4
0
 def __next__(self):
     """
     Returns the next interstitial or
     raises StopIteration
     """
     if len(self.unique_defect_seq) > 0:
         inter_defect = self.unique_defect_seq.pop(0)
         inter_site = inter_defect.site
         self.count_def += 1
         site_name = "Voronoi" + str(self.count_def)
         return Interstitial(self.structure, inter_site, site_name=site_name)
     raise StopIteration
Example #5
0
 def __next__(self):
     """
     Returns the next interstitial or
     raises StopIteration
     """
     if len(self.equiv_site_seq) > 0:
         inter_site_list = self.equiv_site_seq.pop(0)
         self.count_def += 1
         site_name = 'Voronoi' + str(self.count_def)
         return Interstitial(self.structure,
                             inter_site_list[0],
                             site_name=site_name,
                             multiplicity=len(inter_site_list))
     else:
         raise StopIteration
Example #6
0
 def __next__(self):
     """
     Returns the next interstitial or
     raises StopIteration
     """
     if len(self.defect_sites) > 0:
         int_site = self.defect_sites.pop(0)
         mult = self.multiplicities.pop(0)
         self.count_def += 1
         site_name = 'InFiT' + str(self.count_def)
         return Interstitial(self.structure,
                             int_site,
                             site_name=site_name,
                             multiplicity=mult)
     else:
         raise StopIteration
Example #7
0
    def __init__(self, structure, element):
        """
        Initializes an Interstitial generator using Voronoi sites
        Args:
            structure (Structure): pymatgen structure object
            element (str or Element or Species): element for the interstitial
        """
        self.structure = structure
        self.element = element

        framework = list(self.structure.symbol_set)
        get_voronoi = TopographyAnalyzer(self.structure,
                                         framework, [],
                                         check_volume=False)
        get_voronoi.cluster_nodes()
        get_voronoi.remove_collisions()

        # trim equivalent nodes with symmetry analysis
        struct_to_trim = self.structure.copy()
        for poss_inter in get_voronoi.vnodes:
            struct_to_trim.append(self.element,
                                  poss_inter.frac_coords,
                                  coords_are_cartesian=False)

        symmetry_finder = SpacegroupAnalyzer(struct_to_trim, symprec=1e-1)
        equiv_sites_list = symmetry_finder.get_symmetrized_structure(
        ).equivalent_sites

        # do additional screening for sublattice equivalent
        # defects which may have slipped through
        pdc = PointDefectComparator()
        self.unique_defect_seq = []
        for poss_site_list in equiv_sites_list:
            poss_site = poss_site_list[0]
            if poss_site not in self.structure:
                now_defect = Interstitial(self.structure, poss_site)
                append_defect = True
                for unique_defect in self.unique_defect_seq:
                    if pdc.are_equal(now_defect, unique_defect):
                        append_defect = False
                if append_defect:
                    self.unique_defect_seq.append(now_defect)

        self.count_def = 0  # for counting the index of the generated defect
Example #8
0
    def test_sublattice_generation(self):
        struc = PymatgenTest.get_structure("CsCl")
        sc_struc = struc.copy()
        sc_struc.make_supercell(3)

        # test for vacancy and sub (should not change structure)
        Cs_index = sc_struc.indices_from_symbol("Cs")[0]
        cs_vac = Vacancy(sc_struc, sc_struc[Cs_index])
        decorated_cs_vac = create_saturated_interstitial_structure(cs_vac)
        self.assertEqual(len(decorated_cs_vac), len(sc_struc))

        Cl_index = sc_struc.indices_from_symbol("Cl")[0]

        cl_vac = Vacancy(sc_struc, sc_struc[Cl_index])
        decorated_cl_vac = create_saturated_interstitial_structure(cl_vac)
        self.assertEqual(len(decorated_cl_vac), len(sc_struc))

        sub_site = PeriodicSite("Sr",
                                sc_struc[Cs_index].coords,
                                sc_struc.lattice,
                                coords_are_cartesian=True)

        sub = Substitution(sc_struc, sub_site)
        decorated_sub = create_saturated_interstitial_structure(sub)
        self.assertEqual(len(decorated_sub), len(sc_struc))

        # test interstitial in symmorphic structure type
        inter_site = PeriodicSite("H", [0., 1.05225, 2.1045],
                                  struc.lattice,
                                  coords_are_cartesian=True)  # voronoi type
        interstitial = Interstitial(struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 14)

        inter_site = PeriodicSite("H", [0.10021429, 0.10021429, 2.1045],
                                  struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 14)

        inter_site = PeriodicSite("H", [4.10878571, 1.10235714, 2.1045],
                                  struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 26)

        inter_site = PeriodicSite(
            "H", [0., 0., 0.5], struc.lattice,
            coords_are_cartesian=False)  # a reasonable guess type
        interstitial = Interstitial(struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 5)

        # test interstitial in non-symmorphic structure type
        # (voronoi and InFit generator of different types...)
        ns_struc = Structure.from_file(os.path.join(test_dir, "CuCl.cif"))

        inter_site = PeriodicSite("H", [0.45173594, 0.41157895, 5.6604067],
                                  ns_struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(ns_struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 40)

        inter_site = PeriodicSite("H", [0.47279906, 0.82845998, 5.62015285],
                                  ns_struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(ns_struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 40)

        inter_site = PeriodicSite("H", [0.70845255, 6.50298148, 5.16979425],
                                  ns_struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(ns_struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 40)

        inter_site = PeriodicSite("H", [0.98191329, 0.36460337, 4.64718203],
                                  ns_struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(ns_struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 40)

        inter_site = PeriodicSite("H", [0.39286561, 3.92702149, 1.05802631],
                                  ns_struc.lattice,
                                  coords_are_cartesian=True)  # InFit type
        interstitial = Interstitial(ns_struc, inter_site)
        decorated_inter = create_saturated_interstitial_structure(interstitial)
        self.assertEqual(len(decorated_inter), 40)
                                  '/vasprun.xml',
                                  ionic_step_skip=None,
                                  ionic_step_offset=0,
                                  parse_dos=False,
                                  parse_eigen=False,
                                  parse_projected_eigen=False,
                                  parse_potcar_file=False,
                                  occu_tol=1e-08,
                                  exception_on_bad_xml=True)
                # getting total energy from VASP output
                total_energies_dict[q] = vasprun.final_energy

        for q in total_energies_dict:
            # creating vacancy object
            interstitial = Interstitial(structure_pure,
                                        defect_site,
                                        charge=q,
                                        multiplicity=1)

            # including corrections
            corrections = corrections_init.copy()

            # if requested calculate freysoldt corrections
            if include_freysoldt_corrections:
                path_to_defect_locpot = charge_dir + calc_scheme[
                    'locpot'] + '/LOCPOT'
                freysoldt_corrections = get_freysoldt_correction(
                    'interstitial',
                    inter_type,
                    path_to_defect_locpot,
                    path_to_pure_locpot,
                    q,
    def test_check_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55
        defect_frac_sc_coords = self.vac.site.frac_coords[:]

        params = {'initial_defect_structure': initial_defect_structure,
                  'final_defect_structure': final_defect_structure,
                  'sampling_radius': sampling_radius,
                  'defect_frac_sc_coords': defect_frac_sc_coords,
                  'is_compatible': True}
        dentry = DefectEntry(self.vac, 0., corrections={}, parameters=params, entry_id=None)

        dc = DefectCompatibility( tot_relax_tol=0.1, perc_relax_tol=0.1, defect_tot_relax_tol=0.1)
        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        struc_delocal = dentry.parameters['delocalization_meta']['structure_relax']
        self.assertTrue( dentry.parameters['is_compatible'])
        self.assertTrue( struc_delocal['is_compatible'])
        self.assertTrue( struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertEqual( struc_delocal['metadata']['tot_relax_outside_rad'], 0.)
        self.assertTrue( struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertEqual( struc_delocal['metadata']['perc_relax_outside_rad'], 0.)
        self.assertEqual( len(struc_delocal['metadata']['full_structure_relax_data']), len(initial_defect_structure))
        self.assertIsNone( struc_delocal['metadata']['defect_index'])

        defect_delocal = dentry.parameters['delocalization_meta']['defectsite_relax']
        self.assertTrue( defect_delocal['is_compatible'])
        self.assertIsNone( defect_delocal['metadata']['relax_amount'])


        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb( 0.1)
        dentry.parameters.update( {'final_defect_structure': pert_struct_fin_struct})
        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        struc_delocal = dentry.parameters['delocalization_meta']['structure_relax']
        self.assertFalse( dentry.parameters['is_compatible'])
        self.assertFalse( struc_delocal['is_compatible'])
        self.assertFalse( struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertAlmostEqual( struc_delocal['metadata']['tot_relax_outside_rad'], 12.5)
        self.assertFalse( struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertAlmostEqual( struc_delocal['metadata']['perc_relax_outside_rad'], 77.63975155)


        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite('H',  [7.58857304, 11.70848069, 12.97817518],
                                self.vac.bulk_structure.lattice, to_unit_cell=True,
                                coords_are_cartesian=True)
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(
            final_defect_structure.get_sites_in_sphere(inter.site.coords,
                                                       2, include_index=True), key=lambda x: x[1])
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(indices=[def_index],
                                               vector=[0., 0., 0.008]) #fractional coords translation
        defect_frac_sc_coords = inter_def_site.frac_coords[:]

        params = {'initial_defect_structure': initial_defect_structure,
                  'final_defect_structure': final_defect_structure,
                  'sampling_radius': sampling_radius,
                  'defect_frac_sc_coords': defect_frac_sc_coords,
                  'is_compatible': True}
        dentry = DefectEntry(inter, 0., corrections={}, parameters=params, entry_id=None)

        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        defect_delocal = dentry.parameters['delocalization_meta']['defectsite_relax']
        self.assertFalse( defect_delocal['is_compatible'])
        self.assertAlmostEqual( defect_delocal['metadata']['relax_amount'], 0.10836054)
    def test_is_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55

        params = {
            'initial_defect_structure': initial_defect_structure,
            'final_defect_structure': final_defect_structure,
            'sampling_radius': sampling_radius,
            'is_compatible': True
        }
        dentry = DefectEntry(self.vac,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)

        dc = DefectCompatibility(tot_relax_tol=0.1,
                                 perc_relax_tol=0.1,
                                 defect_tot_relax_tol=0.1)
        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters['delocalization_meta'][
            'structure_relax']
        self.assertTrue(dentry.parameters['is_compatible'])
        self.assertTrue(struc_delocal['is_compatible'])
        self.assertTrue(
            struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertEqual(struc_delocal['metadata']['tot_relax_outside_rad'],
                         0.)
        self.assertTrue(
            struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertEqual(struc_delocal['metadata']['perc_relax_outside_rad'],
                         0.)
        self.assertEqual(
            len(struc_delocal['metadata']['full_structure_relax_data']),
            len(initial_defect_structure))
        self.assertIsNone(struc_delocal['metadata']['defect_index'])

        defect_delocal = dentry.parameters['delocalization_meta'][
            'defectsite_relax']
        self.assertTrue(defect_delocal['is_compatible'])
        self.assertIsNone(defect_delocal['metadata']['relax_amount'])

        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb(0.1)
        dentry.parameters.update(
            {'final_defect_structure': pert_struct_fin_struct})
        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters['delocalization_meta'][
            'structure_relax']
        self.assertFalse(dentry.parameters['is_compatible'])
        self.assertFalse(struc_delocal['is_compatible'])
        self.assertFalse(
            struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertAlmostEqual(
            struc_delocal['metadata']['tot_relax_outside_rad'], 12.5)
        self.assertFalse(
            struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertAlmostEqual(
            struc_delocal['metadata']['perc_relax_outside_rad'], 77.63975155)

        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite('H',
                                      [7.58857304, 11.70848069, 12.97817518],
                                      self.vac.bulk_structure.lattice,
                                      to_unit_cell=True,
                                      coords_are_cartesian=True)
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(final_defect_structure.get_sites_in_sphere(
            inter.site.coords, 2, include_index=True),
                              key=lambda x: x[1])
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(
            indices=[def_index],
            vector=[0., 0., 0.008])  #fractional coords translation

        params = {
            'initial_defect_structure': initial_defect_structure,
            'final_defect_structure': final_defect_structure,
            'sampling_radius': sampling_radius,
            'is_compatible': True
        }
        dentry = DefectEntry(inter,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)

        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        defect_delocal = dentry.parameters['delocalization_meta'][
            'defectsite_relax']
        self.assertFalse(defect_delocal['is_compatible'])
        self.assertAlmostEqual(defect_delocal['metadata']['relax_amount'],
                               0.10836054)
Example #12
0
def generate_supercells(
    bulk_structure, 
    grid_size = 4, 
    supercell = (2, 2, 2), 
    method = 'grid', 
    positions=None
):
    """
    This is a wrapper to various methods to generate different interstitial impurities.
    
    Parameters
    ----------
    bulk_structure : Structure object
        A unitcell (magnetic or not) structure in form of Pymatgen Structure object 
    grid_size : int
        A grid size in all lattice directions to generate uniform 
        grid for interstitial impurities implemented by Pietro Bonfa. Default=4.
    supercell : tuple, numpy.ndarray
        Supercell size in a, b and c direction. Default = (2, 2, 2)
    method : str
        The method to generate interstial impurities. Default='grid'
    positions : None
        A numpy.ndarray of muon positions if `method="manual"`.
    
    Returns
    -------
    structure_list : list
        A list of supercell structure containing interstitial impurities
    """

    #magnetic_structure = CollinearMagneticStructureAnalyzer(bulk_structure, make_primitive=False)
    #if magnetic_structure.is_magnetic:
    #    #spin_bulk_structure = magnetic_structure.get_structure_with_spin()
    #    spin_bulk_structure =
    #    spin_bulk_structure.make_supercell(supercell)
    site_properties_preservation = bulk_structure.copy()
    site_properties_preservation.make_supercell(supercell)

    structure_list = []

    ## Manually set ?
    if method == 'manual':
        if positions is None:
            raise ValueError('Position must be specified in manual mode!')
        r = []
        for position in positions:
            defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False)
            r.append(Interstitial(bulk_structure, defect_site, charge=0.))
    elif method == 'tess':
        r = []
        for position in tess_interstitials(bulk_structure):
            defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False)
            r.append(Interstitial(bulk_structure, defect_site, charge=0.))
    elif method == 'infit':
        r = list(InterstitialGenerator( bulk_structure, 'H'))
    elif method == 'grid':
        r = []
        for position in generate_uniform_grid(bulk_structure, grid_size):
            defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False)
            r.append(Interstitial(bulk_structure, defect_site, charge=0.))
    else:
        r = list(VoronoiInterstitialGenerator( bulk_structure, 'H'))

    for i,v in enumerate(r):
        struct=v.generate_defect_structure(supercell=supercell)


        ## Preserve magnetic structure
        #if (magnetic_structure.is_magnetic):
        #    spins = np.zeros(struct.num_sites)
        #    # TODO: check non collinear...
        #    for site1 in spin_bulk_structure:
        #        for i, site2 in enumerate(struct):
        #            if np.allclose(site1.coords, site2.coords, atol = site2.position_atol):
        #                spins[i] = site1.specie.spin
        #                break
        #
        #    struct.add_spin_by_site(spins)

        for site1 in site_properties_preservation:
            for i, site2 in enumerate(struct):
                if np.allclose(site1.coords, site2.coords, atol = site2.position_atol):
                    #spins[i] = site1.specie.spin
                    struct[i].properties = site1.properties
                    break

        # Remove symmetry
        if method != 'manual':
            # Here we assume, manual muon site are perturb.
            # Performs a random perturbation of the sites in the structure 
            # to break symmetries. A distance of 1e-4 Angs. surely does nothing
            # However we can perturb the muon site with a random vector with
            # 0.1 Angs. distance
            struct.perturb(distance=0.0001)
            struct.translate_sites(-1, 0.1 * np.random.random(3), frac_coords=False)           
        if struct.is_valid():
            structure_list.append(struct)
    return structure_list
Example #13
0
    def test_interstitial(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1],
                                struc.lattice)
        interstitial = Interstitial(struc, int_site)

        # test generation and super cell
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4})
        # Ensure the site is in the right place
        self.assertEqual(
            int_site,
            int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0])

        int_struc = interstitial.generate_defect_structure(2)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32})

        int_struc = interstitial.generate_defect_structure(3)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108})

        int_struc = interstitial.generate_defect_structure([[2., 0, 0],
                                                            [0, 0, -3.],
                                                            [0, 2., 0]])
        self.assertEqual(int_struc.composition.as_dict(), {"V": 25, "O": 48})

        # test charge
        interstitial = Interstitial(struc, int_site)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 0.0)

        interstitial = Interstitial(struc, int_site, charge=1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 1.0)

        interstitial = Interstitial(struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, -1.0)

        # test multiplicity
        interstitial = Interstitial(struc, int_site)
        self.assertEqual(interstitial.multiplicity, 1.0)

        interstitial = Interstitial(struc, int_site, multiplicity=4.0)
        self.assertEqual(interstitial.multiplicity, 4.0)

        # Test composoition
        self.assertEqual(dict(interstitial.defect_composition.as_dict()), {
            "V": 3,
            "O": 4
        })
Example #14
0
    def __init__(self,
                 structure,
                 max_min_oxi=None,
                 substitutions=None,
                 oxi_states=None,
                 cellmax=128,
                 antisites_flag=True,
                 include_interstitials=False,
                 interstitial_elements=None,
                 intersites=None,
                 standardized=False,
                 struct_type='semiconductor'):
        """
        Args:
            structure (Structure):
                the bulk structure.
            max_min_oxi (dict):
                The minimal and maximum oxidation state of each element as a
                dict. For instance {"O":(-2,0)}. If not given, the oxi-states
                of pymatgen are considered.
            substitutions (dict):
                The allowed substitutions of elements as a dict. If not given,
                intrinsic defects are computed. If given, intrinsic (e.g.,
                anti-sites) and extrinsic are considered explicitly specified.
                Example: {"Co":["Zn","Mn"]} means Co sites can be substituted
                by Mn or Zn.
            oxi_states (dict):
                The oxidation state of the elements in the compound e.g.
                {"Fe":2,"O":-2}. If not given, the oxidation state of each
                site is computed with bond valence sum. WARNING: Bond-valence
                method can fail for mixed-valence compounds.
            cellmax (int):
                Maximum number of atoms allowed in the supercell.
            antisites_flag (bool):
                If False, don't generate antisites.
            include_interstitials (bool):
                If true, do generate interstitial defect configurations
                (default: False).
            interstitial_elements ([str]):
                List of strings containing symbols of the elements that are
                to be considered for interstitial sites.  The default (None)
                triggers self-interstitial generation,
                given that include_interstitials is True.
            intersites ([PeriodicSite]):
                A list of PeriodicSites in the bulk structure on which we put
                interstitials.  Note that you still have to set flag
                include_interstitials to True in order to make use of this
                manual way of providing interstitial sites.
                If this is used, then no additional interstitials are generated
                beyond the list that is provided in intersites.
            standardized (bool):
                If True, use the primitive standard structure as unit cell
                for generating the defect configurations (default is False).
                The primitive standard structure is obtained from the
                SpacegroupAnalyzer class with a symprec of 0.01.
            struct_type (string):
                Options are 'semiconductor' and 'insulator'. If semiconductor
                is selected, charge states based on database of semiconductors
                is used to assign defect charges. For insulators, defect
                charges are conservatively assigned.
        """
        max_min_oxi = max_min_oxi if max_min_oxi is not None else {}
        substitutions = substitutions if substitutions is not None else {}
        oxi_states = oxi_states if oxi_states is not None else {}
        interstitial_elements = interstitial_elements if interstitial_elements is not None else []
        intersites = intersites if intersites is not None else []

        self.defects = []
        self.cellmax = cellmax
        self.substitutions = {}
        self.struct_type = struct_type
        for key, val in substitutions.items():
            self.substitutions[key] = val

        spa = SpacegroupAnalyzer(structure, symprec=1e-2)
        prim_struct = spa.get_primitive_standard_structure()
        if standardized:
            self.struct = prim_struct
        else:
            self.struct = structure

        struct_species = self.struct.types_of_specie
        if self.struct_type == 'semiconductor':
            self.defect_charger = DefectChargerSemiconductor(
                self.struct, min_max_oxi=max_min_oxi)
        elif self.struct_type == 'insulator':
            self.defect_charger = DefectChargerInsulator(self.struct)
        elif self.struct_type == 'manual':
            self.defect_charger = DefectChargerUserCustom(
                self.struct, oxi_states=oxi_states)
        elif self.struct_type == 'ionic':
            self.defect_charger = DefectChargerIonic(self.struct)
        else:
            raise NotImplementedError

        if include_interstitials and interstitial_elements:
            for elem_str in interstitial_elements:
                if not Element.is_valid_symbol(elem_str):
                    raise ValueError("invalid interstitial element"
                                     " \"{}\"".format(elem_str))

        sc_scale = get_optimized_sc_scale(self.struct, cellmax)
        self.defects = {}
        sc = self.struct.copy()
        sc.make_supercell(sc_scale)
        self.defects['bulk'] = {
            'name': 'bulk',
            'supercell': {
                'size': sc_scale,
                'structure': sc
            }
        }

        # If interstitials are provided as a list of PeriodicSites,
        # make sure that the lattice has not changed.
        if include_interstitials and intersites:
            for intersite in intersites:  #list of PeriodicSite objects
                if intersite.lattice != self.struct.lattice:
                    raise RuntimeError(
                        "Discrepancy between lattices"
                        " underlying the input interstitials and"
                        " the bulk structure; possibly because of"
                        " standardizing the input structure.")

        vacancies = []
        as_defs = []
        sub_defs = []

        VG = VacancyGenerator(self.struct)
        print("Setting up defects...")
        for i, vac in enumerate(VG):
            vac_site = vac.site
            vac_symbol = vac.site.specie.symbol
            vac_sc = vac.generate_defect_structure(sc_scale)

            #create a trivial defect structure to find where supercell transformation moves the lattice
            struct_for_defect_site = Structure(
                vac.bulk_structure.copy().lattice, [vac.site.specie],
                [vac.site.frac_coords],
                to_unit_cell=True,
                coords_are_cartesian=False)
            struct_for_defect_site.make_supercell(sc_scale)
            vac_sc_site = struct_for_defect_site[0]

            charges_vac = self.defect_charger.get_charges(
                'vacancy', vac_symbol)
            vacancies.append({
                'name': "vac_{}_{}".format(i + 1, vac_symbol),
                'unique_site': vac_site,
                'bulk_supercell_site': vac_sc_site,
                'defect_type': 'vacancy',
                'site_specie': vac_symbol,
                'site_multiplicity': vac.multiplicity,
                'supercell': {
                    'size': sc_scale,
                    'structure': vac_sc
                },
                'charges': charges_vac
            })

        if antisites_flag:
            for as_specie in set(struct_species):
                SG = SubstitutionGenerator(self.struct, as_specie)
                for i, sub in enumerate(SG):
                    as_symbol = as_specie.symbol
                    as_sc = sub.generate_defect_structure(sc_scale)

                    # create a trivial defect structure to find where supercell transformation moves the defect
                    struct_for_defect_site = Structure(
                        sub.bulk_structure.copy().lattice, [sub.site.specie],
                        [sub.site.frac_coords],
                        to_unit_cell=True,
                        coords_are_cartesian=False)
                    struct_for_defect_site.make_supercell(sc_scale)
                    as_sc_site = struct_for_defect_site[0]

                    #get bulk_site (non sc)
                    poss_deflist = sorted(
                        sub.bulk_structure.get_sites_in_sphere(
                            sub.site.coords, 0.01, include_index=True),
                        key=lambda x: x[1])
                    if not len(poss_deflist):
                        raise ValueError(
                            "Could not find substitution site inside bulk structure for {}?"
                            .format(sub.name))
                    defindex = poss_deflist[0][2]
                    as_site = sub.bulk_structure[defindex]
                    vac_symbol = as_site.specie

                    charges_as = self.defect_charger.get_charges(
                        'antisite', vac_symbol, as_symbol)

                    as_defs.append({
                        'name':
                        "as_{}_{}_on_{}".format(i + 1, as_symbol, vac_symbol),
                        'unique_site':
                        as_site,
                        'bulk_supercell_site':
                        as_sc_site,
                        'defect_type':
                        'antisite',
                        'site_specie':
                        vac_symbol,
                        'substitution_specie':
                        as_symbol,
                        'site_multiplicity':
                        sub.multiplicity,
                        'supercell': {
                            'size': sc_scale,
                            'structure': as_sc
                        },
                        'charges':
                        charges_as
                    })

        for vac_symbol, subspecie_list in self.substitutions.items():
            for subspecie_symbol in subspecie_list:
                SG = SubstitutionGenerator(self.struct, subspecie_symbol)
                for i, sub in enumerate(SG):
                    sub_symbol = sub.site.specie.symbol

                    #get bulk_site (non sc)
                    poss_deflist = sorted(
                        sub.bulk_structure.get_sites_in_sphere(
                            sub.site.coords, 0.1, include_index=True),
                        key=lambda x: x[1])
                    if not len(poss_deflist):
                        raise ValueError(
                            "Could not find substitution site inside bulk structure for {}?"
                            .format(sub.name))
                    defindex = poss_deflist[0][2]
                    sub_site = self.struct[defindex]
                    this_vac_symbol = sub_site.specie.symbol

                    if (sub_symbol != subspecie_symbol) or (this_vac_symbol !=
                                                            vac_symbol):
                        continue
                    else:
                        sub_sc = sub.generate_defect_structure(sc_scale)

                        # create a trivial defect structure to find where supercell transformation moves the defect
                        struct_for_defect_site = Structure(
                            sub.bulk_structure.copy().lattice,
                            [sub.site.specie], [sub.site.frac_coords],
                            to_unit_cell=True,
                            coords_are_cartesian=False)
                        struct_for_defect_site.make_supercell(sc_scale)
                        sub_sc_site = struct_for_defect_site[0]

                        charges_sub = self.defect_charger.get_charges(
                            'substitution', vac_symbol, subspecie_symbol)
                        sub_defs.append({
                            'name':
                            "sub_{}_{}_on_{}".format(i + 1, subspecie_symbol,
                                                     vac_symbol),
                            'unique_site':
                            sub_site,
                            'bulk_supercell_site':
                            sub_sc_site,
                            'defect_type':
                            'substitution',
                            'site_specie':
                            vac_symbol,
                            'substitution_specie':
                            subspecie_symbol,
                            'site_multiplicity':
                            sub.multiplicity,
                            'supercell': {
                                'size': sc_scale,
                                'structure': sub_sc
                            },
                            'charges':
                            charges_sub
                        })

        self.defects['vacancies'] = vacancies
        self.defects['substitutions'] = sub_defs
        self.defects['substitutions'] += as_defs

        if include_interstitials:
            interstitials = []

            if interstitial_elements:
                inter_elems = interstitial_elements
            else:
                inter_elems = [elem.symbol for elem in \
                        self.struct.composition.elements]
            if len(inter_elems) == 0:
                raise RuntimeError("empty element list for interstitials")

            if intersites:
                #manual specification of interstitials
                for i, intersite in enumerate(intersites):
                    for elt in inter_elems:
                        name = "inter_{}_{}".format(i + 1, elt)

                        if intersite.lattice != self.struct.lattice:
                            err_msg = "Lattice matching error occurs between provided interstitial and the bulk structure."
                            if standardized:
                                err_msg += "\nLikely because the standardized flag was used. Turn this flag off or reset " \
                                           "your interstitial PeriodicSite to match the standardized form of the bulk structure."
                            raise ValueError(err_msg)
                        else:
                            intersite_object = Interstitial(
                                self.struct, intersite)

                        # create a trivial defect structure to find where supercell transformation moves the defect site
                        struct_for_defect_site = Structure(
                            intersite_object.bulk_structure.copy().lattice,
                            [intersite_object.site.specie],
                            [intersite_object.site.frac_coords],
                            to_unit_cell=True,
                            coords_are_cartesian=False)
                        struct_for_defect_site.make_supercell(sc_scale)
                        site_sc = struct_for_defect_site[0]

                        sc_with_inter = intersite_object.generate_defect_structure(
                            sc_scale)
                        charges_inter = self.defect_charger.get_charges(
                            'interstitial', elt)

                        interstitials.append({
                            'name':
                            name,
                            'unique_site':
                            intersite_object.site,
                            'bulk_supercell_site':
                            site_sc,
                            'defect_type':
                            'interstitial',
                            'site_specie':
                            intersite_object.site.specie.symbol,
                            'site_multiplicity':
                            intersite_object.multiplicity,
                            'supercell': {
                                'size': sc_scale,
                                'structure': sc_with_inter
                            },
                            'charges':
                            charges_inter
                        })

            else:
                print(
                    "Searching for interstitial sites (this can take awhile)..."
                )
                for elt in inter_elems:
                    #TODO: Add ability to use other interstitial finding methods in pymatgen
                    IG = InterstitialGenerator(self.struct, elt)
                    for i, intersite_object in enumerate(IG):
                        name = intersite_object.name

                        # create a trivial defect structure to find where supercell transformation moves the defect site
                        struct_for_defect_site = Structure(
                            intersite_object.bulk_structure.copy().lattice,
                            [intersite_object.site.specie],
                            [intersite_object.site.frac_coords],
                            to_unit_cell=True,
                            coords_are_cartesian=False)
                        struct_for_defect_site.make_supercell(sc_scale)
                        site_sc = struct_for_defect_site[0]

                        sc_with_inter = intersite_object.generate_defect_structure(
                            sc_scale)
                        charges_inter = self.defect_charger.get_charges(
                            'interstitial', elt)

                        interstitials.append({
                            'name':
                            "inter_{}_{}".format(
                                i + 1, elt),  #TODO fix naming convention
                            'unique_site':
                            intersite_object.site,
                            'bulk_supercell_site':
                            site_sc,
                            'defect_type':
                            'interstitial',
                            'site_specie':
                            intersite_object.site.specie.symbol,
                            'site_multiplicity':
                            intersite_object.multiplicity,
                            'supercell': {
                                'size': sc_scale,
                                'structure': sc_with_inter
                            },
                            'charges':
                            charges_inter
                        })

            self.defects['interstitials'] = interstitials

        print("\nNumber of jobs created:")
        tottmp = 0
        for j in self.defects.keys():
            if j == 'bulk':
                print("    bulk = 1")
                tottmp += 1
            else:
                print("    {}:".format(j))
                for lis in self.defects[j]:
                    print("        {} = {}".format(lis['name'],
                                                   len(lis['charges'])))
                    tottmp += len(lis['charges'])
        print("Total (non dielectric) jobs created = {}\n".format(tottmp))
Example #15
0
    def test_interstitial(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1],
                                struc.lattice)
        interstitial = Interstitial(struc, int_site)

        # test generation and super cell
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4})
        # Ensure the site is in the right place
        self.assertEqual(
            int_site,
            int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0])

        int_struc = interstitial.generate_defect_structure(2)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32})

        int_struc = interstitial.generate_defect_structure(3)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108})

        int_struc = interstitial.generate_defect_structure([[2., 0, 0],
                                                            [0, 0, -3.],
                                                            [0, 2., 0]])
        self.assertEqual(int_struc.composition.as_dict(), {"V": 25, "O": 48})

        # test charge
        interstitial = Interstitial(struc, int_site)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 0.0)

        interstitial = Interstitial(struc, int_site, charge=1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 1.0)

        interstitial = Interstitial(struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, -1.0)

        # test multiplicity
        interstitial = Interstitial(struc, int_site)
        self.assertEqual(interstitial.multiplicity, 8.0)

        # test manual setting of multiplicity
        interstitial = Interstitial(struc, int_site, multiplicity=4.0)
        self.assertEqual(interstitial.multiplicity, 4.0)

        # Test composoition
        self.assertEqual(dict(interstitial.defect_composition.as_dict()), {
            "V": 3,
            "O": 4
        })

        # test that structure has all velocities equal if velocities previously existed
        # (previously caused failures for structure printing)
        vel_struc = Structure(
            struc.lattice,
            struc.species,
            struc.frac_coords,
            site_properties={'velocities': [[0., 0., 0.]] * len(struc)})
        interstitial = Interstitial(vel_struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)

        self.assertTrue(
            (np.array(int_struc.site_properties['velocities']) == 0.).all())
        self.assertEqual(len(int_struc.site_properties['velocities']),
                         len(int_struc))
    def test_check_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55
        defect_frac_sc_coords = self.vac.site.frac_coords[:]

        params = {
            "initial_defect_structure": initial_defect_structure,
            "final_defect_structure": final_defect_structure,
            "sampling_radius": sampling_radius,
            "defect_frac_sc_coords": defect_frac_sc_coords,
            "is_compatible": True,
        }
        dentry = DefectEntry(self.vac, 0.0, corrections={}, parameters=params, entry_id=None)

        dc = DefectCompatibility(tot_relax_tol=0.1, perc_relax_tol=0.1, defect_tot_relax_tol=0.1)
        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters["delocalization_meta"]["structure_relax"]
        self.assertTrue(dentry.parameters["is_compatible"])
        self.assertTrue(struc_delocal["is_compatible"])
        self.assertTrue(struc_delocal["metadata"]["structure_tot_relax_compatible"])
        self.assertEqual(struc_delocal["metadata"]["tot_relax_outside_rad"], 0.0)
        self.assertTrue(struc_delocal["metadata"]["structure_perc_relax_compatible"])
        self.assertEqual(struc_delocal["metadata"]["perc_relax_outside_rad"], 0.0)
        self.assertEqual(
            len(struc_delocal["metadata"]["full_structure_relax_data"]),
            len(initial_defect_structure),
        )
        self.assertIsNone(struc_delocal["metadata"]["defect_index"])

        defect_delocal = dentry.parameters["delocalization_meta"]["defectsite_relax"]
        self.assertTrue(defect_delocal["is_compatible"])
        self.assertIsNone(defect_delocal["metadata"]["relax_amount"])

        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb(0.1)
        dentry.parameters.update({"final_defect_structure": pert_struct_fin_struct})
        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters["delocalization_meta"]["structure_relax"]
        self.assertFalse(dentry.parameters["is_compatible"])
        self.assertFalse(struc_delocal["is_compatible"])
        self.assertFalse(struc_delocal["metadata"]["structure_tot_relax_compatible"])
        self.assertAlmostEqual(struc_delocal["metadata"]["tot_relax_outside_rad"], 12.5)
        self.assertFalse(struc_delocal["metadata"]["structure_perc_relax_compatible"])
        self.assertAlmostEqual(struc_delocal["metadata"]["perc_relax_outside_rad"], 77.63975155)

        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite(
            "H",
            [7.58857304, 11.70848069, 12.97817518],
            self.vac.bulk_structure.lattice,
            to_unit_cell=True,
            coords_are_cartesian=True,
        )
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(
            final_defect_structure.get_sites_in_sphere(inter.site.coords, 2, include_index=True),
            key=lambda x: x[1],
        )
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(
            indices=[def_index], vector=[0.0, 0.0, 0.008]
        )  # fractional coords translation
        defect_frac_sc_coords = inter_def_site.frac_coords[:]

        params = {
            "initial_defect_structure": initial_defect_structure,
            "final_defect_structure": final_defect_structure,
            "sampling_radius": sampling_radius,
            "defect_frac_sc_coords": defect_frac_sc_coords,
            "is_compatible": True,
        }
        dentry = DefectEntry(inter, 0.0, corrections={}, parameters=params, entry_id=None)

        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        defect_delocal = dentry.parameters["delocalization_meta"]["defectsite_relax"]
        self.assertFalse(defect_delocal["is_compatible"])
        self.assertAlmostEqual(defect_delocal["metadata"]["relax_amount"], 0.10836054)
Example #17
0
    def test_interstitial(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1], struc.lattice)
        interstitial = Interstitial(struc, int_site)

        # test generation and super cell
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4})
        # Ensure the site is in the right place
        self.assertEqual(int_site, int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0])

        int_struc = interstitial.generate_defect_structure(2)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32})

        int_struc = interstitial.generate_defect_structure(3)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108})

        int_struc = interstitial.generate_defect_structure([[2., 0, 0], [0, 0, -3.], [0, 2., 0]])
        self.assertEqual(int_struc.composition.as_dict(), {"V": 25, "O": 48})

        # test charge
        interstitial = Interstitial(struc, int_site)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 0.0)

        interstitial = Interstitial(struc, int_site, charge=1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 1.0)

        interstitial = Interstitial(struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, -1.0)

        # test multiplicity
        interstitial = Interstitial(struc, int_site)
        self.assertEqual(interstitial.multiplicity, 1.0)

        interstitial = Interstitial(struc, int_site, multiplicity=4.0)
        self.assertEqual(interstitial.multiplicity, 4.0)

        # Test composoition
        self.assertEqual(dict(interstitial.defect_composition.as_dict()), {"V": 3, "O": 4})

        # test that structure has all velocities equal if velocities previously existed
        # (previously caused failures for structure printing)
        vel_struc = Structure( struc.lattice, struc.species, struc.frac_coords,
                               site_properties= {'velocities': [[0., 0., 0.]]*len(struc) } )
        interstitial = Interstitial(vel_struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)

        self.assertTrue( (np.array(int_struc.site_properties['velocities']) == 0.).all())
        self.assertEqual( len(int_struc.site_properties['velocities']), len(int_struc))
Example #18
0
    def test_defect_matching(self):
        # SETUP DEFECTS FOR TESTING
        # symmorphic defect test set
        s_struc = Structure.from_file(os.path.join(
            test_dir, "CsSnI3.cif"))  # tetragonal CsSnI3
        identical_Cs_vacs = [
            Vacancy(s_struc, s_struc[0]),
            Vacancy(s_struc, s_struc[1])
        ]
        identical_I_vacs_sublattice1 = [
            Vacancy(s_struc, s_struc[4]),
            Vacancy(s_struc, s_struc[5]),
            Vacancy(s_struc, s_struc[8]),
            Vacancy(s_struc, s_struc[9])
        ]  # in plane halides
        identical_I_vacs_sublattice2 = [
            Vacancy(s_struc, s_struc[6]),
            Vacancy(s_struc, s_struc[7])
        ]  # out of plane halides
        pdc = PointDefectComparator()

        # NOW TEST DEFECTS
        # test vacancy matching
        self.assertTrue(
            pdc.are_equal(identical_Cs_vacs[0],
                          identical_Cs_vacs[0]))  # trivial vacancy test
        self.assertTrue(
            pdc.are_equal(
                identical_Cs_vacs[0],
                identical_Cs_vacs[1]))  # vacancies on same sublattice
        for i, j in itertools.combinations(range(4), 2):
            self.assertTrue(
                pdc.are_equal(identical_I_vacs_sublattice1[i],
                              identical_I_vacs_sublattice1[j]))
        self.assertTrue(
            pdc.are_equal(identical_I_vacs_sublattice2[0],
                          identical_I_vacs_sublattice2[1]))
        self.assertFalse(
            pdc.are_equal(
                identical_Cs_vacs[
                    0],  # both vacancies, but different specie types
                identical_I_vacs_sublattice1[0]))
        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # same specie type, different sublattice
                identical_I_vacs_sublattice2[0]))

        # test substitutional matching
        sub_Cs_on_I_sublattice1_set1 = PeriodicSite(
            'Cs', identical_I_vacs_sublattice1[0].site.frac_coords,
            s_struc.lattice)
        sub_Cs_on_I_sublattice1_set2 = PeriodicSite(
            'Cs', identical_I_vacs_sublattice1[1].site.frac_coords,
            s_struc.lattice)
        sub_Cs_on_I_sublattice2 = PeriodicSite(
            'Cs', identical_I_vacs_sublattice2[0].site.frac_coords,
            s_struc.lattice)
        sub_Rb_on_I_sublattice2 = PeriodicSite(
            'Rb', identical_I_vacs_sublattice2[0].site.frac_coords,
            s_struc.lattice)

        self.assertTrue(
            pdc.are_equal(  # trivial substitution test
                Substitution(s_struc, sub_Cs_on_I_sublattice1_set1),
                Substitution(s_struc, sub_Cs_on_I_sublattice1_set1)))

        self.assertTrue(
            pdc.are_equal(  # same sublattice, different coords
                Substitution(s_struc, sub_Cs_on_I_sublattice1_set1),
                Substitution(s_struc, sub_Cs_on_I_sublattice1_set2)))
        self.assertFalse(
            pdc.are_equal(  # different subs (wrong specie)
                Substitution(s_struc, sub_Cs_on_I_sublattice2),
                Substitution(s_struc, sub_Rb_on_I_sublattice2)))
        self.assertFalse(
            pdc.are_equal(  # different subs (wrong sublattice)
                Substitution(s_struc, sub_Cs_on_I_sublattice1_set1),
                Substitution(s_struc, sub_Cs_on_I_sublattice2)))

        # test symmorphic interstitial matching
        # (using set generated from Voronoi generator, with same sublattice given by saturatated_interstitial_structure function)
        inter_H_sublattice1_set1 = PeriodicSite('H', [0., 0.75, 0.25],
                                                s_struc.lattice)
        inter_H_sublattice1_set2 = PeriodicSite('H', [0., 0.75, 0.75],
                                                s_struc.lattice)
        inter_H_sublattice2 = PeriodicSite(
            'H', [0.57796112, 0.06923687, 0.56923687], s_struc.lattice)
        inter_H_sublattice3 = PeriodicSite('H', [0.25, 0.25, 0.54018268],
                                           s_struc.lattice)
        inter_He_sublattice3 = PeriodicSite('He', [0.25, 0.25, 0.54018268],
                                            s_struc.lattice)

        self.assertTrue(
            pdc.are_equal(  # trivial interstitial test
                Interstitial(s_struc, inter_H_sublattice1_set1),
                Interstitial(s_struc, inter_H_sublattice1_set1)))

        self.assertTrue(
            pdc.are_equal(  # same sublattice, different coords
                Interstitial(s_struc, inter_H_sublattice1_set1),
                Interstitial(s_struc, inter_H_sublattice1_set2)))
        self.assertFalse(
            pdc.are_equal(  # different interstitials (wrong sublattice)
                Interstitial(s_struc, inter_H_sublattice1_set1),
                Interstitial(s_struc, inter_H_sublattice2)))
        self.assertFalse(
            pdc.are_equal(  # different interstitials (wrong sublattice)
                Interstitial(s_struc, inter_H_sublattice1_set1),
                Interstitial(s_struc, inter_H_sublattice3)))
        self.assertFalse(
            pdc.are_equal(  # different interstitials (wrong specie)
                Interstitial(s_struc, inter_H_sublattice3),
                Interstitial(s_struc, inter_He_sublattice3)))

        # test non-symmorphic interstitial matching
        # (using set generated from Voronoi generator, with same sublattice given by saturatated_interstitial_structure function)
        ns_struc = Structure.from_file(os.path.join(test_dir, "CuCl.cif"))
        ns_inter_H_sublattice1_set1 = PeriodicSite(
            'H', [0.06924513, 0.06308959, 0.86766528], ns_struc.lattice)
        ns_inter_H_sublattice1_set2 = PeriodicSite(
            'H', [0.43691041, 0.36766528, 0.06924513], ns_struc.lattice)
        ns_inter_H_sublattice2 = PeriodicSite(
            'H', [0.06022109, 0.60196031, 0.1621814], ns_struc.lattice)
        ns_inter_He_sublattice2 = PeriodicSite(
            'He', [0.06022109, 0.60196031, 0.1621814], ns_struc.lattice)

        self.assertTrue(
            pdc.are_equal(  # trivial interstitial test
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1),
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1)))
        self.assertTrue(
            pdc.are_equal(  # same sublattice, different coords
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1),
                Interstitial(ns_struc, ns_inter_H_sublattice1_set2)))
        self.assertFalse(
            pdc.are_equal(
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1
                             ),  # different interstitials (wrong sublattice)
                Interstitial(ns_struc, ns_inter_H_sublattice2)))
        self.assertFalse(
            pdc.are_equal(  # different interstitials (wrong specie)
                Interstitial(ns_struc, ns_inter_H_sublattice2),
                Interstitial(ns_struc, ns_inter_He_sublattice2)))

        # test influence of charge on defect matching (default is to be charge agnostic)
        vac_diff_chg = identical_Cs_vacs[0].copy()
        vac_diff_chg.set_charge(3.)
        self.assertTrue(pdc.are_equal(identical_Cs_vacs[0], vac_diff_chg))
        chargecheck_pdc = PointDefectComparator(
            check_charge=True)  # switch to PDC which cares about charge state
        self.assertFalse(
            chargecheck_pdc.are_equal(identical_Cs_vacs[0], vac_diff_chg))

        # test different supercell size
        # (comparing same defect but different supercells - default is to not check for this)
        sc_agnostic_pdc = PointDefectComparator(check_primitive_cell=True)
        sc_scaled_s_struc = s_struc.copy()
        sc_scaled_s_struc.make_supercell([2, 2, 3])
        sc_scaled_I_vac_sublatt1_ps1 = PeriodicSite(
            'I',
            identical_I_vacs_sublattice1[0].site.coords,
            sc_scaled_s_struc.lattice,
            coords_are_cartesian=True)
        sc_scaled_I_vac_sublatt1_ps2 = PeriodicSite(
            'I',
            identical_I_vacs_sublattice1[1].site.coords,
            sc_scaled_s_struc.lattice,
            coords_are_cartesian=True)
        sc_scaled_I_vac_sublatt2_ps = PeriodicSite(
            'I',
            identical_I_vacs_sublattice2[1].site.coords,
            sc_scaled_s_struc.lattice,
            coords_are_cartesian=True)
        sc_scaled_I_vac_sublatt1_defect1 = Vacancy(
            sc_scaled_s_struc, sc_scaled_I_vac_sublatt1_ps1)
        sc_scaled_I_vac_sublatt1_defect2 = Vacancy(
            sc_scaled_s_struc, sc_scaled_I_vac_sublatt1_ps2)
        sc_scaled_I_vac_sublatt2_defect = Vacancy(sc_scaled_s_struc,
                                                  sc_scaled_I_vac_sublatt2_ps)

        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # trivially same defect site but between different supercells
                sc_scaled_I_vac_sublatt1_defect1))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(identical_I_vacs_sublattice1[0],
                                      sc_scaled_I_vac_sublatt1_defect1))
        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    1],  # same coords, different lattice structure
                sc_scaled_I_vac_sublatt1_defect1))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(identical_I_vacs_sublattice1[1],
                                      sc_scaled_I_vac_sublatt1_defect1))
        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # same sublattice, different coords
                sc_scaled_I_vac_sublatt1_defect2))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(identical_I_vacs_sublattice1[0],
                                      sc_scaled_I_vac_sublatt1_defect2))
        self.assertFalse(
            sc_agnostic_pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # different defects (wrong sublattice)
                sc_scaled_I_vac_sublatt2_defect))

        # test same structure size, but scaled lattice volume
        # (default is to not allow these to be equal, but check_lattice_scale=True allows for this)
        vol_agnostic_pdc = PointDefectComparator(check_lattice_scale=True)
        vol_scaled_s_struc = s_struc.copy()
        vol_scaled_s_struc.scale_lattice(s_struc.volume * 0.95)
        vol_scaled_I_vac_sublatt1_defect1 = Vacancy(vol_scaled_s_struc,
                                                    vol_scaled_s_struc[4])
        vol_scaled_I_vac_sublatt1_defect2 = Vacancy(vol_scaled_s_struc,
                                                    vol_scaled_s_struc[5])
        vol_scaled_I_vac_sublatt2_defect = Vacancy(vol_scaled_s_struc,
                                                   vol_scaled_s_struc[6])

        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # trivially same defect (but vol change)
                vol_scaled_I_vac_sublatt1_defect1))
        self.assertTrue(
            vol_agnostic_pdc.are_equal(identical_I_vacs_sublattice1[0],
                                       vol_scaled_I_vac_sublatt1_defect1))
        self.assertFalse(
            pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # same defect, different sublattice point (and vol change)
                vol_scaled_I_vac_sublatt1_defect2))
        self.assertTrue(
            vol_agnostic_pdc.are_equal(identical_I_vacs_sublattice1[0],
                                       vol_scaled_I_vac_sublatt1_defect2))
        self.assertFalse(
            vol_agnostic_pdc.are_equal(
                identical_I_vacs_sublattice1[
                    0],  # different defect (wrong sublattice)
                vol_scaled_I_vac_sublatt2_defect))

        # test identical defect which has had entire lattice shifted
        shift_s_struc = s_struc.copy()
        shift_s_struc.translate_sites(range(len(s_struc)), [0.2, 0.3, 0.4],
                                      frac_coords=True,
                                      to_unit_cell=True)
        shifted_identical_Cs_vacs = [
            Vacancy(shift_s_struc, shift_s_struc[0]),
            Vacancy(shift_s_struc, shift_s_struc[1])
        ]
        self.assertTrue(
            pdc.are_equal(
                identical_Cs_vacs[0],  # trivially same defect (but shifted)
                shifted_identical_Cs_vacs[0]))
        self.assertTrue(
            pdc.are_equal(
                identical_Cs_vacs[
                    0],  # same defect on different sublattice point (and shifted)
                shifted_identical_Cs_vacs[1]))

        # test uniform lattice shift within non-symmorphic structure
        shift_ns_struc = ns_struc.copy()
        shift_ns_struc.translate_sites(range(len(ns_struc)), [0., 0.6, 0.3],
                                       frac_coords=True,
                                       to_unit_cell=True)

        shift_ns_inter_H_sublattice1_set1 = PeriodicSite(
            'H', ns_inter_H_sublattice1_set1.frac_coords + [0., 0.6, 0.3],
            shift_ns_struc.lattice)
        shift_ns_inter_H_sublattice1_set2 = PeriodicSite(
            'H', ns_inter_H_sublattice1_set2.frac_coords + [0., 0.6, 0.3],
            shift_ns_struc.lattice)
        self.assertTrue(
            pdc.are_equal(
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1
                             ),  # trivially same defect (but shifted)
                Interstitial(shift_ns_struc,
                             shift_ns_inter_H_sublattice1_set1)))
        self.assertTrue(
            pdc.are_equal(
                Interstitial(ns_struc, ns_inter_H_sublattice1_set1),
                # same defect on different sublattice point (and shifted)
                Interstitial(shift_ns_struc,
                             shift_ns_inter_H_sublattice1_set2)))

        # test a rotational + supercell type structure transformation (requires check_primitive_cell=True)
        rotated_s_struc = s_struc.copy()
        rotated_s_struc.make_supercell([[2, 1, 0], [-1, 3, 0], [0, 0, 2]])
        rotated_identical_Cs_vacs = [
            Vacancy(rotated_s_struc, rotated_s_struc[0]),
            Vacancy(rotated_s_struc, rotated_s_struc[1])
        ]
        self.assertFalse(
            pdc.are_equal(
                identical_Cs_vacs[0],  # trivially same defect (but rotated)
                rotated_identical_Cs_vacs[0]))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(identical_Cs_vacs[0],
                                      rotated_identical_Cs_vacs[0]))
        self.assertFalse(
            pdc.are_equal(
                identical_Cs_vacs[
                    0],  # same defect on different sublattice (and rotated)
                rotated_identical_Cs_vacs[1]))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(
                identical_Cs_vacs[
                    0],  # same defect on different sublattice point (and rotated)
                rotated_identical_Cs_vacs[1]))

        # test a rotational + supercell + shift type structure transformation for non-symmorphic structure
        rotANDshift_ns_struc = ns_struc.copy()
        rotANDshift_ns_struc.translate_sites(range(len(ns_struc)),
                                             [0., 0.6, 0.3],
                                             frac_coords=True,
                                             to_unit_cell=True)
        rotANDshift_ns_struc.make_supercell([[2, 1, 0], [-1, 3, 0], [0, 0, 2]])
        ns_vac_Cs_set1 = Vacancy(ns_struc, ns_struc[0])
        rotANDshift_ns_vac_Cs_set1 = Vacancy(rotANDshift_ns_struc,
                                             rotANDshift_ns_struc[0])
        rotANDshift_ns_vac_Cs_set2 = Vacancy(rotANDshift_ns_struc,
                                             rotANDshift_ns_struc[1])

        self.assertTrue(
            sc_agnostic_pdc.are_equal(
                ns_vac_Cs_set1,  # trivially same defect (but rotated and sublattice shifted)
                rotANDshift_ns_vac_Cs_set1))
        self.assertTrue(
            sc_agnostic_pdc.are_equal(
                ns_vac_Cs_set1,  # same defect on different sublattice point (shifted and rotated)
                rotANDshift_ns_vac_Cs_set2))
Example #19
0
    def test_interstitial(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1], struc.lattice)
        interstitial = Interstitial(struc, int_site)

        # test generation and super cell
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4})
        # Ensure the site is in the right place
        self.assertEqual(int_site, int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0])

        int_struc = interstitial.generate_defect_structure(2)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32})

        int_struc = interstitial.generate_defect_structure(3)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108})

        int_struc = interstitial.generate_defect_structure([[2., 0, 0], [0, 0, -3.], [0, 2., 0]])
        self.assertEqual(int_struc.composition.as_dict(), {"V": 25, "O": 48})

        # test charge
        interstitial = Interstitial(struc, int_site)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 0.0)

        interstitial = Interstitial(struc, int_site, charge=1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 1.0)

        interstitial = Interstitial(struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, -1.0)

        # test multiplicity
        interstitial = Interstitial(struc, int_site)
        self.assertEqual(interstitial.multiplicity, 1.0)

        interstitial = Interstitial(struc, int_site, multiplicity=4.0)
        self.assertEqual(interstitial.multiplicity, 4.0)

        # Test composoition
        self.assertEqual(dict(interstitial.defect_composition.as_dict()), {"V": 3, "O": 4})