コード例 #1
0
    def solve_for_fermi_energy(self, temperature, chemical_potentials,
                               bulk_dos):
        """
        Solve for the Fermi energy self-consistently as a function of T
        Observations are Defect concentrations, electron and hole conc
        Args:
            temperature: Temperature to equilibrate fermi energies for
            chemical_potentials: dict of chemical potentials to use for calculation fermi level
            bulk_dos: bulk system dos (pymatgen Dos object)
        Returns:
            Fermi energy dictated by charge neutrality
        """

        fdos = FermiDos(bulk_dos, bandgap=self.band_gap)
        _, fdos_vbm = fdos.get_cbm_vbm()

        def _get_total_q(ef):
            qd_tot = sum([
                d['charge'] * d['conc'] for d in self.defect_concentrations(
                    chemical_potentials=chemical_potentials,
                    temperature=temperature,
                    fermi_level=ef)
            ])
            qd_tot += fdos.get_doping(fermi_level=ef + fdos_vbm,
                                      temperature=temperature)
            return qd_tot

        return bisect(_get_total_q, -1., self.band_gap + 1.)
コード例 #2
0
    def solve_for_fermi_energy(self, temperature, chemical_potentials, bulk_dos):
        """
        Solve for the Fermi energy self-consistently as a function of T
        Observations are Defect concentrations, electron and hole conc
        Args:
            temperature: Temperature to equilibrate fermi energies for
            chemical_potentials: dict of chemical potentials to use for calculation fermi level
            bulk_dos: bulk system dos (pymatgen Dos object)
        Returns:
            Fermi energy dictated by charge neutrality
        """

        fdos = FermiDos(bulk_dos, bandgap=self.band_gap)
        _,fdos_vbm = fdos.get_cbm_vbm()

        def _get_total_q(ef):

            qd_tot = sum([
                d['charge'] * d['conc']
                for d in self.defect_concentrations(
                    chemical_potentials=chemical_potentials, temperature=temperature, fermi_level=ef)
            ])
            qd_tot += fdos.get_doping(fermi=ef + fdos_vbm, T=temperature)
            return qd_tot

        return bisect(_get_total_q, -1., self.band_gap + 1.)
コード例 #3
0
ファイル: test_dos.py プロジェクト: jmmshn/pymatgen
    def test_doping_fermi(self):
        T = 300
        fermi0 = self.dos.efermi
        frange = [fermi0 - 0.5, fermi0, fermi0 + 2.0, fermi0 + 2.2]
        dopings = [self.dos.get_doping(fermi_level=f, temperature=T) for f in frange]
        ref_dopings = [3.48077e21, 1.9235e18, -2.6909e16, -4.8723e19]
        for i, c_ref in enumerate(ref_dopings):
            self.assertLessEqual(abs(dopings[i] / c_ref - 1.0), 0.01)

        calc_fermis = [self.dos.get_fermi(concentration=c, temperature=T) for c in ref_dopings]
        for j, f_ref in enumerate(frange):
            self.assertAlmostEqual(calc_fermis[j], f_ref, 4)

        sci_dos = FermiDos(self.dos, bandgap=3.0)
        self.assertEqual(sci_dos.get_gap(), 3.0)
        old_cbm, old_vbm = self.dos.get_cbm_vbm()
        old_gap = old_cbm - old_vbm
        new_cbm, new_vbm = sci_dos.get_cbm_vbm()
        self.assertAlmostEqual(new_cbm - old_cbm, (3.0 - old_gap) / 2.0)
        self.assertAlmostEqual(old_vbm - new_vbm, (3.0 - old_gap) / 2.0)
        for i, c_ref in enumerate(ref_dopings):
            if c_ref < 0:
                self.assertAlmostEqual(sci_dos.get_fermi(c_ref, temperature=T) - frange[i], 0.47, places=2)
            else:
                self.assertAlmostEqual(sci_dos.get_fermi(c_ref, temperature=T) - frange[i], -0.47, places=2)

        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(-1e26, 300), 7.5108, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(1e26, 300), -1.4182, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(0.0, 300), 2.9071, 4)
