| Property | Value |
|---|---|
| Difficulty | Intermediate |
| Time | 20-30 minutes |
| Prerequisites | Basic Python, ASE |
| Goal | Find optimal adsorption sites using ML-accelerated relaxations |
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
! pip install fairchem-core fairchem-data-oc fairchem-applications-cattsunamiGet 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.
# Login using the huggingface-cli utility
! huggingface-cli login
# alternatively,
import os
os.environ['HF_TOKEN'] = 'MY_TOKEN'Define desired adsorbate+slab system¶
from __future__ import annotations
import pandas as pd
from fairchem.data.oc.core import Bulk, Slab, Adsorbate
from ase.build import molecule
co_molecule = molecule("CO")
adsorbate = Adsorbate(adsorbate_atoms=co_molecule, adsorbate_binding_indices=[1]) # 1 corresponds to the carbon atom
# adsorbate = [Adsorbate(adsorbate_atoms=co_molecule, adsorbate_binding_indices=[1]) for _ in range(2)] # 2 COs
bulk_src_id = "mp-30"
bulk = Bulk(bulk_src_id_from_db=bulk_src_id)
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]Warp 1.18.0 initialized:
CUDA Toolkit 13.4, Driver 13.1
Devices:
"cpu" : "x86_64"
"cuda:0" : "Tesla T4" (16 GiB, sm_75, mempool enabled)
Kernel cache:
/home/runner/.cache/warp/1.18.0
Downloading /home/runner/work/_tool/Python/3.12.16/x64/lib/python3.12/site-packages/fairchem/data/oc/databases/pkls/bulks.pkl...
/home/runner/work/_tool/Python/3.12.16/x64/lib/python3.12/site-packages/fairchem/data/oc/core/bulk.py:66: UserWarning: Loading data from a pickle file. Pickle files can execute arbitrary code and should only be loaded from trusted sources. Consider migrating to a safer format such as Parquet, CSV, or JSON.
bulk_db = safe_pickle_load(fp)
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 src
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-1p2p1")
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'.
WARNING:root:UMA Nitro cannot serve this request: nitro mode supports only CUDA compute capability 8.x-12.x, not 7.5.
WARNING:root:Now running with nitro=False, execution_mode='umas_fast_gpu' (TF32).
WARNING:root:Running in a reduced-precision mode: some values, such as higher-order derivatives and phonon calculations, will be less accurate. For standard FP32 precision, use inference_settings='high-precision'.
WARNING:root:Model is being compiled. This might take a while the first time.
WARNING:root:Running (unknown commit) with inference settings: multigpu
W1027 22:02:35.522000 9567 site-packages/torch/_logging/_internal.py:1345] [0/0] Profiler record function <class 'torch.autograd.profiler.record_function'> will be ignored
Step Time Energy fmax
LBFGS: 0 22:03:31 -300.270010 0.049535
LBFGS: 1 22:03:32 -300.270559 0.047282
LBFGS: 2 22:03:32 -300.276508 0.003902
WARNING:root:The UMA fast path (merge_mole + compile) is only available for fixed composition, task, charge, and spin. This is optimized for MD applications. Falling back to a less optimized version for subsequent evaluations. Reason: 'Compositions differ from merged model'.
Use inference_settings='batch' for heterogeneous batched evaluations.
WARNING:root:Now running with merge_mole=False, compile=False, execution_mode='general' (TF32).
Step Time Energy fmax
LBFGS: 0 22:03:37 -314.863444 2.159749
LBFGS: 1 22:03:37 -314.856541 2.914537
LBFGS: 2 22:03:37 -314.909280 0.978586
LBFGS: 3 22:03:37 -314.948511 1.204130
LBFGS: 4 22:03:37 -315.058105 2.031401
LBFGS: 5 22:03:37 -315.004366 2.164814
LBFGS: 6 22:03:37 -315.097349 0.777412
LBFGS: 7 22:03:37 -315.107878 0.367360
LBFGS: 8 22:03:38 -315.120830 1.084879
LBFGS: 9 22:03:38 -315.127968 0.974616
LBFGS: 10 22:03:38 -315.154102 0.856724
LBFGS: 11 22:03:38 -315.158887 0.198962
LBFGS: 12 22:03:38 -315.163395 0.175087
LBFGS: 13 22:03:38 -315.166348 0.126107
LBFGS: 14 22:03:38 -315.167376 0.127240
LBFGS: 15 22:03:38 -315.168965 0.162456
LBFGS: 16 22:03:39 -315.170483 0.188273
LBFGS: 17 22:03:39 -315.171285 0.073683
LBFGS: 18 22:03:39 -315.171595 0.040698
LBFGS: 19 22:03:39 -315.171767 0.059040
LBFGS: 20 22:03:39 -315.172043 0.088037
Step Time Energy fmax
LBFGS: 0 22:03:39 -314.901207 1.767008
LBFGS: 1 22:03:39 -314.910140 2.460559
LBFGS: 2 22:03:39 -314.958785 1.223727
LBFGS: 3 22:03:40 -315.081887 2.070113
LBFGS: 4 22:03:40 -315.124092 1.302319
LBFGS: 5 22:03:40 -315.148896 0.696499
LBFGS: 6 22:03:40 -315.155139 0.319433
LBFGS: 7 22:03:40 -315.161494 0.584966
LBFGS: 8 22:03:40 -315.167336 0.818349
LBFGS: 9 22:03:40 -315.178338 0.950676
LBFGS: 10 22:03:40 -315.185397 0.565380
LBFGS: 11 22:03:41 -315.188030 0.091729
LBFGS: 12 22:03:41 -315.188488 0.121044
LBFGS: 13 22:03:41 -315.189337 0.153073
LBFGS: 14 22:03:41 -315.190314 0.167685
LBFGS: 15 22:03:41 -315.191375 0.149263
LBFGS: 16 22:03:41 -315.192093 0.087677
LBFGS: 17 22:03:41 -315.192553 0.068540
LBFGS: 18 22:03:41 -315.193072 0.104956
LBFGS: 19 22:03:42 -315.194052 0.145739
LBFGS: 20 22:03:42 -315.195206 0.117908
Step Time Energy fmax
LBFGS: 0 22:03:42 -314.895588 1.793802
LBFGS: 1 22:03:42 -314.903429 2.488321
LBFGS: 2 22:03:42 -314.951702 1.195950
LBFGS: 3 22:03:42 -315.063676 1.995201
LBFGS: 4 22:03:42 -315.118076 1.438699
LBFGS: 5 22:03:42 -315.142929 0.779471
LBFGS: 6 22:03:43 -315.150625 0.338467
LBFGS: 7 22:03:43 -315.157493 0.630885
LBFGS: 8 22:03:43 -315.163677 0.868140
LBFGS: 9 22:03:43 -315.176021 1.024139
LBFGS: 10 22:03:43 -315.183870 0.619537
LBFGS: 11 22:03:43 -315.187065 0.090151
LBFGS: 12 22:03:43 -315.187589 0.106378
LBFGS: 13 22:03:43 -315.188292 0.131801
LBFGS: 14 22:03:44 -315.189220 0.147150
LBFGS: 15 22:03:44 -315.190233 0.137963
LBFGS: 16 22:03:44 -315.190929 0.088883
LBFGS: 17 22:03:44 -315.191352 0.062679
LBFGS: 18 22:03:44 -315.191787 0.090867
LBFGS: 19 22:03:44 -315.192614 0.129422
LBFGS: 20 22:03:44 -315.193694 0.118181
Step Time Energy fmax
LBFGS: 0 22:03:44 -314.948517 2.474022
LBFGS: 1 22:03:45 -314.937380 3.290307
LBFGS: 2 22:03:45 -315.001810 1.094162
LBFGS: 3 22:03:45 -315.038215 1.110799
LBFGS: 4 22:03:45 -315.113902 2.165217
LBFGS: 5 22:03:45 -315.146797 1.047066
LBFGS: 6 22:03:45 -315.160912 0.550597
LBFGS: 7 22:03:45 -315.165278 0.246091
LBFGS: 8 22:03:46 -315.170613 0.630436
LBFGS: 9 22:03:46 -315.178173 0.971607
LBFGS: 10 22:03:46 -315.187130 1.020579
LBFGS: 11 22:03:46 -315.195549 0.621497
LBFGS: 12 22:03:46 -315.201055 0.254158
LBFGS: 13 22:03:46 -315.204819 0.480848
LBFGS: 14 22:03:46 -315.213645 0.667404
LBFGS: 15 22:03:46 -315.220372 0.497870
LBFGS: 16 22:03:47 -315.224198 0.256409
LBFGS: 17 22:03:47 -315.225729 0.160612
LBFGS: 18 22:03:47 -315.227061 0.271205
LBFGS: 19 22:03:47 -315.228591 0.374793
LBFGS: 20 22:03:47 -315.230323 0.299703
Step Time Energy fmax
LBFGS: 0 22:03:47 -314.931689 2.180878
LBFGS: 1 22:03:47 -314.928586 3.007497
LBFGS: 2 22:03:47 -314.982975 1.130675
LBFGS: 3 22:03:48 -315.031022 1.327726
LBFGS: 4 22:03:48 -315.108958 2.336140
LBFGS: 5 22:03:48 -315.133084 0.949079
LBFGS: 6 22:03:48 -315.142256 0.209266
LBFGS: 7 22:03:48 -315.143984 0.239308
LBFGS: 8 22:03:48 -315.149607 0.623600
LBFGS: 9 22:03:48 -315.154671 0.693485
LBFGS: 10 22:03:48 -315.158573 0.425588
LBFGS: 11 22:03:49 -315.160347 0.123175
LBFGS: 12 22:03:49 -315.161538 0.252856
LBFGS: 13 22:03:49 -315.163592 0.449379
LBFGS: 14 22:03:49 -315.166005 0.458187
LBFGS: 15 22:03:49 -315.167442 0.243917
LBFGS: 16 22:03:49 -315.167994 0.058905
LBFGS: 17 22:03:49 -315.168388 0.136898
LBFGS: 18 22:03:50 -315.168969 0.238583
LBFGS: 19 22:03:50 -315.169706 0.260406
LBFGS: 20 22:03:50 -315.170252 0.155088
Step Time Energy fmax
LBFGS: 0 22:03:50 -314.856538 1.688789
LBFGS: 1 22:03:50 -314.864552 2.305545
LBFGS: 2 22:03:50 -314.910483 1.107743
LBFGS: 3 22:03:50 -315.037996 1.889397
LBFGS: 4 22:03:50 -315.040050 2.084238
LBFGS: 5 22:03:51 -315.114915 1.026774
LBFGS: 6 22:03:51 -315.133708 0.515807
LBFGS: 7 22:03:51 -315.146260 0.921814
LBFGS: 8 22:03:51 -315.153796 0.846467
LBFGS: 9 22:03:51 -315.183211 1.147783
LBFGS: 10 22:03:51 -315.188689 0.231394
LBFGS: 11 22:03:51 -315.191782 0.177451
LBFGS: 12 22:03:52 -315.194285 0.096658
LBFGS: 13 22:03:52 -315.194681 0.099959
LBFGS: 14 22:03:52 -315.195499 0.192871
LBFGS: 15 22:03:52 -315.196546 0.236185
LBFGS: 16 22:03:52 -315.197392 0.179924
LBFGS: 17 22:03:52 -315.197842 0.078009
LBFGS: 18 22:03:53 -315.198092 0.066294
LBFGS: 19 22:03:53 -315.198393 0.129685
LBFGS: 20 22:03:53 -315.198929 0.181495
Step Time Energy fmax
LBFGS: 0 22:03:53 -314.909331 1.791773
LBFGS: 1 22:03:53 -314.917388 2.513921
LBFGS: 2 22:03:53 -314.966165 1.212690
LBFGS: 3 22:03:53 -315.075213 2.016700
LBFGS: 4 22:03:53 -315.130150 1.550571
LBFGS: 5 22:03:54 -315.149308 0.684961
LBFGS: 6 22:03:54 -315.154508 0.252092
LBFGS: 7 22:03:54 -315.158358 0.463456
LBFGS: 8 22:03:54 -315.164631 0.781447
LBFGS: 9 22:03:54 -315.171786 0.858046
LBFGS: 10 22:03:54 -315.178311 0.495172
LBFGS: 11 22:03:55 -315.180392 0.083812
LBFGS: 12 22:03:55 -315.180941 0.163531
LBFGS: 13 22:03:55 -315.182491 0.278408
LBFGS: 14 22:03:55 -315.183866 0.282122
LBFGS: 15 22:03:55 -315.184997 0.198417
LBFGS: 16 22:03:56 -315.185682 0.079512
LBFGS: 17 22:03:56 -315.186205 0.113102
LBFGS: 18 22:03:56 -315.187019 0.200226
LBFGS: 19 22:03:56 -315.188385 0.260076
LBFGS: 20 22:03:56 -315.189673 0.180908
Step Time Energy fmax
LBFGS: 0 22:03:57 -314.917289 1.694947
LBFGS: 1 22:03:57 -314.928344 2.396358
LBFGS: 2 22:03:57 -314.977753 1.276996
LBFGS: 3 22:03:57 -315.119966 2.181086
LBFGS: 4 22:03:57 -315.147865 0.969455
LBFGS: 5 22:03:58 -315.161326 0.352204
LBFGS: 6 22:03:58 -315.163885 0.227949
LBFGS: 7 22:03:58 -315.169740 0.618660
LBFGS: 8 22:03:58 -315.175466 0.806924
LBFGS: 9 22:03:58 -315.181821 0.659433
LBFGS: 10 22:03:58 -315.185232 0.190562
LBFGS: 11 22:03:59 -315.185895 0.134773
LBFGS: 12 22:03:59 -315.186684 0.261002
LBFGS: 13 22:03:59 -315.188243 0.374959
LBFGS: 14 22:03:59 -315.189801 0.345219
LBFGS: 15 22:03:59 -315.190970 0.200073
LBFGS: 16 22:03:59 -315.191702 0.074054
LBFGS: 17 22:04:00 -315.192352 0.168279
LBFGS: 18 22:04:00 -315.193496 0.285349
LBFGS: 19 22:04:00 -315.194939 0.299169
LBFGS: 20 22:04:00 -315.195879 0.145351
Step Time Energy fmax
LBFGS: 0 22:04:00 -314.934735 2.430164
LBFGS: 1 22:04:00 -314.923258 3.244742
LBFGS: 2 22:04:01 -314.984144 1.070523
LBFGS: 3 22:04:01 -315.017439 1.089599
LBFGS: 4 22:04:01 -315.091618 2.179219
LBFGS: 5 22:04:01 -315.118753 1.078858
LBFGS: 6 22:04:01 -315.135207 0.582577
LBFGS: 7 22:04:01 -315.139439 0.243341
LBFGS: 8 22:04:02 -315.144451 0.594109
LBFGS: 9 22:04:02 -315.149994 0.835238
LBFGS: 10 22:04:02 -315.157240 0.827118
LBFGS: 11 22:04:02 -315.162541 0.435007
LBFGS: 12 22:04:02 -315.164826 0.153538
LBFGS: 13 22:04:02 -315.166199 0.319762
LBFGS: 14 22:04:03 -315.169657 0.535468
LBFGS: 15 22:04:03 -315.172826 0.495386
LBFGS: 16 22:04:03 -315.174840 0.284898
LBFGS: 17 22:04:03 -315.176091 0.147526
LBFGS: 18 22:04:03 -315.177520 0.255377
LBFGS: 19 22:04:03 -315.180141 0.505649
LBFGS: 20 22:04:04 -315.184854 0.751343
Step Time Energy fmax
LBFGS: 0 22:04:04 -315.071645 3.294447
LBFGS: 1 22:04:04 -315.036147 3.968594
LBFGS: 2 22:04:04 -315.135719 1.126523
LBFGS: 3 22:04:04 -315.156461 0.818210
LBFGS: 4 22:04:04 -315.193034 1.505977
LBFGS: 5 22:04:05 -315.246493 1.223889
LBFGS: 6 22:04:05 -315.255184 0.498082
LBFGS: 7 22:04:05 -315.260037 0.263619
LBFGS: 8 22:04:05 -315.262506 0.435180
LBFGS: 9 22:04:05 -315.267760 0.565282
LBFGS: 10 22:04:05 -315.270827 0.388820
LBFGS: 11 22:04:06 -315.272594 0.109769
LBFGS: 12 22:04:06 -315.273770 0.226382
LBFGS: 13 22:04:06 -315.275941 0.427166
LBFGS: 14 22:04:06 -315.278974 0.497555
LBFGS: 15 22:04:06 -315.281455 0.330583
LBFGS: 16 22:04:06 -315.282429 0.096436
LBFGS: 17 22:04:07 -315.282878 0.075895
LBFGS: 18 22:04:07 -315.283364 0.176832
LBFGS: 19 22:04:07 -315.284172 0.254199
LBFGS: 20 22:04:07 -315.284992 0.222661
top_candidates = outputs["adslabs"]
global_min_candidate = top_candidates[0]top_candidates = outputs["adslabs"]
pd.DataFrame(top_candidates)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}/")