FAIRChem v2、多領域原子シミュレーションを統一フレームワークで実現
FAIRChem v2 は UMA 汎用機械学習原子間ポテンシャルを統合し、分子化学から触媒・無機材料に至る多領域の原子シミュレーションを単一のフレームワークで実行可能にするツールキットとして発表された。
AI算出
主要ニュースainew評価標準
記事は FAIR の新しい汎用機械学習ポテンシャル「UMA」およびフレームワーク「FAIRChem v2」の発表を報じており、AI モデルとツールそのものが主題であるため ai_relevance は最高値となる。同クラスターに先行記事がないこと、かつ具体的なモデル名(uma-s-1p2)や機能拡張が明記されていることから novelty も高く評価される。検索機会については「FAIRChem v2」および「UMA」という固有名詞が含まれるため 1.0 とする。日本企業や日本固有の情報が含まれていないため japan_relevance は低めとなる。
6つの評価軸を見る
- AI関連度
- 100
- 情報源の信頼性
- 25
- 新規性
- 75
- 調べる価値
- 75
- 重複の少なさ
- 100
- 日本での有用性
- 25
この記事の3ポイント
- 1
多領域統合シミュレーションの実現
- 2
包括的な計算機能の統合
- 3
ASE との連携と GPU 活用
なぜ重要か・誰に関係するか
この発表は、従来のドメイン固有モデルに依存していた原子シミュレーションのワークフローを単一の汎用モデルで統合することで、研究開発の効率化と計算コストの削減を実現する可能性を示す。特に計算化学や材料科学の研究者、および AI を活用した新素材探索を行う企業の R&D 担当者は、多様な物性評価を一つのフレームワークで完結させる手法として本技術の導入を検討すべきである。
AI深層分析を開く2026年7月26日 12:23
キーポイント
多領域統合シミュレーションの実現
FAIRChem v2 は分子化学、触媒反応、無機材料の各ドメインを跨ぐ単一の汎用機械学習原子間ポテンシャル(UMA)を提供し、異なる計算化学ワークフローを統一された環境で処理する。
包括的な計算機能の統合
同フレームワークはエネルギー・力予測、幾何構造最適化、スピン状態比較、反応エネルギー推定、振動解析、表面吸着、結晶セル緩和、状態方程式フィッティング、分子動力学、ポテンシャルエネルギー面走査など多様な計算タスクに対応する。
ASE との連携と GPU 活用
FAIRChem は原子シミュレーション環境(ASE)と統合され、原子構造管理や軌道分析を効率化するとともに、利用可能な場合は GPU アクセラレーションを活用して計算速度を向上させる。
Hugging Face 経由のモデルアクセス
ゲートされた UMA モデル重みへのアクセスには Hugging Face での認証が必要であり、本ツールは環境構築から認証プロセスまでを含む包括的なチュートリアルを提供する。
FAIRChem v2 UMA の実装と認証
Google Colab環境で安全に再実行可能なセットアップを行い、Hugging Faceへの認証を通じてゲート付きモデルウェイトを自動検出・ロードする。
重要な引用
FAIRChem v2 and the UMA universal machine-learning interatomic potential as a unified framework for atomistic simulation across molecular chemistry, catalysis, and inorganic materials.
We then apply the same pretrained potential to a broad set of computational chemistry workflows, including single-point energy and force prediction, molecular geometry optimization, spin-state comparison, reaction-energy estimation, vibrational analysis, surface adsorption, crystal-cell relaxation, equation-of-state fitting, molecular dynamics, and potential-energy surface scanning.
"We install the required FAIRChem... ensuring the setup remains safe to rerun in Google Colab."
"Atomization energy of H2O = {E_atomization:.3f} eV (experiment ~ 9.5 eV incl. ZPE effects)"
編集コメントを表示
編集コメント
FAIRChem v2 は UMA モデルの汎用性を最大限に引き出すツールキットとして、計算化学分野における標準的なワークフローを再定義する重要な進展である。Hugging Face と ASE を活用した実装例は、研究者が即座に多領域シミュレーションを試行可能にする実践的な価値を持つ。
本チュートリアルでは、分子化学、触媒反応、無機材料にわたる原子レベルシミュレーションのための統一フレームワークとして、FAIRChem v2 と UMA(ユニバーサル・マシンラーニング原子間ポテンシャル)を紹介します。まず環境を設定し、Hugging Face で認証してゲートされた UMA モデルの重みにアクセスします。その後、omol、oc20、omat の各ドメインに特化した計算機を初期化します。
次に、単一点エネルギーと力の予測、分子構造最適化、スピン状態の比較、反応エネルギー推定、振動解析、表面吸着、結晶セルの緩和、状態方程式のフィッティング、分子動力学、ポテンシャルエネルギー面の走査など、幅広い計算化学ワークフローに同じ事前学習済みポテンシャルを適用します。
本チュートリアル全体を通じて、原子構造の管理、最適化アルゴリズム、制約条件の設定、熱力学的計算、軌道解析を行うために FAIRChem を Atomic Simulation Environment(ASE)と統合し、利用可能な場合は GPU 加速を活用して処理を行います。
import importlib.util, subprocess, sys, os
def _pip(*pkgs):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
if importlib.util.find_spec("fairchem") is None:
print(">> Installing fairchem-core, ase, and helpers (takes ~2-4 min)...")
_pip("fairchem-core", "ase", "matplotlib", "huggingface_hub")
print(">> Installation done.")
else:
print(">> fairchem already installed.")
from huggingface_hub import login, whoami
def hf_authenticate():
token = None
try:
from google.colab import userdata
token = userdata.get("HF_TOKEN")
except Exception:
pass
token = token or os.environ.get("HF_TOKEN")
try:
whoami()
print(">> Already authenticated with Hugging Face.")
return
except Exception:
pass
if token is None:
from getpass import getpass
token = getpass("Paste your Hugging Face access token: ").strip()
login(token=token)
print(">> Hugging Face login OK.")
hf_authenticate()
import numpy as np
import torch
import matplotlib.pyplot as plt
from fairchem.core import pretrained_mlip, FAIRChemCalculator
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
print(f">> Using device: {DEVICE}")
MODEL = "uma-s-1p2"
predictor = pretrained_mlip.get_predict_unit(MODEL, device=DEVICE)
calc_mol = FAIRChemCalculator(predictor, task_name="omol")
calc_cat = FAIRChemCalculator(predictor, task_name="oc20")
calc_mat = FAIRChemCalculator(predictor, task_name="omat")
print(f">> Loaded {MODEL} with omol / oc20 / omat calculators.")
Google Colab で安全に再実行できるよう、必要な FAIRChem、ASE、可視化ライブラリ、Hugging Face の依存関係をインストールします。ゲート付き UMA モデルの重みにアクセスするために Hugging Face への認証を行い、GPU アクセラレーションの利用可否も自動的に検出します。その後、UMA プリディクターを読み込み、分子・触媒・材料シミュレーションそれぞれに専用の計算器を作成します。
from ase.build import molecule
from ase import Atoms
print("\n" + "="*70)
print("SECTION 2: Single-point energetics of water (omol task)")
print("="*70)
h2o = molecule("H2O")
h2o.info.update({"charge": 0, "spin": 1})
h2o.calc = calc_mol
E_h2o = h2o.get_potential_energy()
F_h2o = h2o.get_forces()
print(f"E(H2O) = {E_h2o:.4f} eV")
print(f"Max |force| = {np.abs(F_h2o).max():.4f} eV/A")
def atom_energy(symbol, spin):
a = Atoms(symbol, positions=[[0, 0, 0]])
a.info.update({"charge": 0, "spin": spin})
a.calc = calc_mol
return a.get_potential_energy()
E_O = atom_energy("O", spin=3)
E_H = atom_energy("H", spin=2)
E_atomization = -(E_h2o - E_O - 2 * E_H)
print(f"Atomization energy of H2O = {E_atomization:.3f} eV "
f"(experiment ~ 9.5 eV incl. ZPE effects)")
from ase.optimize import LBFGS
print("\n" + "="*70)
print("SECTION 3: Relaxing a deliberately distorted water molecule")
print("="*70)
h2o_bad = molecule("H2O")
h2o_bad.positions[1] += [0.25, -0.10, 0.05]
h2o_bad.info.update({"charge": 0, "spin": 1})
h2o_bad.calc = calc_mol
opt = LBFGS(h2o_bad, logfile=None)
energies_opt = []
opt.attach(lambda: energies_opt.append(h2o_bad.get_potential_energy()))
opt.run(fmax=0.01, steps=200)
d_OH = h2o_bad.get_distance(0, 1)
ang = h2o_bad.get_angle(1, 0, 2)
print(f"Converged in {opt.get_number_of_steps()} steps")
print(f"O-H bond length = {d_OH:.3f} A (expt ~0.958 A)")
print(f"H-O-H angle = {ang:.1f} deg (expt ~104.5 deg)")
plt.figure(figsize=(5, 3.2))
plt.plot(energies_opt, "o-")
plt.xlabel("Optimizer step"); plt.ylabel("Energy (eV)")
plt.title("H2O geometry optimization"); plt.tight_layout(); plt.show()
分子 UMA カルキュレーターを用いて、水分子のエネルギー、原子力、および解離エネルギーを評価します。原子化エネルギーの計算を行うために、適切なスピン多重度を持つ孤立した水素原子と酸素原子を参照原子として定義します。
その後、水分子の幾何構造を変形させ、LBFGS オプティマイザーで緩和処理を行い、収束後の結合長、結合角、およびエネルギー軌跡を解析します。
print("\n" + "="*70)
print("SECTION 4: CH2 singlet-triplet gap (UMA is spin-aware!)")
print("="*70)
singlet = molecule("CH2_s1A1d"); singlet.info.update({"charge": 0, "spin": 1})
triplet = molecule("CH2_s3B1d"); triplet.info.update({"charge": 0, "spin": 3})
singlet.calc = FAIRChemCalculator(predictor, task_name="omol")
triplet.calc = FAIRChemCalculator(predictor, task_name="omol")
gap = triplet.get_potential_energy() - singlet.get_potential_energy()
print(f"E(triplet) - E(singlet) = {gap:.3f} eV "
f"(negative => triplet ground state; expt ~ -0.39 eV)")
print("\n" + "="*70)
print("SECTION 5: Reaction energy of CH4 + 2 O2 -> CO2 + 2 H2O")
print("="*70)
def relaxed_energy(name, spin=1):
m = molecule(name)
m.info.update({"charge": 0, "spin": spin})
m.calc = FAIRChemCalculator(predictor, task_name="omol")
LBFGS(m, logfile=None).run(fmax=0.02, steps=200)
return m.get_potential_energy()
E = {
"CH4": relaxed_energy("CH4"),
"O2": relaxed_energy("O2", spin=3),
"CO2": relaxed_energy("CO2"),
"H2O": relaxed_energy("H2O"),
}
dE_rxn = (E["CO2"] + 2*E["H2O"]) - (E["CH4"] + 2*E["O2"])
print(f"Delta E (electronic) = {dE_rxn:.2f} eV = {dE_rxn*96.485:.0f} kJ/mol")
print("Experimental combustion enthalpy ~ -890 kJ/mol (ZPE/thermal not included here)")
from ase.vibrations import Vibrations
print("\n" + "="*70)
print("SECTION 6: Vibrational frequencies of relaxed H2O")
print("="*70)
vib = Vibrations(h2o_bad, name="vib_h2o")
vib.run()
freqs = np.real(vib.get_frequencies())
real_modes = [f for f in freqs if f > 200]
print("Vibrational modes (cm^-1):", ", ".join(f"{f:.0f}" for f in real_modes))
print("Experimental H2O: 1595 (bend), 3657 (sym stretch), 3756 (asym stretch)")
print(f"Zero-point energy = {vib.get_zero_point_energy():.3f} eV")
vib.clean()
メチレンの単重項と三重項の電子状態を比較し、スピン状態間のエネルギー差を算出します。また、メタン、酸素、二酸化炭素、水をそれぞれ最適化(構造緩和)した上で予測されたエネルギー値を組み合わせて、メタンの燃焼に伴う電子反応エネルギーを推定します。さらに、最適化した水分子に対して有限差分法による振動解析を行い、固有モードの周波数と零点エネルギーを取得します。
from ase.build import fcc100, add_adsorbate
from ase.constraints import FixAtoms
print("\n" + "="*70)
print("SECTION 7: CO/Cu(100) relaxation + adsorption energy (oc20 task)")
print("="*70)
slab = fcc100("Cu", size=(3, 3, 3), vacuum=8.0, periodic=True)
slab.set_constraint(FixAtoms(mask=[a.tag > 1 for a in slab]))
add_adsorbate(slab, molecule("CO"), height=2.0, position="bridge")
slab.calc = calc_cat
opt = LBFGS(slab, logfile=None)
opt.run(fmax=0.05, steps=300)
E_slab_ads = slab.get_potential_energy()
print(f"Relaxed CO/Cu(100) in {opt.get_number_of_steps()} steps, "
f"E = {E_slab_ads:.3f} eV")
clean = fcc100("Cu", size=(3, 3, 3), vacuum=8.0, periodic=True)
clean.set_constraint(FixAtoms(mask=[a.tag > 1 for a in clean]))
clean.calc = FAIRChemCalculator(predictor, task_name="oc20")
LBFGS(clean, logfile=None).run(fmax=0.05, steps=300)
E_clean = clean.get_potential_energy()
co = molecule("CO"); co.info.update({"charge": 0, "spin": 1})
co.calc = FAIRChemCalculator(predictor, task_name="omol")
LBFGS(co, logfile=None).run(fmax=0.02, steps=100)
E_co = co.get_potential_energy()
E_ads = E_slab_ads - E_clean - E_co
print(f"E(clean slab) = {E_clean:.3f} eV, E(CO gas) = {E_co:.3f} eV")
print(f"Adsorption energy (naive cycle) = {E_ads:.3f} eV")
print("(oc20 uses its own DFT reference scheme; for publication-grade numbers")
print(" keep all species within a consistent task/reference framework.)")
周期構造を持つ Cu(100) スラブを構築し、一酸化炭素分子をブリッジ吸着サイトに配置した上で、下部の銅層を固定します。その後、OC20 カルキュレーターを用いて吸着体と表面系の緩和を行い、同時にクリーンなスラブおよび気相の一酸化炭素を参照として個別に最適化します。最後に、OC20 がタスク固有のエネルギー基準を採用していることを踏まえつつ、教育的な吸着エネルギーサイクルの評価を行います。
Copy CodeCopiedUse a different Browser
from ase.build import bulk
from ase.optimize import FIRE
from ase.filters import FrechetCellFilter
from ase.eos import EquationOfState
print("\n" + "="*70)
print("SECTION 8: BCC iron — full cell relaxation and bulk modulus (omat)")
print("="*70)
fe = bulk("Fe", "bcc", a=2.9)
fe.calc = calc_mat
FIRE(FrechetCellFilter(fe), logfile=None).run(fmax=0.02, steps=300)
a_relaxed = fe.cell.cellpar()[0]
print(f"Relaxed BCC Fe lattice constant = {a_relaxed:.3f} A (expt ~2.866 A)")
volumes, energies = [], []
cell0 = fe.get_cell()
for scale in np.linspace(0.94, 1.06, 9):
s = fe.copy()
s.set_cell(cell0 * scale, scale_atoms=True)
s.calc = FAIRChemCalculator(predictor, task_name="omat")
volumes.append(s.get_volume())
energies.append(s.get_potential_energy())
eos = EquationOfState(volumes, energies, eos="birchmurnaghan")
v0, e0, B = eos.fit()
from ase.units import GPa as _GPa
B_GPa = B / _GPa
print(f"Equilibrium volume = {v0:.2f} A^3/cell")
print(f"Bulk modulus = {B_GPa:.0f} GPa (expt ~170 GPa for Fe)")
plt.figure(figsize=(5, 3.2))
plt.plot(volumes, energies, "o", label="UMA points")
vfit = np.linspace(min(volumes), max(volumes), 100)
plt.plot(vfit, [eos.func(v, *eos.eos_parameters) for v in vfit], "-", label="BM fit")
plt.xlabel("Volume (A^3)"); plt.ylabel("Energy (eV)")
plt.title("BCC Fe equation of state"); plt.legend(); plt.tight_layout(); plt.show()
from ase import units
from ase.md.langevin import Langevin
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
print("\n" + "="*70)
print("SECTION 9: 0.5 ps Langevin MD of a water molecule at 300 K")
print("="*70)
md_atoms = molecule("H2O")
md_atoms.info.update({"charge": 0, "spin": 1})
seed = int(np.random.randint(0, np.iinfo(np.int32).max))
md_predictor = pretrained_mlip.get_predict_unit(MODEL, device=DEVICE, seed=seed)
md_atoms.calc = FAIRChemCalculator(md_predictor, task_name="omol")
MaxwellBoltzmannDistribution(md_atoms, temperature_K=300)
dyn = Langevin(md_atoms, timestep=0.5 * units.fs,
temperature_K=300, friction=0.01 / units.fs)
times, temps, epots, d_oh1 = [], [], [], []
def log_md():
t = dyn.get_number_of_steps() * 0.5
times.append(t)
temps.append(md_atoms.get_temperature())
epots.append(md_atoms.get_potential_energy())
d_oh1.append(md_atoms.get_distance(0, 1))
dyn.attach(log_md, interval=5)
dyn.run(steps=1000)
print(f"MD done. = {np.mean(temps[10:]):.0f} K, "
f" = {np.mean(d_oh1):.3f} A")
fig, ax = plt.subplots(1, 3, figsize=(12, 3.2))
ax[0].plot(times, temps); ax[0].set_title("Temperature (K)")
ax[1].plot(times, epots); ax[1].set_title("Potential energy (eV)")
ax[2].plot(times, d_oh1); ax[2].set_title("O-H bond length (A)")
for a in ax: a.set_xlabel("time (fs)")
plt.tight_layout(); plt.show()
FAIRChem v2 UMA を用いて、BCC 鉄の原子位置とシミュレーションセルを緩和します。ここでは Frechet セルフィルタを活用し、圧縮・膨張した体積範囲にわたってエネルギーをサンプリング。Birch–Murnaghan の状態方程式をフィッティングすることで、平衡体積や体積弾性率を推定します。
また、300 K における水のランジュアン分子動力学シミュレーションも実行。時間経過に伴う温度、ポテンシャルエネルギー、O–H 結合長の変化を追跡します。
print("\n" + "="*70)
print("SECTION 10: O-H bond stretch scan in water")
print("="*70)
distances = np.linspace(0.7, 2.5, 25)
pes = []
for d in distances:
a = molecule("H2O")
a.info.update({"charge": 0, "spin": 1})
vec = a.positions[1] - a.positions[0]
a.positions[1] = a.positions[0] + vec / np.linalg.norm(vec) * d
a.calc = FAIRChemCalculator(predictor, task_name="omol")
pes.append(a.get_potential_energy())
pes = np.array(pes) - min(pes)
plt.figure(figsize=(5.5, 3.4))
plt.plot(distances, pes, "o-")
plt.axvline(0.958, ls="--", c="gray", label="expt r_e")
plt.xlabel("O-H distance (A)"); plt.ylabel("Relative energy (eV)")
plt.title("O-H stretch PES from UMA"); plt.legend()
plt.tight_layout(); plt.show()
print("\n" + "="*70)
print("TUTORIAL COMPLETE!")
print("="*70)
print("""
Next steps to explore:
- Swap MODEL to "uma-m-1p1" for higher accuracy (needs more GPU memory).
- Try task_name="odac" with a MOF CIF, or "omc" for molecular crystals.
- Larger MD: fairchem supports multi-GPU inference via workers=N
(pip install fairchem-core[extras]).
- Docs: https://fair-chem.github.io/
""")
水分子のポテンシャルエネルギー表面を、特定の距離範囲にわたって O–H 結合を系統的に引き伸ばすことでスキャンします。各幾何構造における分子エネルギーを評価し、最小値に対する相対値として正規化して、得られた解離プロファイルを可視化しました。
本チュートリアルの最後には、より高精度な UMA モデルや追加の化学ドメイン、大規模なマルチ GPU シミュレーションへの拡張可能性について言及しています。
結論として、FAIRChem v2 を中心とした完全な原子論的シミュレーションワークフローを構築し、UMA が各タスクごとに個別モデルを用意することなく、化学的に異なるドメイン間で共有された学習済みポテンシャルを提供できることを実証しました。分子計算を用いてエネルギーや力、原子化挙動、スピンギャップ、反応エネルギー、振動モード、結合引き伸ばしプロファイルを評価しました。触媒分野では CO を Cu(100) 表面に吸着させて緩和し、吸着エネルギーを調べました。材料分野では BCC 鉄を緩和し、状態方程式のフィットから体積弾性率を推定しました。また、ランジュアン分子動力学を実行して、有限温度における時間経過に伴う構造とエネルギーの変動を観察しました。
UMA の推論に ASE(Atomic Simulation Environment)の構造ビルダー、最適化器、フィルタ、振動解析ツール、分子動力学ユーティリティを組み合わせることで、より大きな分子や触媒界面、結晶材料、金属有機骨格(MOF)、分子結晶、そして高精度な UMA モデルバリアントへのワークフロー拡張を可能にする再利用可能な基盤を整備しました。
詳細なコードは、こちらからご確認ください。
また、Twitter でフォローしていただくと幸いです。15 万人以上の ML 関係者が参加する当社の SubReddit への参加や、ニュースレターの購読もぜひご検討ください。Telegram をご利用の方にも、今なら Telegram チャンネルへのご参加をお勧めします。
GitHub リポジトリの紹介、Hugging Face ページの宣伝、製品リリース、ウェビナーなど、パートナーシップをご希望の場合は、お気軽にご連絡ください。
本記事「FAIRChem v2 UMA:分子、触媒、材料、振動、分子動力学にわたるマルチドメイン原子シミュレーション」は、MarkTechPost で最初に公開されました。
原文を表示
In this tutorial, we explore FAIRChem v2 and the UMA universal machine-learning interatomic potential as a unified framework for atomistic simulation across molecular chemistry, catalysis, and inorganic materials. We configure an environment, authenticate with Hugging Face to access the gated UMA model weights, and initialize task-specific calculators for the omol, oc20, and omat domains. We then apply the same pretrained potential to a broad set of computational chemistry workflows, including single-point energy and force prediction, molecular geometry optimization, spin-state comparison, reaction-energy estimation, vibrational analysis, surface adsorption, crystal-cell relaxation, equation-of-state fitting, molecular dynamics, and potential-energy surface scanning. Throughout the tutorial, we integrate FAIRChem with the Atomic Simulation Environment to manage atomic structures, optimizers, constraints, thermodynamic calculations, and trajectory analysis while using GPU acceleration whenever it is available.
Copy CodeCopiedUse a different Browser
import importlib.util, subprocess, sys, os
def _pip(*pkgs):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
if importlib.util.find_spec("fairchem") is None:
print(">> Installing fairchem-core, ase, and helpers (takes ~2-4 min)...")
_pip("fairchem-core", "ase", "matplotlib", "huggingface_hub")
print(">> Installation done.")
else:
print(">> fairchem already installed.")
from huggingface_hub import login, whoami
def hf_authenticate():
token = None
try:
from google.colab import userdata
token = userdata.get("HF_TOKEN")
except Exception:
pass
token = token or os.environ.get("HF_TOKEN")
try:
whoami()
print(">> Already authenticated with Hugging Face.")
return
except Exception:
pass
if token is None:
from getpass import getpass
token = getpass("Paste your Hugging Face access token: ").strip()
login(token=token)
print(">> Hugging Face login OK.")
hf_authenticate()
import numpy as np
import torch
import matplotlib.pyplot as plt
from fairchem.core import pretrained_mlip, FAIRChemCalculator
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
print(f">> Using device: {DEVICE}")
MODEL = "uma-s-1p2"
predictor = pretrained_mlip.get_predict_unit(MODEL, device=DEVICE)
calc_mol = FAIRChemCalculator(predictor, task_name="omol")
calc_cat = FAIRChemCalculator(predictor, task_name="oc20")
calc_mat = FAIRChemCalculator(predictor, task_name="omat")
print(f">> Loaded {MODEL} with omol / oc20 / omat calculators.")
We install the required FAIRChem, ASE, visualization, and Hugging Face dependencies while ensuring the setup remains safe to rerun in Google Colab. We authenticate with Hugging Face to access the gated UMA model weights and automatically detect whether GPU acceleration is available. We then load the UMA predictor and create separate calculators for molecular, catalysis, and materials simulations.
Copy CodeCopiedUse a different Browser
from ase.build import molecule
from ase import Atoms
print("\n" + "="*70)
print("SECTION 2: Single-point energetics of water (omol task)")
print("="*70)
h2o = molecule("H2O")
h2o.info.update({"charge": 0, "spin": 1})
h2o.calc = calc_mol
E_h2o = h2o.get_potential_energy()
F_h2o = h2o.get_forces()
print(f"E(H2O) = {E_h2o:.4f} eV")
print(f"Max |force| = {np.abs(F_h2o).max():.4f} eV/A")
def atom_energy(symbol, spin):
a = Atoms(symbol, positions=[[0, 0, 0]])
a.info.update({"charge": 0, "spin": spin})
a.calc = calc_mol
return a.get_potential_energy()
E_O = atom_energy("O", spin=3)
E_H = atom_energy("H", spin=2)
E_atomization = -(E_h2o - E_O - 2 * E_H)
print(f"Atomization energy of H2O = {E_atomization:.3f} eV "
f"(experiment ~ 9.5 eV incl. ZPE effects)")
from ase.optimize import LBFGS
print("\n" + "="*70)
print("SECTION 3: Relaxing a deliberately distorted water molecule")
print("="*70)
h2o_bad = molecule("H2O")
h2o_bad.positions[1] += [0.25, -0.10, 0.05]
h2o_bad.info.update({"charge": 0, "spin": 1})
h2o_bad.calc = calc_mol
opt = LBFGS(h2o_bad, logfile=None)
energies_opt = []
opt.attach(lambda: energies_opt.append(h2o_bad.get_potential_energy()))
opt.run(fmax=0.01, steps=200)
d_OH = h2o_bad.get_distance(0, 1)
ang = h2o_bad.get_angle(1, 0, 2)
print(f"Converged in {opt.get_number_of_steps()} steps")
print(f"O-H bond length = {d_OH:.3f} A (expt ~0.958 A)")
print(f"H-O-H angle = {ang:.1f} deg (expt ~104.5 deg)")
plt.figure(figsize=(5, 3.2))
plt.plot(energies_opt, "o-")
plt.xlabel("Optimizer step"); plt.ylabel("Energy (eV)")
plt.title("H2O geometry optimization"); plt.tight_layout(); plt.show()
We use the molecular UMA calculator to evaluate the energy, atomic forces, and atomization energy of a water molecule. We define isolated hydrogen and oxygen reference atoms with the correct spin multiplicities to construct the atomization-energy calculation. We then distort the water geometry, relax it with the LBFGS optimizer, and analyze the converged bond length, bond angle, and energy trajectory.
Copy CodeCopiedUse a different Browser
print("\n" + "="*70)
print("SECTION 4: CH2 singlet-triplet gap (UMA is spin-aware!)")
print("="*70)
singlet = molecule("CH2_s1A1d"); singlet.info.update({"charge": 0, "spin": 1})
triplet = molecule("CH2_s3B1d"); triplet.info.update({"charge": 0, "spin": 3})
singlet.calc = FAIRChemCalculator(predictor, task_name="omol")
triplet.calc = FAIRChemCalculator(predictor, task_name="omol")
gap = triplet.get_potential_energy() - singlet.get_potential_energy()
print(f"E(triplet) - E(singlet) = {gap:.3f} eV "
f"(negative => triplet ground state; expt ~ -0.39 eV)")
print("\n" + "="*70)
print("SECTION 5: Reaction energy of CH4 + 2 O2 -> CO2 + 2 H2O")
print("="*70)
def relaxed_energy(name, spin=1):
m = molecule(name)
m.info.update({"charge": 0, "spin": spin})
m.calc = FAIRChemCalculator(predictor, task_name="omol")
LBFGS(m, logfile=None).run(fmax=0.02, steps=200)
return m.get_potential_energy()
E = {
"CH4": relaxed_energy("CH4"),
"O2": relaxed_energy("O2", spin=3),
"CO2": relaxed_energy("CO2"),
"H2O": relaxed_energy("H2O"),
}
dE_rxn = (E["CO2"] + 2*E["H2O"]) - (E["CH4"] + 2*E["O2"])
print(f"Delta E (electronic) = {dE_rxn:.2f} eV = {dE_rxn*96.485:.0f} kJ/mol")
print("Experimental combustion enthalpy ~ -890 kJ/mol (ZPE/thermal not included here)")
from ase.vibrations import Vibrations
print("\n" + "="*70)
print("SECTION 6: Vibrational frequencies of relaxed H2O")
print("="*70)
vib = Vibrations(h2o_bad, name="vib_h2o")
vib.run()
freqs = np.real(vib.get_frequencies())
real_modes = [f for f in freqs if f > 200]
print("Vibrational modes (cm^-1):", ", ".join(f"{f:.0f}" for f in real_modes))
print("Experimental H2O: 1595 (bend), 3657 (sym stretch), 3756 (asym stretch)")
print(f"Zero-point energy = {vib.get_zero_point_energy():.3f} eV")
vib.clean()
We compare the singlet and triplet electronic states of methylene to calculate its spin-state energy gap. We relax methane, oxygen, carbon dioxide, and water before combining their predicted energies to estimate the electronic reaction energy of methane combustion. We also perform a finite-difference vibrational analysis of relaxed water to obtain its normal-mode frequencies and zero-point energy.
Copy CodeCopiedUse a different Browser
from ase.build import fcc100, add_adsorbate
from ase.constraints import FixAtoms
print("\n" + "="*70)
print("SECTION 7: CO/Cu(100) relaxation + adsorption energy (oc20 task)")
print("="*70)
slab = fcc100("Cu", size=(3, 3, 3), vacuum=8.0, periodic=True)
slab.set_constraint(FixAtoms(mask=[a.tag > 1 for a in slab]))
add_adsorbate(slab, molecule("CO"), height=2.0, position="bridge")
slab.calc = calc_cat
opt = LBFGS(slab, logfile=None)
opt.run(fmax=0.05, steps=300)
E_slab_ads = slab.get_potential_energy()
print(f"Relaxed CO/Cu(100) in {opt.get_number_of_steps()} steps, "
f"E = {E_slab_ads:.3f} eV")
clean = fcc100("Cu", size=(3, 3, 3), vacuum=8.0, periodic=True)
clean.set_constraint(FixAtoms(mask=[a.tag > 1 for a in clean]))
clean.calc = FAIRChemCalculator(predictor, task_name="oc20")
LBFGS(clean, logfile=None).run(fmax=0.05, steps=300)
E_clean = clean.get_potential_energy()
co = molecule("CO"); co.info.update({"charge": 0, "spin": 1})
co.calc = FAIRChemCalculator(predictor, task_name="omol")
LBFGS(co, logfile=None).run(fmax=0.02, steps=100)
E_co = co.get_potential_energy()
E_ads = E_slab_ads - E_clean - E_co
print(f"E(clean slab) = {E_clean:.3f} eV, E(CO gas) = {E_co:.3f} eV")
print(f"Adsorption energy (naive cycle) = {E_ads:.3f} eV")
print("(oc20 uses its own DFT reference scheme; for publication-grade numbers")
print(" keep all species within a consistent task/reference framework.)")
We construct a periodic Cu(100) slab, place a carbon monoxide molecule at a bridge adsorption site, and constrain the lower copper layers. We relax the adsorbate–surface system with the OC20 calculator and separately optimize the clean slab and gas-phase carbon monoxide references. We then evaluate a pedagogical adsorption-energy cycle while recognizing that OC20 uses a task-specific energy reference convention.
Copy CodeCopiedUse a different Browser
from ase.build import bulk
from ase.optimize import FIRE
from ase.filters import FrechetCellFilter
from ase.eos import EquationOfState
print("\n" + "="*70)
print("SECTION 8: BCC iron — full cell relaxation and bulk modulus (omat)")
print("="*70)
fe = bulk("Fe", "bcc", a=2.9)
fe.calc = calc_mat
FIRE(FrechetCellFilter(fe), logfile=None).run(fmax=0.02, steps=300)
a_relaxed = fe.cell.cellpar()[0]
print(f"Relaxed BCC Fe lattice constant = {a_relaxed:.3f} A (expt ~2.866 A)")
volumes, energies = [], []
cell0 = fe.get_cell()
for scale in np.linspace(0.94, 1.06, 9):
s = fe.copy()
s.set_cell(cell0 * scale, scale_atoms=True)
s.calc = FAIRChemCalculator(predictor, task_name="omat")
volumes.append(s.get_volume())
energies.append(s.get_potential_energy())
eos = EquationOfState(volumes, energies, eos="birchmurnaghan")
v0, e0, B = eos.fit()
from ase.units import GPa as _GPa
B_GPa = B / _GPa
print(f"Equilibrium volume = {v0:.2f} A^3/cell")
print(f"Bulk modulus = {B_GPa:.0f} GPa (expt ~170 GPa for Fe)")
plt.figure(figsize=(5, 3.2))
plt.plot(volumes, energies, "o", label="UMA points")
vfit = np.linspace(min(volumes), max(volumes), 100)
plt.plot(vfit, [eos.func(v, *eos.eos_parameters) for v in vfit], "-", label="BM fit")
plt.xlabel("Volume (A^3)"); plt.ylabel("Energy (eV)")
plt.title("BCC Fe equation of state"); plt.legend(); plt.tight_layout(); plt.show()
from ase import units
from ase.md.langevin import Langevin
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
print("\n" + "="*70)
print("SECTION 9: 0.5 ps Langevin MD of a water molecule at 300 K")
print("="*70)
md_atoms = molecule("H2O")
md_atoms.info.update({"charge": 0, "spin": 1})
seed = int(np.random.randint(0, np.iinfo(np.int32).max))
md_predictor = pretrained_mlip.get_predict_unit(MODEL, device=DEVICE, seed=seed)
md_atoms.calc = FAIRChemCalculator(md_predictor, task_name="omol")
MaxwellBoltzmannDistribution(md_atoms, temperature_K=300)
dyn = Langevin(md_atoms, timestep=0.5 * units.fs,
temperature_K=300, friction=0.01 / units.fs)
times, temps, epots, d_oh1 = [], [], [], []
def log_md():
t = dyn.get_number_of_steps() * 0.5
times.append(t)
temps.append(md_atoms.get_temperature())
epots.append(md_atoms.get_potential_energy())
d_oh1.append(md_atoms.get_distance(0, 1))
dyn.attach(log_md, interval=5)
dyn.run(steps=1000)
print(f"MD done. <T> = {np.mean(temps[10:]):.0f} K, "
f"<d(O-H)> = {np.mean(d_oh1):.3f} A")
fig, ax = plt.subplots(1, 3, figsize=(12, 3.2))
ax[0].plot(times, temps); ax[0].set_title("Temperature (K)")
ax[1].plot(times, epots); ax[1].set_title("Potential energy (eV)")
ax[2].plot(times, d_oh1); ax[2].set_title("O-H bond length (A)")
for a in ax: a.set_xlabel("time (fs)")
plt.tight_layout(); plt.show()
We relax the atomic positions and simulation cell of BCC iron using the materials-domain UMA calculator and a Frechet cell filter. We sample energies across a range of compressed and expanded volumes, fit a Birch–Murnaghan equation of state, and estimate the equilibrium volume and bulk modulus. We also run Langevin molecular dynamics for water at 300 K and track its temperature, potential energy, and O–H bond length over time.
Copy CodeCopiedUse a different Browser
print("\n" + "="*70)
print("SECTION 10: O-H bond stretch scan in water")
print("="*70)
distances = np.linspace(0.7, 2.5, 25)
pes = []
for d in distances:
a = molecule("H2O")
a.info.update({"charge": 0, "spin": 1})
vec = a.positions[1] - a.positions[0]
a.positions[1] = a.positions[0] + vec / np.linalg.norm(vec) * d
a.calc = FAIRChemCalculator(predictor, task_name="omol")
pes.append(a.get_potential_energy())
pes = np.array(pes) - min(pes)
plt.figure(figsize=(5.5, 3.4))
plt.plot(distances, pes, "o-")
plt.axvline(0.958, ls="--", c="gray", label="expt r_e")
plt.xlabel("O-H distance (A)"); plt.ylabel("Relative energy (eV)")
plt.title("O-H stretch PES from UMA"); plt.legend()
plt.tight_layout(); plt.show()
print("\n" + "="*70)
print("TUTORIAL COMPLETE!")
print("="*70)
print("""
Next steps to explore:
- Swap MODEL to "uma-m-1p1" for higher accuracy (needs more GPU memory).
- Try task_name="odac" with a MOF CIF, or "omc" for molecular crystals.
- Larger MD: fairchem supports multi-GPU inference via workers=N
(pip install fairchem-core[extras]).
- Docs: https://fair-chem.github.io/
""")
We scan the potential-energy surface of water by systematically stretching one O–H bond across a selected distance range. We evaluate the molecular energy at each geometry, normalize the energies relative to the minimum, and visualize the resulting dissociation profile. We conclude the tutorial by identifying higher-accuracy UMA models, additional chemical domains, and larger multi-GPU simulations as possible extensions.
In conclusion, we built a complete atomistic simulation workflow around FAIRChem v2 and demonstrated how UMA provides a shared learned potential across chemically distinct domains without requiring a separate model for every task. We used molecular calculations to evaluate energies, forces, atomization behavior, spin gaps, reaction energetics, vibrational modes, and bond-stretch profiles; we used the catalysis domain to relax CO on a Cu(100) surface and examine adsorption energetics; and we used the materials domain to relax BCC iron and estimate its bulk modulus from an equation-of-state fit. We also ran Langevin molecular dynamics to observe finite-temperature structural and energetic fluctuations over time. By combining UMA inference with ASE structure builders, optimizers, filters, vibrational tools, and molecular-dynamics utilities, we established a reusable foundation for extending the workflow to larger molecules, catalytic interfaces, crystalline materials, metal-organic frameworks, molecular crystals, and higher-accuracy UMA model variants.
Check out the Full Code here. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us
The post FAIRChem v2 UMA for Multidomain Atomistic Simulation across Molecules, Catalysts, Materials, Vibrations, and Molecular Dynamics appeared first on MarkTechPost.
関連記事
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み