Example #1
0
def get_freysoldt_correction(defect_type, defect_specie, path_to_defect_locpot,path_to_pure_locpot,charge,
                             dielectric_constant,defect_site_coordinates,energy_cutoff=500,get_plot=False):
    
    ''' Function to perform charge corrections according to the method proposed py Freysoldt
        If this correction is used, please reference Freysoldt's original paper.
        doi: 10.1103/PhysRevLett.102.016402
        
        Args:
            defect_type: 'vacancy' or 'interstitial'
            defect_specie: string with element occupying the defect site
            path_to_defect_locpot: path to LOCPOT file of defect structure
            path_to_pure_locpot: path to LOCPOT file of Pure structure
            charge: Charge of the defected system
            dielectric_constant: Dielectric constant
            defect_site_coordinates: numpy array with fractional coordinates of defect site
            energy_cutoff: Cut-off of plane wave expansion
            get_plot: return also Matplotlib object with plot
            
        Returns:
            Freysoldt corrections values as a dictionary 
            '''
    # acquiring data from LOCPOT files    
    locpot_pure = Locpot.from_file(path_to_pure_locpot)
    vol_data_pure = VolumetricData(locpot_pure.structure,locpot_pure.data)
    
    locpot_defect = Locpot.from_file(path_to_defect_locpot)
    vol_data_defect = VolumetricData(locpot_defect.structure,locpot_defect.data)
    
    parameters = {}
    parameters['axis_grid'] = []
    parameters['bulk_planar_averages'] = []
    parameters['defect_planar_averages'] = []
    for i in range(0,3):
        parameters['axis_grid'].append(vol_data_pure.get_axis_grid(i))
        parameters['bulk_planar_averages'].append(vol_data_pure.get_average_along_axis(i))
        parameters['defect_planar_averages'].append(vol_data_defect.get_average_along_axis(i))
    parameters['initial_defect_structure'] = locpot_defect.structure
    parameters['defect_frac_sc_coords'] = defect_site_coordinates
    
    structure_bulk = locpot_pure.structure
    defect_site = PeriodicSite(defect_specie, coords=defect_site_coordinates, lattice = locpot_pure.structure.lattice)
    
    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)
    
    freysoldt_class = FreysoldtCorrection(dielectric_constant,energy_cutoff=energy_cutoff)
    
    freysoldt_corrections = freysoldt_class.get_correction(defect_entry)
  
    if get_plot:
        plt = freysoldt_class.plot(1)
        return freysoldt_corrections , plt
    else:    
        return freysoldt_corrections