コード例 #4
0
    def solve_for_non_equilibrium_fermi_energy(self, temperature, quench_temperature,
                                               chemical_potentials, bulk_dos):
        """
        Solve for the Fermi energy after quenching in the defect concentrations at a higher
        temperature (the quench temperature),
        as outlined in P. Canepa et al (2017) Chemistry of Materials (doi: 10.1021/acs.chemmater.7b02909)

        Args:
            temperature: Temperature to equilibrate fermi energy at after quenching in defects
            quench_temperature: Temperature to equilibrate defect concentrations at (higher temperature)
            chemical_potentials: dict of chemical potentials to use for calculation fermi level
            bulk_dos: bulk system dos (pymatgen Dos object)
        Returns:
            Fermi energy dictated by charge neutrality with respect to frozen in defect concentrations
        """

        high_temp_fermi_level = self.solve_for_fermi_energy(quench_temperature, chemical_potentials,
                                                            bulk_dos)
        fixed_defect_charge = sum([
            d['charge'] * d['conc']
            for d in self.defect_concentrations(
                chemical_potentials=chemical_potentials, temperature=quench_temperature,
                fermi_level=high_temp_fermi_level)
        ])

        fdos = FermiDos(bulk_dos, bandgap=self.band_gap)
        _, fdos_vbm = fdos.get_cbm_vbm()

        def _get_total_q(ef):
            qd_tot = fixed_defect_charge
            qd_tot += fdos.get_doping(fermi_level=ef + fdos_vbm, temperature=temperature)
            return qd_tot

        return bisect(_get_total_q, -1., self.band_gap + 1.)
コード例 #5
0
ファイル: test_dos.py プロジェクト: materialsproject/pymatgen
    def test_doping_fermi(self):
        T = 300
        fermi0 = self.dos.efermi
        frange = [fermi0 - 0.5, fermi0, fermi0 + 2.0, fermi0 + 2.2]
        dopings = [self.dos.get_doping(fermi=f, T=T) for f in frange]
        ref_dopings = [3.48077e+21, 1.9235e+18, -2.6909e+16, -4.8723e+19]
        for i, c_ref in enumerate(ref_dopings):
            self.assertLessEqual(abs(dopings[i] / c_ref - 1.0), 0.01)

        calc_fermis = [self.dos.get_fermi(c=c, T=T) for c in ref_dopings]
        for j, f_ref in enumerate(frange):
            self.assertAlmostEqual(calc_fermis[j], f_ref, 4)

        sci_dos = FermiDos(self.dos, bandgap=3.0)
        self.assertEqual( sci_dos.get_gap(), 3.)
        old_cbm, old_vbm = self.dos.get_cbm_vbm()
        old_gap = old_cbm - old_vbm
        new_cbm, new_vbm = sci_dos.get_cbm_vbm()
        self.assertAlmostEqual( new_cbm - old_cbm, (3. - old_gap) / 2.)
        self.assertAlmostEqual( old_vbm - new_vbm, (3. - old_gap) / 2.)
        for i, c_ref in enumerate(ref_dopings):
            if c_ref < 0:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, T=T) - frange[i], 0.47, places=2)
            else:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, T=T) - frange[i], -0.47, places=2)

        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(-1e26, 300),
                               7.5108, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(1e26, 300),
                               -1.4182, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(0.0, 300),
                               2.5226, 4)
