Hi @Petthebat,
The difference you’re seeing is dependent on the DFT functional used for each calculation, as well as the mixing / correction scheme used by MP.
For example, the MPRelaxSet
uses either PBE or PBE+U, whereas the MPScanRelaxSet
uses r2SCAN. MP is currently transitioning all of its calculations to the more accurate r2SCAN functional.
In addition to this, MP applies corrections for compatibilities and known deficits of DFT to formation energies. That shifts the computed formation enthalpy away from the raw DFT value.
To see this, let’s pull the same materials you identified from MP using the API:
from mp_api.client import MPRester
mpids = ["mp-2317","mp-23671","mp-23","mp-730101","mp-26"]
elemental_to_mpid = {"Ni": "mp-23", "H": "mp-730101", "La": "mp-26"}
with MPRester() as mpr:
thermo_docs = mpr.materials.thermo.search(material_ids=mpids)
corrected_formation_enthalpies = {
mpid: {} for mpid in mpids if mpid not in elemental_to_mpid.values()
}
for doc in thermo_docs:
if (mpid := str(doc.material_id)) in corrected_formation_enthalpies:
corrected_formation_enthalpies[mpid][str(doc.thermo_type)] = doc.formation_energy_per_atom
If you print corrected_formation_enthalpies
, you should get something like this:
{'mp-2317': {'GGA_GGA+U': -0.2817098874999999,
'R2SCAN': -0.24004932416666472,
'GGA_GGA+U_R2SCAN': -0.2817098875000011},
'mp-23671': {'R2SCAN': -0.24349168432692198,
'GGA_GGA+U': -0.32070788961538454,
'GGA_GGA+U_R2SCAN': -0.3193938314423089}}
which lines up with what you see on the website, when you look at the GGA_GGA+U_R2SCAN
keys. This is currently the preferred method for MP, and reflects our most up-to-date corrected DFT methods.
If we instead try to get the uncorrected/raw formation energies from MP, we need a little more manipulation:
energies_per_atom = {mpid: {} for mpid in mpids}
compositions = {}
for doc in thermo_docs:
mpid = str(doc.material_id)
energies_per_atom[mpid][str(doc.thermo_type)] = doc.uncorrected_energy_per_atom
if mpid not in compositions:
compositions[mpid] = doc.composition.as_dict()
formation_energies = {
mpid : {
dfa : energy_per_atom
for dfa, energy_per_atom in entry.items()
} for mpid, entry in energies_per_atom.items() if mpid not in elemental_to_mpid.values()
}
for mpid, entry in formation_energies.items():
for dfa in entry:
formation_energies[mpid][dfa] -= sum(
stoich * energies_per_atom[elemental_to_mpid[atom]][dfa]
for atom, stoich in compositions[mpid].items()
)/sum(compositions[mpid].values())
But printing formation_energies
gives about the same values you found with the MPRelaxSet
when you look at the GGA_GGA+U
key:
{'mp-2317': {'GGA_GGA+U': -0.2817098874999999,
'R2SCAN': -0.2400493241666659,
'GGA_GGA+U_R2SCAN': -0.2400493241666659},
'mp-23671': {'R2SCAN': -0.24349168432692103,
'GGA_GGA+U': -0.2266397552884607,
'GGA_GGA+U_R2SCAN': -0.24349168432692103}}