用 UMA 模型把吸附能计算压到秒级:一条可复制的 OCP 催化筛选流水线
【免费下载链接】ocpFAIR Chemistry's library of machine learning methods for chemistry项目地址: https://gitcode.com/GitHub_Trending/oc/ocp
DFT 跑一个吸附构型一天还没收敛,是催化筛选里的常态。Open Catalyst Project(OCP)把 UMA 模型封装成开箱即用的机器学习势(MLIP,用神经网络代替哈密顿量算能量和力),让 GPU 上的吸附能预测进入秒级计算。
下面这张图是 OCP 生成吸附构型的标准流水线:体相晶体 → 表面切片 → 吸附质放置 → 标准化输入,OCP 训练数据都走这套流程。
为什么用 UMA 模型而不是 DFT
| 维度 | DFT | UMA 模型 |
|---|---|---|
| 速度 | 单构型弛豫小时到天级 | 单点秒级,百原子弛豫数秒 |
| 精度 | 基准 | 吸附能相对 DFT 约 0.1 eV 量级偏差,筛选够用 |
| 参数量 / 成本 | 随体系增大需更大算力集群 | uma-s-1p2 激活约 660 万参数,单卡即可 |
| 适用规模 | 每个材料几十构型 | 每个材料上千构型,甚至整面体动力学(MD) |
关键不是"模型准",而是试错成本降了两个数量级:UMA 负责把初筛做到"几百构型一锅出",DFT 留在最后做验证位,两边各干各的。
五分钟跑通最小示例:UMA 模型使用方法
克隆与安装
git clone https://gitcode.com/GitHub_Trending/oc/ocp cd ocp pip install fairchem-core fairchem-data-oc认证与模型拉取
UMA 权重放在 HuggingFace 且为 gated 仓库:注册 HuggingFace 账号并申请facebook/UMA的访问权限,批准后本地登录:
huggingface-cli login确认已注册的模型名单:
from fairchem.core import pretrained_mlip print(pretrained_mlip.available_models) # ('uma-s-1p2p1', 'uma-s-1p2', 'uma-s-1p1', 'uma-m-1p1', ...)首次调用get_predict_unit时,checkpoint 和元素参考能量文件会自动下载到~/.cache/fairchem,不用手动搬权重。
出第一个预测结果
先算气相 CO2 的能量,跑通即算环境就绪:
from fairchem.core import FAIRChemCalculator, pretrained_mlip from ase.build import molecule predictor = pretrained_mlip.get_predict_unit("uma-s-1p2", device="cuda") calc = FAIRChemCalculator(predictor, task_name="omol") co2 = molecule("CO2") co2.calc = calc print(co2.get_potential_energy()) # 约 -11 eV(含元素参考能,非裸总能量)task_name决定模型使用哪套参考能量体系:分子体系用omol,表面体系用oc20,混用会让后续所有结果偏移一个常数。
从表面到吸附能:三步完整工作流
这一节把 CO2 在 Cu(111) 上的吸附能从头算到排出序,全程 🔬 三条代码块。
步骤 1 · 构建催化表面与吸附构型
这步的活是批量生成"CO2 放在 Cu(111) 面上"的初始结构。OCP 的 structure_generator.py 流水线被封装成四个对象,几行就能取用:
from fairchem.data.oc.core import Bulk, Slab, Adsorbate, AdsorbateSlabConfig bulk = Bulk(bulk_src_id_from_db="mp-30") # Cu,Materials Project ID slab_objs = Slab.from_bulk_get_specific_millers(bulk=bulk, specific_millers=(1, 1, 1)) co2 = Adsorbate(adsorbate_smiles_from_db="*CO2") # * 标记成键原子 adslabs = AdsorbateSlabConfig( slab_objs[0], co2, mode="random_site_heuristic_placement", num_sites=20, ) print(len(adslabs.atoms_list)) # 20 个初始吸附构型num_sites控制采样的表面位点数量,给得越大越不容易漏掉低能构型;random_site_heuristic_placement会把成键原子直接落在位点上,初始结构离终态更近,收敛更快。
步骤 2 · 批量结构优化(ASE + UMA 计算器)
每个构型用 ASE 的 QuasiNewton 弛豫到 0.05 eV/Å 的力阈值,UMA 只负责供能量和力。顺手用自带的轨迹异常检测把 CO2 解离、脱附的构型过滤掉,避免污染吸附能统计:
from ase.optimize import QuasiNewton from fairchem.core import FAIRChemCalculator, pretrained_mlip from fairchem.data.oc.utils import DetectTrajAnomaly predictor = pretrained_mlip.get_predict_unit("uma-s-1p2", device="cuda") calc = FAIRChemCalculator(predictor, task_name="oc20") e_adslabs = [] for i, adslab in enumerate(adslabs.atoms_list): init = adslab.copy() adslab.calc = calc adslab.pbc = True QuasiNewton(adslab, trajectory=f"data/co2_{i}.traj").run(fmax=0.05, steps=100) det = DetectTrajAnomaly(init, adslab, adslab.get_tags()) if det.is_adsorbate_dissociated() or det.is_adsorbate_desorbed(): continue e_adslabs.append(adslab.get_potential_energy())检测逻辑在 flag_anomaly.py,还提供表面重构、插层两类检查,按体系需要加进过滤条件即可。
步骤 3 · 吸附能计算与结果排序(吸附能批量计算)
吸附能 = 吸附体系能量 − 清洁表面能量 − 气相分子能量。两个参考能量必须和 adslab 用同一收敛标准算,否则差值没有意义:
import pandas as pd from ase.build import molecule slab = slab_objs[0].atoms slab.calc = calc slab.pbc = True QuasiNewton(slab, trajectory="data/cu_slab.traj").run(fmax=0.05, steps=100) e_slab = slab.get_potential_energy() gas = molecule("CO2") gas.calc = FAIRChemCalculator(predictor, task_name="omol") e_gas = gas.get_potential_energy() df = pd.DataFrame({"idx": range(len(e_adslabs)), "E_ads": [e - e_slab - e_gas for e in e_adslabs]}) print(df.sort_values("E_ads").head()) # 最负的吸附能 = 结合最强构型到这里,排序好的吸附能表已经出来——同样的流程用 DFT 走,大概还在排队提交VASP作业。
性能调优与精度取舍:机器学习势函数催化实战
⚡ 单构型调试用默认配置即可,规模上来后动这三个旋钮:
- 并行:
get_predict_unit(..., workers=8)会创建 ParallelMLIPPredictUnit,把结构分批喂进并行队列;大批量单点再加inference_settings="turbo"启用 compile 快速路径。 - 模型档位:
uma-s-1p2快筛;候选体系换uma-m-1p1精算(参数约四倍,精度同步提升);uma-s-1p1/uma-s-1p2p1是更小变体,适合快速试体系。 - 任务模式:
oc20催化表面、oc25电催化、omat无机材料、omol分子与气相、omc分子晶体。每个任务挂独立的参考能量体系,表面必须 oc20、气相必须 omol。
精度换速度的取舍关系,在力 MAE 对比推理吞吐量的曲线里能看得很清楚:
排错三问
Q1:模型下载失败或 401?权重是 gated 的,先在 HuggingFace 申请facebook/UMA访问权限再huggingface-cli login;无外网的机器把.pt权重和参考能量 yaml 手动放进~/.cache/fairchem。
Q2:显存溢出(OOM)?给get_predict_unit传overrides={"max_atoms": ...}限制单批最大原子数;批量单点交给 SinglePointRunner 分块处理,让 batcher 自动切分超大 batch。
Q3:与 DFT 偏差大?按顺序查:①task_name是否与体系匹配;② 参考能量是否随模型正常下载;③ 系统偏差在 ~0.1 eV 内一般筛选可用,边界候选换uma-m-1p1重算或 DFT 单点校正。
OCP 催化剂筛选:规模化筛选与结果可视化
几百上千个构型就不建议手写了 for 循环。fairchem.core.components.calculate里的RelaxationRunner支持num_jobs分片整批跑,结果写成.json.gz,中断后也好续跑:
from fairchem.core.components.calculate import RelaxationRunner runner = RelaxationRunner( calculator=calc, # 前面建好的 FAIRChemCalculator input_data=adslabs.atoms_list, fmax=0.05, steps=100, ) results = runner.calculate(job_num=0, num_jobs=4) # 多卡/多机时调大 num_jobs 分片 runner.write_results(results, results_dir="results")跑完用 pandas + matplotlib 画一张能量分布图,整体情况一眼看全:
import matplotlib.pyplot as plt plt.figure(figsize=(9, 5)) plt.hist(df["E_ads"], bins=20, alpha=0.75, edgecolor="k") plt.xlabel("E_ads (eV)") plt.ylabel("count") plt.title("CO2 on Cu(111): adsorption energy distribution (UMA)") plt.grid(alpha=0.3) plt.tight_layout() plt.savefig("adsorption_energy_distribution.png", dpi=200)正常运行后,大多数构型会聚集在 -1 ~ -1.5 eV 附近并拖出一条弱结合尾巴,就是下面这张由上面代码生成的直方图:
吸附能分布直方图:UMA 模型吸附能批量计算结果示例
收尾
- ✅ 初筛用
uma-s-1p2扫全部构型,候选切到uma-m-1p1精算,两档分开存档 - ✅ 上报吸附能前必查解离/脱附/表面重构等异常,只认干净构型里最负的那个值
- ✅ 边界候选用 DFT 单点能校正,全链路保持 fmax=0.05 eV/Å 的同一收敛标准
- ✅ 批量任务用作业调度或
num_jobs分片,结果落盘.json.gz方便断点续跑 - ✅ 跟踪 configs/uma/training_release 与
pretrained_models.json中的新 checkpoint——项目正持续扩展 OC25、OMol25 等新数据集及对应模型
开新项目前把 checkpoint 列表 diff 一遍,然后拿代码里的mp-30换成你的目标催化剂,把三步流水线跑起来。
【免费下载链接】ocpFAIR Chemistry's library of machine learning methods for chemistry项目地址: https://gitcode.com/GitHub_Trending/oc/ocp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考