コード例 #6
0
class FermiDosTest(unittest.TestCase):
    def setUp(self):
        with open(
                os.path.join(PymatgenTest.TEST_FILES_DIR, "complete_dos.json"),
                "r") as f:
            self.dos = CompleteDos.from_dict(json.load(f))
        self.dos = FermiDos(self.dos)

    def test_doping_fermi(self):
        T = 300
        fermi0 = self.dos.efermi
        frange = [fermi0 - 0.5, fermi0, fermi0 + 2.0, fermi0 + 2.2]
        dopings = [
            self.dos.get_doping(fermi_level=f, temperature=T) for f in frange
        ]
        ref_dopings = [3.48077e21, 1.9235e18, -2.6909e16, -4.8723e19]
        for i, c_ref in enumerate(ref_dopings):
            self.assertLessEqual(abs(dopings[i] / c_ref - 1.0), 0.01)

        calc_fermis = [
            self.dos.get_fermi(concentration=c, temperature=T)
            for c in ref_dopings
        ]
        for j, f_ref in enumerate(frange):
            self.assertAlmostEqual(calc_fermis[j], f_ref, 4)

        sci_dos = FermiDos(self.dos, bandgap=3.0)
        self.assertEqual(sci_dos.get_gap(), 3.0)
        old_cbm, old_vbm = self.dos.get_cbm_vbm()
        old_gap = old_cbm - old_vbm
        new_cbm, new_vbm = sci_dos.get_cbm_vbm()
        self.assertAlmostEqual(new_cbm - old_cbm, (3.0 - old_gap) / 2.0)
        self.assertAlmostEqual(old_vbm - new_vbm, (3.0 - old_gap) / 2.0)
        for i, c_ref in enumerate(ref_dopings):
            if c_ref < 0:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, temperature=T) - frange[i],
                    0.47,
                    places=2)
            else:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, temperature=T) - frange[i],
                    -0.47,
                    places=2)

        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(-1e26, 300),
                               7.5108, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(1e26, 300),
                               -1.4182, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(0.0, 300),
                               2.5226, 4)
コード例 #7
0
    def featurize(self, dos, bandgap=None):
        """
        Args:
            dos (pymatgen Dos, CompleteDos or FermiDos):
            bandgap (float): for example the experimentally measured band gap
                or one that is calculated via more accurate methods than the
                one used to generate dos. dos will be scissored to have the
                same electronic band gap as bandgap.

        Returns ([float]): features are fermi levels in eV at the given
            concentrations and temperature + eref in eV if return_eref
        """
        dos = FermiDos(dos, bandgap=bandgap)
        feats = []
        eref = 0.0
        for c in self.dopings:
            fermi = dos.get_fermi(concentration=c,
                                  temperature=self.T,
                                  nstep=50)
            if isinstance(self.eref, str):
                if self.eref == "dos_fermi":
                    eref = dos.efermi
                elif self.eref in ["midgap", "vbm", "cbm"]:
                    ecbm, evbm = dos.get_cbm_vbm()
                    if self.eref == "midgap":
                        eref = (evbm + ecbm) / 2.0
                    elif self.eref == "vbm":
                        eref = evbm
                    elif self.eref == "cbm":
                        eref = ecbm
                elif self.eref == "band center":
                    eref = self.BC.featurize(dos.structure.composition)[0]
                else:
                    raise ValueError('Unsupported "eref": {}'.format(
                        self.eref))
            else:
                eref = self.eref
            if not self.return_eref:
                fermi -= eref
            feats.append(fermi)
        if self.return_eref:
            feats.append(eref)
        return feats
コード例 #8
0
ファイル: dos.py プロジェクト: ardunn/MatMiner
    def featurize(self, dos, bandgap=None):
        """
        Args:
            dos (pymatgen Dos, CompleteDos or FermiDos):
            bandgap (float): for example the experimentally measured band gap
                or one that is calculated via more accurate methods than the
                one used to generate dos. dos will be scissored to have the
                same electronic band gap as bandgap.

        Returns ([float]): features are fermi levels in eV at the given
            concentrations and temperature + eref in eV if return_eref
        """
        dos = FermiDos(dos, bandgap=bandgap)
        feats = []
        eref = 0.0
        for c in self.dopings:
            fermi = dos.get_fermi(c=c, T=self.T, nstep=50)
            if isinstance(self.eref, str):
                if self.eref == "dos_fermi":
                    eref = dos.efermi
                elif self.eref in ["midgap", "vbm", "cbm"]:
                    ecbm, evbm = dos.get_cbm_vbm()
                    if self.eref == "midgap":
                        eref = (evbm + ecbm) / 2.0
                    elif self.eref == "vbm":
                        eref = evbm
                    elif self.eref == "cbm":
                        eref = ecbm
                elif self.eref == "band center":
                    eref = self.BC.featurize(dos.structure.composition)[0]
                else:
                    raise ValueError('Unsupported "eref": {}'.format(self.eref))
            else:
                eref = self.eref
            if not self.return_eref:
                fermi -= eref
            feats.append(fermi)
        if self.return_eref:
            feats.append(eref)
        return feats
