Esempio n. 1
0
    def test_kumagai(self):
        gamma = 0.19357221
        prec = 28
        lattice = Lattice(
            [[4.692882, -8.12831, 0.0], [4.692882, 8.12831, 0.0], [0.0, 0.0, 10.03391]]
        )

        # note that real/recip vector generation is not dependent on epsilon
        g_vecs, _, r_vecs, _ = generate_R_and_G_vecs(
            gamma, prec, lattice, 80.0 * np.identity(3)
        )

        # test real space summation (bigger for large epsilon)
        kc_high_diel = KumagaiCorrection(80.0 * np.identity(3), gamma=gamma)
        real_sum = kc_high_diel.get_real_summation(gamma, r_vecs[0])
        self.assertAlmostEqual(real_sum, 0.00843104)

        # test recip space summation (bigger for small epsilon)
        kc_low_diel = KumagaiCorrection(0.1 * np.identity(3), gamma=gamma)
        recip_sum = kc_low_diel.get_recip_summation(gamma, g_vecs[0], lattice.volume)
        self.assertAlmostEqual(recip_sum, 0.31117099)

        # test self interaction
        si_corr = kc_low_diel.get_self_interaction(gamma)
        self.assertAlmostEqual(si_corr, -0.54965249)

        # test potenital shift interaction correction
        ps_corr = kc_low_diel.get_potential_shift(gamma, lattice.volume)
        self.assertAlmostEqual(ps_corr, -0.00871593)

        # """Test Defect Entry approach to correction """
        bulk_struc = Poscar.from_file(
            os.path.join(PymatgenTest.TEST_FILES_DIR, "defect", "CONTCAR_bulk")
        ).structure
        bulk_out = Outcar(os.path.join(PymatgenTest.TEST_FILES_DIR, "defect", "OUTCAR_bulk.gz"))
        defect_out = Outcar(os.path.join(PymatgenTest.TEST_FILES_DIR, "defect", "OUTCAR_vac_Ga_-3.gz"))
        epsilon = 18.118 * np.identity(3)
        vac = Vacancy(bulk_struc, bulk_struc.sites[0], charge=-3)
        defect_structure = vac.generate_defect_structure()
        defect_frac_coords = [0.0, 0.0, 0.0]

        parameters = {
            "bulk_atomic_site_averages": bulk_out.electrostatic_potential,
            "defect_atomic_site_averages": defect_out.electrostatic_potential,
            "site_matching_indices": [[ind, ind - 1] for ind in range(len(bulk_struc))],
            "initial_defect_structure": defect_structure,
            "defect_frac_sc_coords": defect_frac_coords,
        }
        dentry = DefectEntry(vac, 0.0, parameters=parameters)
        kc = KumagaiCorrection(epsilon)
        kcorr = kc.get_correction(dentry)
        self.assertAlmostEqual(kcorr["kumagai_electrostatic"], 0.88236299)
        self.assertAlmostEqual(kcorr["kumagai_potential_alignment"], 2.09704862)

        # test ES correction
        high_diel_es_corr = kc_high_diel.perform_es_corr(gamma, prec, lattice, -3.0)
        self.assertAlmostEqual(high_diel_es_corr, 0.25176240)

        low_diel_es_corr = kc_low_diel.perform_es_corr(gamma, prec, lattice, -3.0)
        self.assertAlmostEqual(low_diel_es_corr, 201.28810966)

        # test pot correction
        site_list = []
        for bs_ind, ds_ind in dentry.parameters["site_matching_indices"]:
            Vqb = -(
                defect_out.electrostatic_potential[ds_ind]
                - bulk_out.electrostatic_potential[bs_ind]
            )
            site_list.append([defect_structure[ds_ind], Vqb])

        sampling_radius = dentry.parameters["kumagai_meta"]["sampling_radius"]
        gamma = dentry.parameters["kumagai_meta"]["gamma"]
        q = -3
        g_vecs, _, r_vecs, _ = generate_R_and_G_vecs(
            gamma, 28, defect_structure.lattice, np.identity(3)
        )
        high_diel_pot_corr = kc_high_diel.perform_pot_corr(
            defect_structure,
            defect_frac_coords,
            site_list,
            sampling_radius,
            q,
            r_vecs[0],
            g_vecs[0],
            gamma,
        )
        self.assertAlmostEqual(high_diel_pot_corr, 2.35840716)
        low_diel_pot_corr = kc_low_diel.perform_pot_corr(
            defect_structure,
            defect_frac_coords,
            site_list,
            sampling_radius,
            q,
            r_vecs[0],
            g_vecs[0],
            gamma,
        )
        self.assertAlmostEqual(low_diel_pot_corr, -58.83598095)

        # test the kumagai plotter
        kcp = kc.plot()
        self.assertTrue(kcp)

        # check that uncertainty metadata exists
        self.assertAlmostEqual(
            set(kc.metadata["pot_corr_uncertainty_md"].keys()),
            set(["number_sampled", "stats"]),
        )
