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 loginor 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 00:15:05 -300.219297 0.047121
LBFGS: 1 00:15:05 -300.219793 0.045099
LBFGS: 2 00:15:06 -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 00:15:06 -329.009720 2.969513
LBFGS: 1 00:15:06 -329.262831 1.461636
LBFGS: 2 00:15:06 -329.394583 0.970979
LBFGS: 3 00:15:07 -329.437779 0.865683
LBFGS: 4 00:15:07 -329.510420 0.710859
LBFGS: 5 00:15:07 -329.535748 0.527411
LBFGS: 6 00:15:07 -329.547667 0.368459
LBFGS: 7 00:15:08 -329.559611 0.412819
LBFGS: 8 00:15:08 -329.577612 0.612530
LBFGS: 9 00:15:08 -329.603846 0.625800
LBFGS: 10 00:15:08 -329.627179 0.542655
LBFGS: 11 00:15:08 -329.650082 0.598627
LBFGS: 12 00:15:09 -329.681864 0.556477
LBFGS: 13 00:15:09 -329.724482 0.899029
LBFGS: 14 00:15:09 -329.774584 1.075264
LBFGS: 15 00:15:09 -329.824795 0.864841
LBFGS: 16 00:15:09 -329.859660 0.402721
LBFGS: 17 00:15:09 -329.880391 0.496842
LBFGS: 18 00:15:10 -329.913310 0.741736
LBFGS: 19 00:15:10 -329.952433 0.843984
LBFGS: 20 00:15:10 -329.978152 0.518004
Step Time Energy fmax
LBFGS: 0 00:15:10 -328.863083 3.004484
LBFGS: 1 00:15:10 -329.128966 1.449173
LBFGS: 2 00:15:11 -329.297532 1.136906
LBFGS: 3 00:15:11 -329.349667 1.035493
LBFGS: 4 00:15:11 -329.442999 0.754097
LBFGS: 5 00:15:11 -329.470620 0.464103
LBFGS: 6 00:15:11 -329.485619 0.474577
LBFGS: 7 00:15:11 -329.507035 0.504810
LBFGS: 8 00:15:12 -329.534361 0.710284
LBFGS: 9 00:15:12 -329.564250 0.611046
LBFGS: 10 00:15:12 -329.587151 0.594209
LBFGS: 11 00:15:12 -329.618109 0.758068
LBFGS: 12 00:15:12 -329.666066 0.844148
LBFGS: 13 00:15:13 -329.731734 0.960187
LBFGS: 14 00:15:13 -329.812541 1.099692
LBFGS: 15 00:15:13 -329.892558 0.743048
LBFGS: 16 00:15:13 -329.941868 0.452660
LBFGS: 17 00:15:13 -329.968741 0.471130
LBFGS: 18 00:15:13 -329.997119 0.400365
LBFGS: 19 00:15:14 -330.011265 0.938403
LBFGS: 20 00:15:14 -330.021704 0.587148
Step Time Energy fmax
LBFGS: 0 00:15:14 -329.256669 2.819493
LBFGS: 1 00:15:14 -329.460398 1.434213
LBFGS: 2 00:15:14 -329.577996 0.942242
LBFGS: 3 00:15:15 -329.612786 0.876027
LBFGS: 4 00:15:15 -329.669684 0.456018
LBFGS: 5 00:15:15 -329.683714 0.335053
LBFGS: 6 00:15:15 -329.692036 0.361899
LBFGS: 7 00:15:15 -329.702544 0.349866
LBFGS: 8 00:15:15 -329.719117 0.538391
LBFGS: 9 00:15:16 -329.736926 0.499485
LBFGS: 10 00:15:16 -329.751372 0.440193
LBFGS: 11 00:15:16 -329.768120 0.522296
LBFGS: 12 00:15:16 -329.793063 0.593131
LBFGS: 13 00:15:16 -329.825982 0.699337
LBFGS: 14 00:15:17 -329.863442 0.737234
LBFGS: 15 00:15:17 -329.897254 0.451652
LBFGS: 16 00:15:17 -329.919173 0.308338
LBFGS: 17 00:15:17 -329.939772 0.458424
LBFGS: 18 00:15:17 -329.970370 0.587847
LBFGS: 19 00:15:17 -329.996241 0.462211
LBFGS: 20 00:15:18 -330.011389 0.347100
Step Time Energy fmax
LBFGS: 0 00:15:18 -329.205533 2.770492
LBFGS: 1 00:15:18 -329.425757 1.349018
LBFGS: 2 00:15:18 -329.544638 0.934491
LBFGS: 3 00:15:18 -329.576283 0.841550
LBFGS: 4 00:15:19 -329.634005 0.618343
LBFGS: 5 00:15:19 -329.649130 0.403419
LBFGS: 6 00:15:19 -329.658314 0.343110
LBFGS: 7 00:15:19 -329.670216 0.412104
LBFGS: 8 00:15:19 -329.686518 0.494449
LBFGS: 9 00:15:19 -329.702441 0.360506
LBFGS: 10 00:15:20 -329.715127 0.422123
LBFGS: 11 00:15:20 -329.731503 0.524128
LBFGS: 12 00:15:20 -329.758107 0.593273
LBFGS: 13 00:15:20 -329.797154 0.846372
LBFGS: 14 00:15:20 -329.845614 0.867877
LBFGS: 15 00:15:21 -329.893460 0.532782
LBFGS: 16 00:15:21 -329.922965 0.297056
LBFGS: 17 00:15:21 -329.944392 0.413072
LBFGS: 18 00:15:21 -329.975642 0.534580
LBFGS: 19 00:15:21 -330.004639 0.487967
LBFGS: 20 00:15:21 -330.024415 0.446960
Step Time Energy fmax
LBFGS: 0 00:15:22 -329.211251 2.539021
LBFGS: 1 00:15:22 -329.424614 1.304844
LBFGS: 2 00:15:22 -329.546061 0.967965
LBFGS: 3 00:15:22 -329.582848 0.843348
LBFGS: 4 00:15:22 -329.649565 0.715535
LBFGS: 5 00:15:23 -329.668446 0.470572
LBFGS: 6 00:15:23 -329.680211 0.335375
LBFGS: 7 00:15:23 -329.694861 0.424283
LBFGS: 8 00:15:23 -329.717116 0.593597
LBFGS: 9 00:15:23 -329.741145 0.510338
LBFGS: 10 00:15:23 -329.759760 0.553038
LBFGS: 11 00:15:24 -329.783667 0.671102
LBFGS: 12 00:15:24 -329.818921 0.717837
LBFGS: 13 00:15:24 -329.866862 0.852129
LBFGS: 14 00:15:24 -329.926051 0.900678
LBFGS: 15 00:15:24 -329.983866 0.579060
LBFGS: 16 00:15:25 -330.014624 0.273164
LBFGS: 17 00:15:25 -330.030867 0.295774
LBFGS: 18 00:15:25 -330.050557 0.346585
LBFGS: 19 00:15:25 -330.073613 0.690539
LBFGS: 20 00:15:25 -330.085312 0.531529
Step Time Energy fmax
LBFGS: 0 00:15:25 -329.135079 2.582889
LBFGS: 1 00:15:26 -329.367688 1.265373
LBFGS: 2 00:15:26 -329.494570 1.086840
LBFGS: 3 00:15:26 -329.540062 0.986833
LBFGS: 4 00:15:26 -329.625929 0.962408
LBFGS: 5 00:15:26 -329.667473 0.662271
LBFGS: 6 00:15:27 -329.689784 0.509089
LBFGS: 7 00:15:27 -329.717738 0.575062
LBFGS: 8 00:15:27 -329.760653 0.709009
LBFGS: 9 00:15:27 -329.811249 0.742614
LBFGS: 10 00:15:27 -329.849524 0.627475
LBFGS: 11 00:15:28 -329.893956 0.795585
LBFGS: 12 00:15:28 -329.935404 0.857904
LBFGS: 13 00:15:28 -329.992936 0.844182
LBFGS: 14 00:15:28 -330.053814 0.867165
LBFGS: 15 00:15:28 -330.108363 0.605064
LBFGS: 16 00:15:28 -330.132163 0.437457
LBFGS: 17 00:15:29 -330.136225 0.503904
LBFGS: 18 00:15:29 -330.148573 0.281967
LBFGS: 19 00:15:29 -330.156334 0.200697
LBFGS: 20 00:15:29 -330.171757 0.241566
Step Time Energy fmax
LBFGS: 0 00:15:29 -328.733914 3.200606
LBFGS: 1 00:15:30 -328.991669 1.490291
LBFGS: 2 00:15:30 -329.154738 1.069548
LBFGS: 3 00:15:30 -329.214295 1.158682
LBFGS: 4 00:15:30 -329.306178 0.880184
LBFGS: 5 00:15:30 -329.354765 0.521455
LBFGS: 6 00:15:30 -329.373814 0.406390
LBFGS: 7 00:15:31 -329.392211 0.423460
LBFGS: 8 00:15:31 -329.424115 0.793888
LBFGS: 9 00:15:31 -329.471203 0.983909
LBFGS: 10 00:15:31 -329.517493 0.720450
LBFGS: 11 00:15:31 -329.554766 0.678924
LBFGS: 12 00:15:32 -329.605507 0.670617
LBFGS: 13 00:15:32 -329.668789 1.013306
LBFGS: 14 00:15:32 -329.743601 1.208101
LBFGS: 15 00:15:32 -329.825650 1.019949
LBFGS: 16 00:15:32 -329.894026 0.502879
LBFGS: 17 00:15:32 -329.929635 0.549714
LBFGS: 18 00:15:33 -329.969435 0.774943
LBFGS: 19 00:15:33 -330.012406 0.637325
LBFGS: 20 00:15:33 -330.041668 0.636763
Step Time Energy fmax
LBFGS: 0 00:15:33 -328.812851 3.139528
LBFGS: 1 00:15:33 -329.104132 1.659777
LBFGS: 2 00:15:34 -329.261296 1.063189
LBFGS: 3 00:15:34 -329.315396 0.941084
LBFGS: 4 00:15:34 -329.401923 0.762253
LBFGS: 5 00:15:34 -329.432639 0.585087
LBFGS: 6 00:15:34 -329.447831 0.387251
LBFGS: 7 00:15:34 -329.464146 0.482835
LBFGS: 8 00:15:35 -329.488940 0.754032
LBFGS: 9 00:15:35 -329.530211 0.830489
LBFGS: 10 00:15:35 -329.567839 0.643470
LBFGS: 11 00:15:35 -329.601153 0.690265
LBFGS: 12 00:15:35 -329.642043 0.614292
LBFGS: 13 00:15:36 -329.693692 0.974727
LBFGS: 14 00:15:36 -329.754910 1.237406
LBFGS: 15 00:15:36 -329.820445 1.103466
LBFGS: 16 00:15:36 -329.870158 0.439247
LBFGS: 17 00:15:36 -329.893590 0.480284
LBFGS: 18 00:15:37 -329.922291 0.646482
LBFGS: 19 00:15:37 -329.961436 0.807242
LBFGS: 20 00:15:37 -329.985348 0.502200
Step Time Energy fmax
LBFGS: 0 00:15:37 -329.314450 2.736768
LBFGS: 1 00:15:37 -329.518340 1.399365
LBFGS: 2 00:15:37 -329.630574 0.889362
LBFGS: 3 00:15:38 -329.660500 0.798830
LBFGS: 4 00:15:38 -329.712327 0.471946
LBFGS: 5 00:15:38 -329.722418 0.285275
LBFGS: 6 00:15:38 -329.729029 0.291251
LBFGS: 7 00:15:38 -329.737362 0.353103
LBFGS: 8 00:15:39 -329.748869 0.425774
LBFGS: 9 00:15:39 -329.759110 0.313389
LBFGS: 10 00:15:39 -329.767613 0.363697
LBFGS: 11 00:15:39 -329.779284 0.441909
LBFGS: 12 00:15:39 -329.798659 0.552627
LBFGS: 13 00:15:39 -329.826356 0.683697
LBFGS: 14 00:15:40 -329.857180 0.620626
LBFGS: 15 00:15:40 -329.881241 0.312345
LBFGS: 16 00:15:40 -329.894892 0.283699
LBFGS: 17 00:15:40 -329.911227 0.489780
LBFGS: 18 00:15:40 -329.941628 0.716185
LBFGS: 19 00:15:41 -329.974206 0.678451
LBFGS: 20 00:15:41 -329.992060 0.306076
Step Time Energy fmax
LBFGS: 0 00:15:41 -329.228390 2.918155
LBFGS: 1 00:15:41 -329.437790 1.484228
LBFGS: 2 00:15:41 -329.555565 0.932672
LBFGS: 3 00:15:41 -329.590762 0.872376
LBFGS: 4 00:15:42 -329.650158 0.486893
LBFGS: 5 00:15:42 -329.665320 0.335021
LBFGS: 6 00:15:42 -329.674771 0.327784
LBFGS: 7 00:15:42 -329.686377 0.376702
LBFGS: 8 00:15:42 -329.703898 0.557315
LBFGS: 9 00:15:43 -329.722817 0.502451
LBFGS: 10 00:15:43 -329.738276 0.468217
LBFGS: 11 00:15:43 -329.756321 0.529001
LBFGS: 12 00:15:43 -329.783690 0.643110
LBFGS: 13 00:15:43 -329.821879 0.804544
LBFGS: 14 00:15:43 -329.866307 0.804847
LBFGS: 15 00:15:44 -329.906359 0.506008
LBFGS: 16 00:15:44 -329.928643 0.354927
LBFGS: 17 00:15:44 -329.945220 0.405342
LBFGS: 18 00:15:44 -329.975024 0.566644
LBFGS: 19 00:15:44 -330.004460 0.510294
LBFGS: 20 00:15:45 -330.020983 0.304203
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.1717572690838, 'forces': [[0.0... |
| 1 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.08531241434747, 'forces': [[0.... |
| 2 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.02441458719903, 'forces': [[0.... |
| 3 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.0217042447918, 'forces': [[0.0... |
| 4 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.0209832670086, 'forces': [[0.0... |
| 5 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -330.01138930338556, 'forces': [[0.... |
| 6 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.99206023234063, 'forces': [[0.... |
| 7 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.98534827250177, 'forces': [[0.... |
| 8 | {'atoms': (Atom('Cu', [np.float64(-1.300046521... | (Atom('Cu', [np.float64(-1.3000465215529715), ... | {'energy': -329.97815184611017, '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}/")