Example #2
0
    def test_freysoldt(self):
        struc = PymatgenTest.get_structure("VO2")
        struc.make_supercell(3)
        struc = struc
        vac = Vacancy(struc, struc.sites[0], charge=-3)
        ids = vac.generate_defect_structure(1)

        abc = struc.lattice.abc
        axisdata = [np.arange(0.0, lattval, 0.2) for lattval in abc]
        bldata = [
            np.array([1.0 for u in np.arange(0.0, lattval, 0.2)]) for lattval in abc
        ]
        dldata = [
            np.array(
                [
                    (-1 - np.cos(2 * np.pi * u / lattval))
                    for u in np.arange(0.0, lattval, 0.2)
                ]
            )
            for lattval in abc
        ]
        params = {
            "axis_grid": axisdata,
            "bulk_planar_averages": bldata,
            "defect_planar_averages": dldata,
            "initial_defect_structure": ids,
            "defect_frac_sc_coords": struc.sites[0].frac_coords,
        }
        fc = FreysoldtCorrection(15)

        # test electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, -3)
        self.assertAlmostEqual(es_corr, 0.975893)

        # test potential alignment method
        pot_corr = fc.perform_pot_corr(
            axisdata[0], bldata[0], dldata[0], struc.lattice, -3, vac.site.coords, 0
        )
        self.assertAlmostEqual(pot_corr, 2.836369987722345)

        # test entry full correction method
        de = DefectEntry(vac, 0.0, corrections={}, parameters=params, entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val["freysoldt_electrostatic"], 0.975893)
        self.assertAlmostEqual(val["freysoldt_potential_alignment"], 4.4700574)

        # test the freysoldt plotter
        for ax in range(3):
            fcp = fc.plot(axis=ax)
            self.assertTrue(fcp)

        # check that uncertainty metadata exists
        for ax in range(3):
            self.assertAlmostEqual(
                set(fc.metadata["pot_corr_uncertainty_md"][ax].keys()),
                set(["potcorr", "stats"]),
            )

        # test a specified axis from entry
        fc = FreysoldtCorrection(15, axis=[1])
        val = fc.get_correction(de)
        self.assertAlmostEqual(val["freysoldt_potential_alignment"], 5.2869010593283132)

        # test a different charge
        #   for electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, 2)
        self.assertAlmostEqual(es_corr, 0.43373)
        #   for potential alignment method
        pot_corr = fc.perform_pot_corr(
            axisdata[0], bldata[0], dldata[0], struc.lattice, 2, vac.site.coords, 0
        )
        self.assertAlmostEqual(pot_corr, -2.1375685936497768)

        # test an input anisotropic dielectric constant
        fc = FreysoldtCorrection([[1.0, 2.0, 3.0], [0.0, 3.0, 5.0], [4.0, 10.0, 8.0]])
        self.assertAlmostEqual(fc.dielectric, 4.0)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val["freysoldt_electrostatic"], 3.659599)
        self.assertAlmostEqual(val["freysoldt_potential_alignment"], 3.3605255195745087)

        # test potalign being added to defect entry
        self.assertAlmostEqual(de.parameters["potalign"], 1.1201751731915028)

        # test that metadata entries exist in defect entry
        self.assertTrue("freysoldt_meta" in de.parameters.keys())
        self.assertAlmostEqual(
            set(de.parameters["freysoldt_meta"].keys()),
            set(["pot_plot_data", "pot_corr_uncertainty_md"]),
        )

        # test a charge of zero
        vac = Vacancy(struc, struc.sites[0], charge=0)
        de = DefectEntry(vac, 0.0, corrections={}, parameters=params, entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val["freysoldt_electrostatic"], 0.0)
        self.assertAlmostEqual(val["freysoldt_potential_alignment"], 0.0)
    def test_freysoldt(self):
        struc = PymatgenTest.get_structure("VO2")
        struc.make_supercell(3)
        struc = struc
        vac = Vacancy(struc, struc.sites[0], charge=-3)

        abc = struc.lattice.abc
        axisdata = [np.arange(0., lattval, 0.2) for lattval in abc]
        bldata = [np.array([1. for u in np.arange(0., lattval, 0.2)]) for lattval in abc]
        dldata = [
            np.array([(-1 - np.cos(2 * np.pi * u / lattval)) for u in np.arange(0., lattval, 0.2)]) for lattval in abc
        ]
        params = {'axis_grid': axisdata, 'bulk_planar_averages': bldata, 'defect_planar_averages': dldata}
        fc = FreysoldtCorrection(15)

        #test electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, -3)
        self.assertAlmostEqual(es_corr, 0.975893)

        #test potential alignment method
        pot_corr = fc.perform_pot_corr(axisdata[0], bldata[0], dldata[0], struc.lattice, -3, vac.site.coords, 0)
        self.assertAlmostEqual(pot_corr, 2.836369987722345)

        #test entry full correction method
        de = DefectEntry(vac, 0., corrections={}, parameters=params, entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 0.975893)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 4.4700574)

        #test the freysoldt plotter and that plot metadata exists
        pltsaver = []
        for ax in range(3):
            pltsaver.append(fc.plot(axis=ax))
        self.assertAlmostEqual(len(pltsaver), 3)

        #check that uncertainty metadata exists
        for ax in range(3):
            self.assertAlmostEqual(set(fc.metadata['pot_corr_uncertainty_md'][ax].keys()), set(['potcorr', 'stats']))

        #test a specified axis from entry
        fc = FreysoldtCorrection(15, axis=[1])
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 5.2869010593283132)

        #test a different charge
        #   for electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, 2)
        self.assertAlmostEqual(es_corr, 0.43373)
        #   for potential alignment method
        pot_corr = fc.perform_pot_corr(axisdata[0], bldata[0], dldata[0], struc.lattice, 2, vac.site.coords, 0)
        self.assertAlmostEqual(pot_corr, -2.1375685936497768)

        #test an input anisotropic dielectric constant
        fc = FreysoldtCorrection([[1., 2., 3.], [0., 3., 5.], [4., 10., 8.]])
        self.assertAlmostEqual(fc.dielectric, 4.)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 3.659599)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 3.3605255195745087)

        #test potalign being added to defect entry
        self.assertAlmostEqual(de.parameters['potalign'], 1.1201751731915028)

        #test that metadata entries exist in defect entry
        self.assertTrue('freysoldt_meta' in de.parameters.keys())
        self.assertAlmostEqual(
            set(de.parameters['freysoldt_meta'].keys()), set(['pot_plot_data', 'pot_corr_uncertainty_md']))

        #test a charge of zero
        vac = Vacancy(struc, struc.sites[0], charge=0)
        de = DefectEntry(vac, 0., corrections={}, parameters=params, entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 0.)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 0.)