Esempio n. 2
0
def get_kumagai_correction(structure_defect,structure_bulk,path_to_defect_outcar,path_to_bulk_outcar,dielectric_tensor,
                           charge,defect_type=None,defect_specie=None,defect_site=None,sampling_radius=None,gamma=None,
                           get_plot=False):
    """
    Get Kumagai correction with Pymatgen.

    Parameters
    ----------
    structure_defect : (Structure)
        Structure of defect.
    structure_bulk : (Structure)
        Bulk structure.
    path_to_defect_outcar : (str)
        Path to OUTCAR of defect calculation.
    path_to_bulk_outcar : (str)
        Path to OUTCAR of pure calculation.
    dielectric_tensor : (array or float)
        Dielectric tensor, if is a float a diagonal matrix is constructed.
    charge : (int or float)
        Charge of the defect.
    defect_type : (str), optional
        Type of defect ('Vacancy','Interstitial' or 'Substitution')
        If None it's determined with defect_finder. The default is None.
    defect_specie : (str), optional
        Symbol of the defect specie.
        If None it's determined with defect_finder. The default is None.
    defect_site : (Site), optional
        Site of defect. If None it's determined with defect_finder. The default is None.
    sampling_radius (float): radius (in Angstrom) which sites must be outside
        of to be included in the correction. Publication by Kumagai advises to
        use Wigner-Seitz radius of defect supercell, so this is default value.
    gamma (float): convergence parameter for gamma function.
                    Code will automatically determine this if set to None.
    get_plot : (bool), optional
        Get Matplotlib object with plot. The default is False.

    Returns
    -------
    corr : (dict or tuple)
        Dictionary with corrections, if get_plot is True a tuple with dict and plt object is returned.
    """
    
    if not defect_site and not defect_type and not defect_specie:
        defect_site, defect_type = defect_finder(structure_defect, structure_bulk)
        defect_specie = defect_site.specie.symbol
   
    site_matching_indices = []
    for site in structure_defect:
        site_in_str ,index_bulk = is_site_in_structure(site, structure_bulk)
        if site_in_str:
            site_matching_indices.append([index_bulk,structure_defect.index(site)])
        else:
            print(f'Warning in Kumagai corrections: Site {site} is not in bulk structure')
    
    bulk_atomic_site_averages = Outcar(op.join(path_to_bulk_outcar,'OUTCAR')).read_avg_core_poten()[-1]
    defect_atomic_site_averages = Outcar(op.join(path_to_defect_outcar,'OUTCAR')).read_avg_core_poten()[0]
    defect_frac_sc_coords = defect_site.frac_coords
    initial_defect_structure = structure_defect
    
    parameters = {}
    parameters['bulk_atomic_site_averages'] = bulk_atomic_site_averages
    parameters['defect_atomic_site_averages'] = defect_atomic_site_averages
    parameters['site_matching_indices'] = site_matching_indices
    parameters['initial_defect_structure'] = initial_defect_structure
    parameters['defect_frac_sc_coords'] = defect_frac_sc_coords
    
    module = importlib.import_module("pymatgen.analysis.defects.core")
    defect_class = getattr(module,defect_type)
    defect = defect_class(structure_bulk, defect_site, charge=charge, multiplicity=None)
    defect_entry = DefectEntry(defect,None,corrections=None,parameters=parameters)

    kumagai = KumagaiCorrection(dielectric_tensor,sampling_radius,gamma)
    kumagai_corrections = kumagai.get_correction(defect_entry)
    
    if get_plot:
        plt = kumagai.plot()
        return kumagai_corrections , plt
    else:    
        return kumagai_corrections