コード例 #9
0
ファイル: test_dos.py プロジェクト: materialsproject/pymatgen
class FermiDosTest(unittest.TestCase):
    def setUp(self):
        with open(os.path.join(test_dir, "complete_dos.json"), "r") as f:
            self.dos = CompleteDos.from_dict(json.load(f))
        self.dos = FermiDos(self.dos)

    def test_doping_fermi(self):
        T = 300
        fermi0 = self.dos.efermi
        frange = [fermi0 - 0.5, fermi0, fermi0 + 2.0, fermi0 + 2.2]
        dopings = [self.dos.get_doping(fermi=f, T=T) for f in frange]
        ref_dopings = [3.48077e+21, 1.9235e+18, -2.6909e+16, -4.8723e+19]
        for i, c_ref in enumerate(ref_dopings):
            self.assertLessEqual(abs(dopings[i] / c_ref - 1.0), 0.01)

        calc_fermis = [self.dos.get_fermi(c=c, T=T) for c in ref_dopings]
        for j, f_ref in enumerate(frange):
            self.assertAlmostEqual(calc_fermis[j], f_ref, 4)

        sci_dos = FermiDos(self.dos, bandgap=3.0)
        self.assertEqual( sci_dos.get_gap(), 3.)
        old_cbm, old_vbm = self.dos.get_cbm_vbm()
        old_gap = old_cbm - old_vbm
        new_cbm, new_vbm = sci_dos.get_cbm_vbm()
        self.assertAlmostEqual( new_cbm - old_cbm, (3. - old_gap) / 2.)
        self.assertAlmostEqual( old_vbm - new_vbm, (3. - old_gap) / 2.)
        for i, c_ref in enumerate(ref_dopings):
            if c_ref < 0:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, T=T) - frange[i], 0.47, places=2)
            else:
                self.assertAlmostEqual(
                    sci_dos.get_fermi(c_ref, T=T) - frange[i], -0.47, places=2)

        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(-1e26, 300),
                               7.5108, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(1e26, 300),
                               -1.4182, 4)
        self.assertAlmostEqual(sci_dos.get_fermi_interextrapolated(0.0, 300),
                               2.5226, 4)
コード例 #10
0
    def solve_for_non_equilibrium_fermi_energy(self, temperature, quench_temperature,
                                               chemical_potentials, bulk_dos):
        """
        Solve for the Fermi energy after quenching in the defect concentrations at a higher
        temperature (the quench temperature),
        as outlined in P. Canepa et al (2017) Chemistry of Materials (doi: 10.1021/acs.chemmater.7b02909)

        Args:
            temperature: Temperature to equilibrate fermi energy at after quenching in defects
            quench_temperature: Temperature to equilibrate defect concentrations at (higher temperature)
            chemical_potentials: dict of chemical potentials to use for calculation fermi level
            bulk_dos: bulk system dos (pymatgen Dos object)
        Returns:
            Fermi energy dictated by charge neutrality with respect to frozen in defect concentrations
        """

        high_temp_fermi_level = self.solve_for_fermi_energy( quench_temperature, chemical_potentials,
                                                             bulk_dos)
        fixed_defect_charge = sum([
            d['charge'] * d['conc']
            for d in self.defect_concentrations(
                chemical_potentials=chemical_potentials, temperature=quench_temperature,
                fermi_level=high_temp_fermi_level)
            ])

        fdos = FermiDos(bulk_dos, bandgap=self.band_gap)
        _,fdos_vbm = fdos.get_cbm_vbm()

        def _get_total_q(ef):

            qd_tot = fixed_defect_charge
            qd_tot += fdos.get_doping(fermi=ef + fdos_vbm, T=temperature)
            return qd_tot

        return bisect(_get_total_q, -1., self.band_gap + 1.)

        return