Example #4
0
    def test_freysoldt(self):
        struc = PymatgenTest.get_structure("VO2")
        struc.make_supercell(3)
        struc = struc
        vac = Vacancy(struc, struc.sites[0], charge=-3)

        abc = struc.lattice.abc
        axisdata = [np.arange(0., lattval, 0.2) for lattval in abc]
        bldata = [
            np.array([1. for u in np.arange(0., lattval, 0.2)])
            for lattval in abc
        ]
        dldata = [
            np.array([(-1 - np.cos(2 * np.pi * u / lattval))
                      for u in np.arange(0., lattval, 0.2)]) for lattval in abc
        ]
        params = {
            'axis_grid': axisdata,
            'bulk_planar_averages': bldata,
            'defect_planar_averages': dldata
        }
        fc = FreysoldtCorrection(15)

        #test electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, -3)
        self.assertAlmostEqual(es_corr, 0.975893)

        #test potential alignment method
        pot_corr = fc.perform_pot_corr(axisdata[0], bldata[0], dldata[0],
                                       struc.lattice, -3, vac.site.coords, 0)
        self.assertAlmostEqual(pot_corr, 2.836369987722345)

        #test entry full correction method
        de = DefectEntry(vac,
                         0.,
                         corrections={},
                         parameters=params,
                         entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 0.975893)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 4.4700574)

        #test the freysoldt plotter and that plot metadata exists
        pltsaver = []
        for ax in range(3):
            pltsaver.append(fc.plot(axis=ax))
        self.assertAlmostEqual(len(pltsaver), 3)

        #check that uncertainty metadata exists
        for ax in range(3):
            self.assertAlmostEqual(
                set(fc.metadata['pot_corr_uncertainty_md'][ax].keys()),
                set(['potcorr', 'stats']))

        #test a specified axis from entry
        fc = FreysoldtCorrection(15, axis=[1])
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'],
                               5.2869010593283132)

        #test a different charge
        #   for electrostatic correction
        es_corr = fc.perform_es_corr(struc.lattice, 2)
        self.assertAlmostEqual(es_corr, 0.43373)
        #   for potential alignment method
        pot_corr = fc.perform_pot_corr(axisdata[0], bldata[0], dldata[0],
                                       struc.lattice, 2, vac.site.coords, 0)
        self.assertAlmostEqual(pot_corr, -2.1375685936497768)

        #test an input anisotropic dielectric constant
        fc = FreysoldtCorrection([[1., 2., 3.], [0., 3., 5.], [4., 10., 8.]])
        self.assertAlmostEqual(fc.dielectric, 4.)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 3.659599)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'],
                               3.3605255195745087)

        #test potalign being added to defect entry
        self.assertAlmostEqual(de.parameters['potalign'], 1.1201751731915028)

        #test that metadata entries exist in defect entry
        self.assertTrue('freysoldt_meta' in de.parameters.keys())
        self.assertAlmostEqual(
            set(de.parameters['freysoldt_meta'].keys()),
            set(['pot_plot_data', 'pot_corr_uncertainty_md']))

        #test a charge of zero
        vac = Vacancy(struc, struc.sites[0], charge=0)
        de = DefectEntry(vac,
                         0.,
                         corrections={},
                         parameters=params,
                         entry_id=None)
        val = fc.get_correction(de)
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 0.)
        self.assertAlmostEqual(val['freysoldt_potential_alignment'], 0.)