def get_correction_kumagai(defect_entry, epsilon, title=None, partflag='All'):
    """
    Function to compute the Kumagai correction for each defect (modified freysoldt for anisotropic dielectric).
    NOTE that bulk_init class must be pre-instantiated to use this function
    Args:
        defect_entry: DefectEntry object with the following
            keys stored in defect.parameters:
                required:
                    bulk_atomic_site_averages (list):  list of bulk structure"s atomic site averaged ESPs * charge,
                        in same order as indices of bulk structure
                        note this is list given by VASP's OUTCAR (so it is multiplied by a test charge of -1)

                    defect_atomic_site_averages (list):  list of defect structure"s atomic site averaged ESPs * charge,
                        in same order as indices of defect structure
                        note this is list given by VASP's OUTCAR (so it is multiplied by a test charge of -1)

                    site_matching_indices (list):  list of corresponding site index values for
                        bulk and defect site structures EXCLUDING the defect site itself
                        (ex. [[bulk structure site index, defect structure"s corresponding site index], ... ]

                    initial_defect_structure (Structure): Pymatgen Structure object representing un-relaxed defect structure

                    defect_frac_sc_coords (array): Defect Position in fractional coordinates of the supercell
                        given in bulk_structure
                optional:
                    gamma (float): Ewald parameter, Default is to determine it based on convergence of
                        brute summation tolerance
                    sampling_radius (float):r adius (in Angstrom) which sites must be outside of to be included
                        in the correction. Publication by Kumagai advises to use Wigner-Seitz radius of
                        defect supercell, so this is default value.
        epsilon (float or 3x3 matrix): Dielectric constant for the structure
        title: decides whether to plot electrostatic potential plots or not...
            if None, no plot is printed, if a string,
            then the plot will be saved using the string
        partflag: four options for correction output:
               'pc' for just point charge correction, or
               'potalign' for just potalign correction, or
               'All' for both (added together), or
               'AllSplit' for individual parts split up (form is [PC, potterm, full])
    """
    if partflag not in ['All', 'AllSplit', 'pc', 'potalign']:
        print(
            '{} is incorrect potalign type. Must be "All", "AllSplit", "pc", or '
            '"potalign".'.format(partflag))
        return

    sampling_radius = defect_entry.parameters.get('sampling_radius', None)
    gamma = defect_entry.parameters.get('gamma', None)

    if not defect_entry.charge:
        print('charge is zero so charge correction is zero')
        return 0.

    template_defect = defect_entry.copy()
    corr_class = KumagaiCorrection(epsilon,
                                   sampling_radius=sampling_radius,
                                   gamma=gamma)
    k_corr_summ = corr_class.get_correction(template_defect)

    if title:
        p = corr_class.plot(title="Kumagai", saved=False)
        p.savefig(title + '_kumagaiplot.pdf', bbox_inches='tight')

    if partflag in ['AllSplit', 'All']:
        kumagai_val = np.sum(list(k_corr_summ.values()))
    elif partflag == 'pc':
        kumagai_val = k_corr_summ['kumagai_electrostatic']
    elif partflag == 'potalign':
        kumagai_val = k_corr_summ['kumagai_potential_alignment']

    print('\n Final Kumagai correction is {}'.format(kumagai_val))

    if partflag == 'AllSplit':
        kumagai_val = [
            k_corr_summ['kumagai_electrostatic'],
            k_corr_summ['kumagai_potential_alignment'], kumagai_val
        ]
    return kumagai_val
    def test_kumagai(self):
        gamma = 0.19357221
        prec = 28
        lattice = Lattice( [[ 4.692882, -8.12831 ,  0.],
                            [ 4.692882,  8.12831 ,  0.],
                            [ 0.,  0., 10.03391 ]])

        #note that real/recip vector generation is not dependent on epsilon
        g_vecs, _, r_vecs, _ = generate_R_and_G_vecs( gamma, prec, lattice, 80. * np.identity(3))

        #test real space summation (bigger for large epsilon)
        kc_high_diel = KumagaiCorrection( 80. * np.identity(3), gamma=gamma)
        real_sum = kc_high_diel.get_real_summation( gamma, r_vecs[0])
        self.assertAlmostEqual( real_sum, 0.00843104)

        #test recip space summation (bigger for small epsilon)
        kc_low_diel = KumagaiCorrection( 0.1 * np.identity(3), gamma=gamma)
        recip_sum = kc_low_diel.get_recip_summation( gamma, g_vecs[0], lattice.volume)
        self.assertAlmostEqual( recip_sum, 0.31117099)

        #test self interaction
        si_corr = kc_low_diel.get_self_interaction( gamma)
        self.assertAlmostEqual( si_corr, -0.54965249)

        #test potenital shift interaction correction
        ps_corr = kc_low_diel.get_potential_shift( gamma, lattice.volume)
        self.assertAlmostEqual( ps_corr, -0.00871593)

        # """Test Defect Entry approach to correction """
        bulk_struc = Poscar.from_file(os.path.join( test_dir, 'defect', 'CONTCAR_bulk')).structure
        bulk_out = Outcar( os.path.join( test_dir, 'defect', 'OUTCAR_bulk.gz'))
        defect_out = Outcar( os.path.join( test_dir, 'defect', 'OUTCAR_vac_Ga_-3.gz'))
        epsilon = 18.118 * np.identity(3)
        vac = Vacancy(bulk_struc, bulk_struc.sites[0], charge=-3)
        defect_structure = vac.generate_defect_structure()
        defect_frac_coords = [0.,0.,0.]

        parameters = {'bulk_atomic_site_averages': bulk_out.electrostatic_potential,
                      'defect_atomic_site_averages': defect_out.electrostatic_potential,
                      'site_matching_indices': [[ind, ind-1] for ind in range(len(bulk_struc))],
                      'initial_defect_structure': defect_structure,
                      'defect_frac_sc_coords': defect_frac_coords}
        dentry = DefectEntry( vac, 0., parameters=parameters)
        kc = KumagaiCorrection( epsilon)
        kcorr = kc.get_correction( dentry)
        self.assertAlmostEqual( kcorr['kumagai_electrostatic'], 0.88236299)
        self.assertAlmostEqual( kcorr['kumagai_potential_alignment'], 2.09704862)

        # test ES correction
        high_diel_es_corr = kc_high_diel.perform_es_corr( gamma, prec, lattice, -3.)
        self.assertAlmostEqual( high_diel_es_corr, 0.25176240)

        low_diel_es_corr = kc_low_diel.perform_es_corr( gamma, prec, lattice, -3.)
        self.assertAlmostEqual( low_diel_es_corr, 201.28810966)

        # test pot correction
        site_list = []
        for bs_ind, ds_ind in dentry.parameters['site_matching_indices']:
            Vqb = -(defect_out.electrostatic_potential[ds_ind] - bulk_out.electrostatic_potential[bs_ind])
            site_list.append([defect_structure[ds_ind], Vqb])

        sampling_radius = dentry.parameters["kumagai_meta"]["sampling_radius"]
        gamma = dentry.parameters["kumagai_meta"]["gamma"]
        q = -3
        g_vecs, _, r_vecs, _ = generate_R_and_G_vecs( gamma, 28, defect_structure.lattice, np.identity(3))
        high_diel_pot_corr  = kc_high_diel.perform_pot_corr( defect_structure, defect_frac_coords,
                                                             site_list, sampling_radius, q,
                                                             r_vecs[0], g_vecs[0], gamma)
        self.assertAlmostEqual( high_diel_pot_corr, 2.35840716)
        low_diel_pot_corr  = kc_low_diel.perform_pot_corr( defect_structure, defect_frac_coords,
                                                           site_list, sampling_radius, q,
                                                           r_vecs[0], g_vecs[0], gamma)
        self.assertAlmostEqual( low_diel_pot_corr, -58.83598095)

        #test the kumagai plotter
        kcp = kc.plot()
        self.assertTrue( kcp)

        #check that uncertainty metadata exists
        self.assertAlmostEqual(set(kc.metadata['pot_corr_uncertainty_md'].keys()), set(['number_sampled', 'stats']))