Пример #1
0
    def perform_es_corr(self, gamma, prec, lattice, charge):
        """
        Peform Electrostatic Kumagai Correction
        Args:
            gamma (float): Ewald parameter
            prec (int): Precision parameter for reciprical/real lattice vector generation
            lattice: Pymatgen Lattice object corresponding to defect supercell
            charge (int): Defect charge
        Return:
            Electrostatic Point Charge contribution to Kumagai Correction (float)
        """
        volume = lattice.volume

        g_vecs, recip_summation, r_vecs, real_summation = generate_R_and_G_vecs(
            gamma, [prec], lattice, self.dielectric)
        recip_summation = recip_summation[0]
        real_summation = real_summation[0]

        es_corr = (recip_summation + real_summation +
                   self.get_potential_shift(gamma, volume) +
                   self.get_self_interaction(gamma))

        es_corr *= -(charge**2.) * kumagai_to_V / 2.  # [eV]

        return es_corr
Пример #2
0
 def test_generate_R_and_G_vecs(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]])
     epsilon = 10.0 * np.identity(3)
     g_vecs, recip_summation, r_vecs, real_summation = generate_R_and_G_vecs(gamma, prec, lattice, epsilon)
     self.assertEqual(len(g_vecs[0]), 16418)
     self.assertAlmostEqual(recip_summation[0], 2.8946556e-15)
     self.assertEqual(len(r_vecs[0]), 16299)
     self.assertAlmostEqual(real_summation[0], 0.00679361)
Пример #3
0
 def test_generate_R_and_G_vecs(self):
     gamma = 0.19357221
     prec = 28
     lattice = Lattice( [[ 4.692882, -8.12831 ,  0.],
                         [ 4.692882,  8.12831 ,  0.],
                         [ 0.,  0., 10.03391 ]])
     epsilon = 10. * np.identity(3)
     g_vecs, recip_summation, r_vecs, real_summation = generate_R_and_G_vecs( gamma, prec,
                                                                              lattice, epsilon)
     self.assertEqual(len(g_vecs[0]), 16418)
     self.assertAlmostEqual(recip_summation[0], 2.8946556e-15)
     self.assertEqual(len(r_vecs[0]), 16299)
     self.assertAlmostEqual(real_summation[0], 0.00679361)
Пример #4
0
    def get_correction(self, entry):
        """
        Gets the Kumagai correction for a defect entry
        Args:
            entry (DefectEntry): defect entry to compute Kumagai correction on.

                Requires following parameters in the DefectEntry to exist:

                    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
        Returns:
            KumagaiCorrection values as a dictionary

        """
        bulk_atomic_site_averages = entry.parameters[
            "bulk_atomic_site_averages"]
        defect_atomic_site_averages = entry.parameters[
            "defect_atomic_site_averages"]
        site_matching_indices = entry.parameters["site_matching_indices"]
        defect_sc_structure = entry.parameters["initial_defect_structure"]
        defect_frac_sc_coords = entry.parameters["defect_frac_sc_coords"]

        lattice = defect_sc_structure.lattice
        volume = lattice.volume
        q = entry.defect.charge

        if not self.metadata["gamma"]:
            self.metadata["gamma"] = tune_for_gamma(lattice, self.dielectric)

        prec_set = [25, 28]
        g_vecs, recip_summation, r_vecs, real_summation = generate_R_and_G_vecs(
            self.metadata["gamma"], prec_set, lattice, self.dielectric)

        pot_shift = self.get_potential_shift(self.metadata["gamma"], volume)
        si = self.get_self_interaction(self.metadata["gamma"])
        es_corr = [
            (real_summation[ind] + recip_summation[ind] + pot_shift + si)
            for ind in range(2)
        ]

        # increase precision if correction is not converged yet
        # TODO: allow for larger prec_set to be tried if this fails
        if abs(es_corr[0] - es_corr[1]) > 0.0001:
            logger.debug(
                "Es_corr summation not converged! ({} vs. {})\nTrying a larger prec_set..."
                .format(es_corr[0], es_corr[1]))
            prec_set = [30, 35]
            g_vecs, recip_summation, r_vecs, real_summation = generate_R_and_G_vecs(
                self.metadata["gamma"], prec_set, lattice, self.dielectric)
            es_corr = [
                (real_summation[ind] + recip_summation[ind] + pot_shift + si)
                for ind in range(2)
            ]
            if abs(es_corr[0] - es_corr[1]) < 0.0001:
                raise ValueError(
                    "Correction still not converged after trying prec_sets up to 35... serious error."
                )

        es_corr = es_corr[0] * -(q**2.) * kumagai_to_V / 2.  # [eV]

        # if no sampling radius specified for pot align, then assuming Wigner-Seitz radius:
        if not self.metadata["sampling_radius"]:
            wz = lattice.get_wigner_seitz_cell()
            dist = []
            for facet in wz:
                midpt = np.mean(np.array(facet), axis=0)
                dist.append(np.linalg.norm(midpt))
            self.metadata["sampling_radius"] = min(dist)

        # assemble site_list based on matching indices
        # [[defect_site object, Vqb for site], .. repeat for all non defective sites]
        site_list = []
        for bs_ind, ds_ind in site_matching_indices:
            Vqb = -(defect_atomic_site_averages[int(ds_ind)] -
                    bulk_atomic_site_averages[int(bs_ind)])
            site_list.append([defect_sc_structure[int(ds_ind)], Vqb])

        pot_corr = self.perform_pot_corr(defect_sc_structure,
                                         defect_frac_sc_coords, site_list,
                                         self.metadata["sampling_radius"], q,
                                         r_vecs[0], g_vecs[0],
                                         self.metadata["gamma"])

        entry.parameters["kumagai_meta"] = dict(self.metadata)
        entry.parameters["potalign"] = pot_corr / (-q) if q else 0.

        return {
            "kumagai_electrostatic": es_corr,
            "kumagai_potential_alignment": pot_corr
        }
Пример #5
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"]),
        )
Пример #6
0
    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']))