Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Formation Energy

We’re going to start simple here - let’s run a local relaxation (optimize the unit cell and positions) using a pre-trained UMA model to compute formation energies for inorganic materials.

Note predicting formation energy using models that models trained solely on OMat24 must use OMat24 compatible references and corrections for mixing PBE and PBE+U calculations. We use MP2020-style corrections fitted to OMat24 DFT calculations. For more information see the documentation at the Materials Project. The necessary references can be found using the fairchem.data.omat package!

from __future__ import annotations

import pprint

from ase.build import bulk
from ase.optimize import FIRE
from quacc.recipes.mlp.core import relax_job
from quacc import flow
from fairchem.core.calculate import FAIRChemCalculator, FormationEnergyCalculator

# Make an Atoms object of a bulk Cu structure
atoms = bulk("Cu")

# Run a structure relaxation
@flow
def relax_flow(*args, **kwargs):
  return relax_job(*args, **kwargs)

result = relax_flow(
    atoms,
    method="fairchem",
    name_or_path="uma-s-1p2",
    task_name="omat",
    relax_cell=True,
    opt_params={"fmax": 1e-3, "optimizer": FIRE},
)

# Get the realxed atoms!
atoms = result["atoms"]

# Create an calculator using uma-s-1p2
calculator = FAIRChemCalculator.from_model_checkpoint("uma-s-1p2", task_name="omat")

# Now use the FormationEnergyCalculator to calculate the formation energy
# This will now return MP-style corrected formation energies
# For the omat task, this defaults to apply MP2020 style corrections with OMat24 compatibility
form_e_calc = FormationEnergyCalculator(calculator, apply_corrections=True)
atoms.calc = form_e_calc
form_energy = atoms.get_potential_energy()
/tmp/ipykernel_9637/3292623750.py:7: DeprecationWarning: quacc.recipes.mlp is deprecated. Use quacc.recipes.mlip instead.
  from quacc.recipes.mlp.core import relax_job
/tmp/ipykernel_9637/3292623750.py:7: DeprecationWarning: quacc.recipes.mlp.core is deprecated. Use quacc.recipes.mlip.core instead.
  from quacc.recipes.mlp.core import relax_job
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[1], line 19
     15 @flow
     16 def relax_flow(*args, **kwargs):
     17   return relax_job(*args, **kwargs)
     18 
---> 19 result = relax_flow(
     20     atoms,
     21     method="fairchem",
     22     name_or_path="uma-s-1p2",

File ~/work/_tool/Python/3.12.13/x64/lib/python3.12/site-packages/quacc/wflow_tools/context.py:148, in tracked.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    146 @wraps(func)
    147 def wrapper(*args, **kwargs):
--> 148     return _tracked_call(func, node_type, args, kwargs)

File ~/work/_tool/Python/3.12.13/x64/lib/python3.12/site-packages/quacc/wflow_tools/context.py:169, in _tracked_call(func, node_type, args, kwargs)
    166 # When NESTED_RESULTS is off, skip all context tracking and just
    167 # delegate to the original function directly.
    168 if not settings.NESTED_RESULTS:
--> 169     return func(*args, **kwargs)
    171 # Create a unique name we can use at this level.
    172 name = make_unique_name(prefix=f"{func.__name__}-")

Cell In[1], line 17, in relax_flow(*args, **kwargs)
     15 @flow
     16 def relax_flow(*args, **kwargs):
---> 17   return relax_job(*args, **kwargs)

File ~/work/_tool/Python/3.12.13/x64/lib/python3.12/site-packages/quacc/wflow_tools/context.py:148, in tracked.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    146 @wraps(func)
    147 def wrapper(*args, **kwargs):
--> 148     return _tracked_call(func, node_type, args, kwargs)

File ~/work/_tool/Python/3.12.13/x64/lib/python3.12/site-packages/quacc/wflow_tools/context.py:169, in _tracked_call(func, node_type, args, kwargs)
    166 # When NESTED_RESULTS is off, skip all context tracking and just
    167 # delegate to the original function directly.
    168 if not settings.NESTED_RESULTS:
--> 169     return func(*args, **kwargs)
    171 # Create a unique name we can use at this level.
    172 name = make_unique_name(prefix=f"{func.__name__}-")

TypeError: relax_job() missing 1 required positional argument: 'library'
pprint.pprint(f"Total energy: {result['results']['energy']} eV \n Formation energy {form_energy} eV")

Compare the results to the value of -3.038 eV/atom reported in the Materials Project! Note that we expect differences due to the different DFT settings used to calculate the OMat24 training data.

Congratulations; you ran your first relaxation and predicted the formation energy of MgO using UMA and quacc!