def get_correction_freysoldt(defect_entry,
                             epsilon,
                             title=None,
                             partflag='All',
                             axis=None):
    """
    Function to compute the isotropic freysoldt correction for each defect.
    If this correction is used, please reference Freysoldt's original paper.
    doi: 10.1103/PhysRevLett.102.016402
    Args:
        defect_entry: DefectEntry object with the following
            keys stored in defect.parameters:
                required:
                    axis_grid (3 x NGX where NGX is the length of the NGX grid
                    in the x,y and z axis directions. Same length as planar
                    average lists):
                        A list of 3 numpy arrays which contain the cartesian axis
                        values (in angstroms) that correspond to each planar avg
                        potential supplied.

                    bulk_planar_averages (3 x NGX where NGX is the length of
                    the NGX grid in the x,y and z axis directions.):
                        A list of 3 numpy arrays which contain the planar averaged
                        electrostatic potential for the bulk supercell.

                    defect_planar_averages (3 x NGX where NGX is the length of
                    the NGX grid in the x,y and z axis directions.):
                        A list of 3 numpy arrays which contain the planar averaged
                        electrostatic potential for the defective supercell.

                    bulk_sc_structure (Structure) bulk structure corresponding to
                        defect supercell structure (uses Lattice for charge correction)

                    defect_frac_sc_coords (3 x 1 array) Fracitional co-ordinates of
                        defect location in supercell structure
                optional:
                    'encut' : energy cutoff desired for Freysoldt correction
                    'madetol' : madelung tolerance for Freysoldt correction
                    'q_model' : Charge Model for Freysoldt correction
                    'q_model' : Charge Model for Freysoldt correction
        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])
        axis (int or None): if integer, then freysoldt correction is performed on the single axis.
            If it is None, then averaging of the corrections for the three axes is used for the correction.

    Returns Correction
    """
    if partflag not in ['All', 'AllSplit', 'pc', 'potalign']:
        print(
            '{} is incorrect potalign type. Must be "All", "AllSplit", "pc", or '
            '"potalign".'.format(partflag))
        return

    q_model = defect_entry.parameters.get('q_model', None)
    encut = defect_entry.parameters.get('encut', 520)
    madetol = defect_entry.parameters.get('madetol', 0.0001)

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

    template_defect = defect_entry.copy()
    corr_class = FreysoldtCorrection(epsilon,
                                     q_model=q_model,
                                     energy_cutoff=encut,
                                     madetol=madetol,
                                     axis=axis)
    f_corr_summ = corr_class.get_correction(template_defect)

    if title:
        if axis is None:
            ax_list = [[k, "axis" + str(k)]
                       for k in corr_class.metadata["pot_plot_data"].keys()]
        else:
            ax_list = [[axis, "axis" + str(axis + 1)]]

        for ax_key, ax_title in ax_list:
            p = corr_class.plot(ax_key, title=ax_title, saved=False)
            p.savefig(title + '_' + ax_title + '_freysoldtplot.pdf',
                      bbox_inches='tight')

    if partflag in ['AllSplit', 'All']:
        freyval = np.sum(list(f_corr_summ.values()))
    elif partflag == 'pc':
        freyval = f_corr_summ['freysoldt_electrostatic']
    elif partflag == 'potalign':
        freyval = f_corr_summ['freysoldt_potential_alignment']

    print('\n Final Freysoldt correction is {}'.format(freyval))

    if partflag == 'AllSplit':
        freyval = [
            f_corr_summ['freysoldt_electrostatic'],
            f_corr_summ['freysoldt_potential_alignment'], freyval
        ]

    return freyval