AdsorbML tutorial#
The AdsorbML paper showed that pre-trained machine learning potentials were now viable to find and prioritize the best adsorption sites for a given surface. The results were quite impressive, especially if you were willing to do a DFT single-point calculation on the best calculations.
The latest UMA models are now total-energy models, and the results for the adsorption energy are even more impressive (see the paper for details and benchmarks). The AdsorbML package helps you with automated multi-adsorbate placement, and will automatically run calculations using the ML models to find the best sites to sample.
Need to install fairchem-core or get UMA access or getting permissions/401 errors?
Install the necessary packages using pip, uv etc
Get access to any necessary huggingface gated models
Get and login to your Huggingface account
Request access to https://huggingface.co/facebook/UMA
Create a Huggingface token at https://huggingface.co/settings/tokens/ with the permission “Permissions: Read access to contents of all public gated repos you can access”
Add the token as an environment variable using
huggingface-cli login
or by setting the HF_TOKEN environment variable.
Define desired adsorbate+slab system#
from __future__ import annotations
import pandas as pd
from fairchem.data.oc.core import Adsorbate, Bulk, Slab
bulk_src_id = "mp-30"
adsorbate_smiles = "*CO"
bulk = Bulk(bulk_src_id_from_db=bulk_src_id)
adsorbate = Adsorbate(adsorbate_smiles_from_db=adsorbate_smiles)
slabs = Slab.from_bulk_get_specific_millers(bulk=bulk, specific_millers=(1, 1, 1))
# There may be multiple slabs with this miller index.
# For demonstrative purposes we will take the first entry.
slab = slabs[0]
Downloading /home/runner/work/fairchem/fairchem/src/fairchem/data/oc/databases/pkls/bulks.pkl...
Run heuristic/random adsorbate placement and ML relaxations#
Now that we’ve defined the bulk, slab, and adsorbates of interest, we can quickly use the pre-trained UMA model as a calculator and the helper script fairchem.core.components.calculate.recipes.adsorbml.run_adsorbml
. More details on the automated pipeline can be found at https://github.com/facebookresearch/fairchem/blob/main/src/fairchem/core/components/calculate/recipes/adsorbml.py#L316.
from ase.optimize import LBFGS
from fairchem.core import FAIRChemCalculator, pretrained_mlip
from fairchem.core.components.calculate.recipes.adsorbml import run_adsorbml
predictor = pretrained_mlip.get_predict_unit("uma-s-1p1")
calc = FAIRChemCalculator(predictor, task_name="oc20")
outputs = run_adsorbml(
slab=slab,
adsorbate=adsorbate,
calculator=calc,
optimizer_cls=LBFGS,
fmax=0.02,
steps=20, # Increase to 200 for practical application, 20 is used for demonstrations
num_placements=10, # Increase to 100 for practical application, 10 is used for demonstrations
reference_ml_energies=True, # True if using a total energy model (i.e. UMA)
relaxed_slab_atoms=None,
place_on_relaxed_slab=False,
)
WARNING:root:device was not explicitly set, using device='cuda'.
Step Time Energy fmax
LBFGS: 0 21:43:18 -300.219297 0.047121
LBFGS: 1 21:43:18 -300.219793 0.045100
LBFGS: 2 21:43:18 -300.225582 0.004432
/home/runner/work/fairchem/fairchem/src/fairchem/data/oc/core/adsorbate.py:89: UserWarning: An adsorbate with that SMILES string was not found. Choosing one at random instead.
warnings.warn(
Step Time Energy fmax
LBFGS: 0 21:43:19 -329.009718 2.969512
LBFGS: 1 21:43:19 -329.262827 1.461636
LBFGS: 2 21:43:19 -329.394583 0.970977
LBFGS: 3 21:43:19 -329.437779 0.865701
LBFGS: 4 21:43:20 -329.510418 0.710859
LBFGS: 5 21:43:20 -329.535748 0.527390
LBFGS: 6 21:43:20 -329.547663 0.368418
LBFGS: 7 21:43:20 -329.559617 0.412722
LBFGS: 8 21:43:20 -329.577612 0.612673
LBFGS: 9 21:43:21 -329.603837 0.625827
LBFGS: 10 21:43:21 -329.627175 0.542616
LBFGS: 11 21:43:21 -329.650065 0.598551
LBFGS: 12 21:43:21 -329.681857 0.556465
LBFGS: 13 21:43:21 -329.724471 0.898914
LBFGS: 14 21:43:21 -329.774584 1.075290
LBFGS: 15 21:43:22 -329.824788 0.864931
LBFGS: 16 21:43:22 -329.859665 0.402758
LBFGS: 17 21:43:22 -329.880385 0.496725
LBFGS: 18 21:43:22 -329.913317 0.741685
LBFGS: 19 21:43:22 -329.952427 0.843942
LBFGS: 20 21:43:23 -329.978148 0.517879
Step Time Energy fmax
LBFGS: 0 21:43:23 -328.863083 3.004485
LBFGS: 1 21:43:23 -329.128964 1.449171
LBFGS: 2 21:43:23 -329.297518 1.136811
LBFGS: 3 21:43:23 -329.349667 1.035452
LBFGS: 4 21:43:24 -329.442961 0.754484
LBFGS: 5 21:43:24 -329.470618 0.464063
LBFGS: 6 21:43:24 -329.485610 0.474620
LBFGS: 7 21:43:24 -329.507018 0.504636
LBFGS: 8 21:43:24 -329.534342 0.710272
LBFGS: 9 21:43:25 -329.564234 0.611170
LBFGS: 10 21:43:25 -329.587128 0.594139
LBFGS: 11 21:43:25 -329.618067 0.757933
LBFGS: 12 21:43:25 -329.666018 0.844214
LBFGS: 13 21:43:25 -329.731673 0.960115
LBFGS: 14 21:43:25 -329.812491 1.100035
LBFGS: 15 21:43:26 -329.892535 0.743733
LBFGS: 16 21:43:26 -329.941897 0.452612
LBFGS: 17 21:43:26 -329.968768 0.471116
LBFGS: 18 21:43:26 -329.997138 0.400141
LBFGS: 19 21:43:26 -330.011321 0.937429
LBFGS: 20 21:43:27 -330.021729 0.586853
Step Time Energy fmax
LBFGS: 0 21:43:27 -329.256671 2.819494
LBFGS: 1 21:43:27 -329.460398 1.434213
LBFGS: 2 21:43:27 -329.577998 0.942200
LBFGS: 3 21:43:28 -329.612790 0.876082
LBFGS: 4 21:43:28 -329.669686 0.456103
LBFGS: 5 21:43:28 -329.683716 0.335053
LBFGS: 6 21:43:28 -329.692036 0.361926
LBFGS: 7 21:43:28 -329.702544 0.349863
LBFGS: 8 21:43:29 -329.719107 0.538284
LBFGS: 9 21:43:29 -329.736920 0.499415
LBFGS: 10 21:43:29 -329.751357 0.440131
LBFGS: 11 21:43:29 -329.768105 0.522302
LBFGS: 12 21:43:29 -329.793049 0.592985
LBFGS: 13 21:43:30 -329.825976 0.699343
LBFGS: 14 21:43:30 -329.863429 0.737342
LBFGS: 15 21:43:30 -329.897248 0.451821
LBFGS: 16 21:43:30 -329.919179 0.308365
LBFGS: 17 21:43:30 -329.939784 0.458456
LBFGS: 18 21:43:30 -329.970368 0.587663
LBFGS: 19 21:43:31 -329.996235 0.461996
LBFGS: 20 21:43:31 -330.011397 0.346959
Step Time Energy fmax
LBFGS: 0 21:43:31 -329.205535 2.770492
LBFGS: 1 21:43:31 -329.425765 1.349018
LBFGS: 2 21:43:31 -329.544646 0.934499
LBFGS: 3 21:43:32 -329.576287 0.841551
LBFGS: 4 21:43:32 -329.634013 0.618370
LBFGS: 5 21:43:32 -329.649132 0.403443
LBFGS: 6 21:43:32 -329.658312 0.343086
LBFGS: 7 21:43:32 -329.670216 0.412197
LBFGS: 8 21:43:33 -329.686526 0.494412
LBFGS: 9 21:43:33 -329.702439 0.360481
LBFGS: 10 21:43:33 -329.715121 0.422154
LBFGS: 11 21:43:33 -329.731492 0.524042
LBFGS: 12 21:43:33 -329.758103 0.593438
LBFGS: 13 21:43:34 -329.797141 0.846446
LBFGS: 14 21:43:34 -329.845614 0.868023
LBFGS: 15 21:43:34 -329.893462 0.532929
LBFGS: 16 21:43:34 -329.922980 0.296850
LBFGS: 17 21:43:34 -329.944403 0.413050
LBFGS: 18 21:43:35 -329.975659 0.534599
LBFGS: 19 21:43:35 -330.004643 0.487714
LBFGS: 20 21:43:35 -330.024424 0.447026
Step Time Energy fmax
LBFGS: 0 21:43:35 -329.211251 2.539020
LBFGS: 1 21:43:35 -329.424616 1.304845
LBFGS: 2 21:43:35 -329.546055 0.967949
LBFGS: 3 21:43:36 -329.582854 0.843348
LBFGS: 4 21:43:36 -329.649556 0.715599
LBFGS: 5 21:43:36 -329.668448 0.470625
LBFGS: 6 21:43:36 -329.680207 0.335373
LBFGS: 7 21:43:36 -329.694853 0.424157
LBFGS: 8 21:43:37 -329.717104 0.593438
LBFGS: 9 21:43:37 -329.741129 0.510379
LBFGS: 10 21:43:37 -329.759747 0.552960
LBFGS: 11 21:43:37 -329.783654 0.671046
LBFGS: 12 21:43:37 -329.818902 0.717945
LBFGS: 13 21:43:38 -329.866841 0.852018
LBFGS: 14 21:43:38 -329.926028 0.900703
LBFGS: 15 21:43:38 -329.983857 0.579157
LBFGS: 16 21:43:38 -330.014620 0.273345
LBFGS: 17 21:43:38 -330.030873 0.295839
LBFGS: 18 21:43:39 -330.050549 0.346902
LBFGS: 19 21:43:39 -330.073622 0.689738
LBFGS: 20 21:43:39 -330.085406 0.527915
Step Time Energy fmax
LBFGS: 0 21:43:39 -329.135083 2.582889
LBFGS: 1 21:43:39 -329.367684 1.265373
LBFGS: 2 21:43:40 -329.494574 1.086839
LBFGS: 3 21:43:40 -329.540066 0.986836
LBFGS: 4 21:43:40 -329.625918 0.962447
LBFGS: 5 21:43:40 -329.667468 0.662335
LBFGS: 6 21:43:40 -329.689774 0.509101
LBFGS: 7 21:43:41 -329.717721 0.575106
LBFGS: 8 21:43:41 -329.760649 0.709027
LBFGS: 9 21:43:41 -329.811249 0.742647
LBFGS: 10 21:43:41 -329.849520 0.627479
LBFGS: 11 21:43:41 -329.893937 0.795283
LBFGS: 12 21:43:42 -329.935420 0.857954
LBFGS: 13 21:43:42 -329.992878 0.844127
LBFGS: 14 21:43:42 -330.053803 0.867184
LBFGS: 15 21:43:42 -330.108346 0.604956
LBFGS: 16 21:43:42 -330.132103 0.442063
LBFGS: 17 21:43:42 -330.136000 0.512144
LBFGS: 18 21:43:43 -330.148474 0.281772
LBFGS: 19 21:43:43 -330.156233 0.200596
LBFGS: 20 21:43:43 -330.171444 0.246663
Step Time Energy fmax
LBFGS: 0 21:43:43 -328.733918 3.200606
LBFGS: 1 21:43:43 -328.991669 1.490291
LBFGS: 2 21:43:44 -329.154746 1.069567
LBFGS: 3 21:43:44 -329.214297 1.158717
LBFGS: 4 21:43:44 -329.306181 0.880134
LBFGS: 5 21:43:44 -329.354771 0.521384
LBFGS: 6 21:43:44 -329.373810 0.406388
LBFGS: 7 21:43:45 -329.392218 0.423461
LBFGS: 8 21:43:45 -329.424124 0.793781
LBFGS: 9 21:43:45 -329.471215 0.983853
LBFGS: 10 21:43:45 -329.517487 0.720394
LBFGS: 11 21:43:45 -329.554768 0.678916
LBFGS: 12 21:43:46 -329.605521 0.670620
LBFGS: 13 21:43:46 -329.668797 1.013325
LBFGS: 14 21:43:46 -329.743615 1.208166
LBFGS: 15 21:43:46 -329.825665 1.019862
LBFGS: 16 21:43:46 -329.894036 0.502802
LBFGS: 17 21:43:47 -329.929633 0.549742
LBFGS: 18 21:43:47 -329.969439 0.775069
LBFGS: 19 21:43:47 -330.012419 0.637198
LBFGS: 20 21:43:47 -330.041649 0.637577
Step Time Energy fmax
LBFGS: 0 21:43:47 -328.812851 3.139527
LBFGS: 1 21:43:48 -329.104132 1.659777
LBFGS: 2 21:43:48 -329.261303 1.063174
LBFGS: 3 21:43:48 -329.315396 0.941131
LBFGS: 4 21:43:48 -329.401928 0.762323
LBFGS: 5 21:43:48 -329.432641 0.585124
LBFGS: 6 21:43:48 -329.447836 0.387235
LBFGS: 7 21:43:49 -329.464148 0.482794
LBFGS: 8 21:43:49 -329.488936 0.753973
LBFGS: 9 21:43:49 -329.530207 0.830508
LBFGS: 10 21:43:49 -329.567837 0.643478
LBFGS: 11 21:43:49 -329.601143 0.690295
LBFGS: 12 21:43:50 -329.642041 0.614301
LBFGS: 13 21:43:50 -329.693680 0.974777
LBFGS: 14 21:43:50 -329.754918 1.237414
LBFGS: 15 21:43:50 -329.820445 1.103559
LBFGS: 16 21:43:50 -329.870160 0.439112
LBFGS: 17 21:43:51 -329.893593 0.480347
LBFGS: 18 21:43:51 -329.922291 0.646340
LBFGS: 19 21:43:51 -329.961440 0.807300
LBFGS: 20 21:43:51 -329.985346 0.502128
Step Time Energy fmax
LBFGS: 0 21:43:51 -329.314454 2.736768
LBFGS: 1 21:43:52 -329.518342 1.399366
LBFGS: 2 21:43:52 -329.630578 0.889342
LBFGS: 3 21:43:52 -329.660500 0.798789
LBFGS: 4 21:43:52 -329.712323 0.471973
LBFGS: 5 21:43:52 -329.722420 0.285309
LBFGS: 6 21:43:53 -329.729033 0.291268
LBFGS: 7 21:43:53 -329.737362 0.353003
LBFGS: 8 21:43:53 -329.748873 0.425758
LBFGS: 9 21:43:53 -329.759104 0.313395
LBFGS: 10 21:43:53 -329.767609 0.363665
LBFGS: 11 21:43:54 -329.779276 0.441911
LBFGS: 12 21:43:54 -329.798653 0.552586
LBFGS: 13 21:43:54 -329.826336 0.683713
LBFGS: 14 21:43:54 -329.857171 0.620688
LBFGS: 15 21:43:54 -329.881232 0.312576
LBFGS: 16 21:43:55 -329.894883 0.283823
LBFGS: 17 21:43:55 -329.911231 0.489748
LBFGS: 18 21:43:55 -329.941618 0.716100
LBFGS: 19 21:43:55 -329.974211 0.678695
LBFGS: 20 21:43:55 -329.992068 0.306173
Step Time Energy fmax
LBFGS: 0 21:43:55 -329.228390 2.918155
LBFGS: 1 21:43:56 -329.437792 1.484229
LBFGS: 2 21:43:56 -329.555562 0.932666
LBFGS: 3 21:43:56 -329.590766 0.872370
LBFGS: 4 21:43:56 -329.650149 0.487024
LBFGS: 5 21:43:56 -329.665322 0.335143
LBFGS: 6 21:43:57 -329.674775 0.327737
LBFGS: 7 21:43:57 -329.686373 0.376691
LBFGS: 8 21:43:57 -329.703894 0.557268
LBFGS: 9 21:43:57 -329.722813 0.502474
LBFGS: 10 21:43:57 -329.738255 0.468160
LBFGS: 11 21:43:58 -329.756297 0.528897
LBFGS: 12 21:43:58 -329.783667 0.643042
LBFGS: 13 21:43:58 -329.821841 0.804497
LBFGS: 14 21:43:58 -329.866274 0.805005
LBFGS: 15 21:43:58 -329.906334 0.506314
LBFGS: 16 21:43:59 -329.928641 0.355108
LBFGS: 17 21:43:59 -329.945204 0.405251
LBFGS: 18 21:43:59 -329.975028 0.566438
LBFGS: 19 21:43:59 -330.004466 0.510189
LBFGS: 20 21:43:59 -330.020989 0.304086
top_candidates = outputs["adslabs"]
global_min_candidate = top_candidates[0]
top_candidates = outputs["adslabs"]
pd.DataFrame(top_candidates)
input_atoms | atoms | results | |
---|---|---|---|
0 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.17144446390796, 'forces': [[0.... |
1 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.0854058744304, 'forces': [[0.0... |
2 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.0244241239422, 'forces': [[0.0... |
3 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.021729040324, 'forces': [[0.0,... |
4 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.02098898905444, 'forces': [[0.... |
5 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.01139693278003, 'forces': [[0.... |
6 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.9920678617351, 'forces': [[0.0... |
7 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.9853463651531, 'forces': [[0.0... |
8 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.97814803141284, 'forces': [[0.... |
Write VASP input files#
If you want to verify the results, you should run VASP. This assumes you have access to VASP pseudopotentials. The default VASP flags (which are equivalent to those used to make OC20) are located in ocdata.utils.vasp
. Alternatively, you may pass your own vasp flags to the write_vasp_input_files
function as vasp_flags
. Note that to run this you need access to the VASP pseudopotentials and need to have those set up in ASE.
import os
from fairchem.data.oc.utils.vasp import write_vasp_input_files
# Grab the 5 systems with the lowest energy
top_5_candidates = top_candidates[:5]
# Write the inputs
for idx, config in enumerate(top_5_candidates):
os.makedirs(f"data/{idx}", exist_ok=True)
write_vasp_input_files(config["atoms"], outdir=f"data/{idx}/")