Open In Colab

Single Point

janus-core contains various machine learnt interatomic potentials (MLIPs), including MACE based models (MACE-MP, MACE-OFF), CHGNet, and matgl based M3GNet.

Other will be added as their utility is proven beyond a specific material.

Set up environment (optional)

These steps are required for Google Colab, but may work on other systems too:

[ ]:
# import locale
# locale.getpreferredencoding = lambda: "UTF-8"
# !python3 -m pip install janus-core[all]

Use data_tutorials to get the data required for this tutorial:

[ ]:
from data_tutorials.data import get_data

get_data(
    url="https://raw.githubusercontent.com/stfc/janus-tutorials/main/data/",
    filename=["sucrose.xyz", "NaCl-set.xyz"],
    folder="data",
)

Single point calculations for periodic system

[ ]:
from ase.build import bulk

from janus_core.calculations.single_point import SinglePoint

# Change to cuda if you have a gpu or mps for apple silicon
device = "cpu"

NaCl = bulk("NaCl", "rocksalt", a=5.63, cubic=True)
sp = SinglePoint(
    struct=NaCl,
    arch="mace_mp",
    device=device,
    calc_kwargs={"model_paths": "small", "default_dtype": "float64"},
)

res_mace = sp.run()

NaCl = bulk("NaCl", "rocksalt", a=5.63, cubic=True)
sp = SinglePoint(
    struct=NaCl,
    arch="m3gnet",
    device=device,
)

res_chgnet = sp.run()

NaCl = bulk("NaCl", "rocksalt", a=5.63, cubic=True)
sp = SinglePoint(
    struct=NaCl,
    arch="chgnet",
    device=device,
)

res_m3gnet = sp.run()

print(f"  MACE[eV]: {res_mace['energy']}")
print(f"M3GNET[eV]: {res_m3gnet['energy']}")
print(f"CHGNET[eV]: {res_chgnet['energy']}")

Simple Molecules

[ ]:
from ase.build import molecule
from ase.visualize import view

from janus_core.calculations.single_point import SinglePoint

sp = SinglePoint(
    struct=molecule("H2O"),
    arch="mace_off",
    device=device,
    calc_kwargs={"model_paths": "medium"},
)
res = sp.run()
print(res)
view(NaCl, viewer="x3d")

Sugar on salt

[ ]:
from ase.build import add_adsorbate, bulk
from ase.io import read, write
from ase.visualize import view

a = 5.63
NaCl = bulk(
    "NaCl", crystalstructure="rocksalt", cubic=True, orthorhombic=True, a=5.63
) * (6, 6, 3)

NaCl.center(vacuum=20.0, axis=2)
sugar = read("data/sucrose.xyz")
add_adsorbate(slab=NaCl, adsorbate=sugar, height=4.5, position=(10, 10))
write("slab.xyz", NaCl)

sp = SinglePoint(
    struct_path="slab.xyz",
    arch="mace_mp",
    device=device,
    calc_kwargs={"model_paths": "small"},
)
res = sp.run()
print(res)
view(NaCl, viewer="x3d")

Calculate an entire collection of data frames

[ ]:
from ase.io import read
import matplotlib.pyplot as plt
import numpy as np

frames = read("data/NaCl-set.xyz", format="extxyz", index=":")
dft_energy = np.array([s.info["dft_energy"] / len(s) for s in frames])

sp = SinglePoint(
    struct_path="data/NaCl-set.xyz",
    arch="mace_mp",
    device=device,
    calc_kwargs={"model_paths": "small"},
)
sp.run()

mace_mp_energy = np.array([s.info["mace_mp_energy"] / len(s) for s in sp.struct])
rmse_mace = np.linalg.norm(mace_mp_energy - dft_energy) / np.sqrt(len(dft_energy))

sp = SinglePoint(struct_path="data/NaCl-set.xyz", arch="chgnet", device=device)
sp.run()

chgnet_energy = np.array([s.info["chgnet_energy"] / len(s) for s in sp.struct])
rmse_chgnet = np.linalg.norm(chgnet_energy - dft_energy) / np.sqrt(len(dft_energy))

sp = SinglePoint(struct_path="data/NaCl-set.xyz", arch="m3gnet", device=device)
sp.run()

m3gnet_energy = np.array([s.info["m3gnet_energy"] / len(s) for s in sp.struct])
rmse_m3gnet = np.linalg.norm(m3gnet_energy - dft_energy) / np.sqrt(len(dft_energy))

print(
    f"rmse: mace_mp = {rmse_mace}, chgnet = {rmse_chgnet}, "
    f"m3gnet = {rmse_m3gnet} eV/atom"
)

fig, ax = plt.subplots()

ax.scatter(dft_energy, mace_mp_energy, marker="o", label="mace-mp-0")
ax.scatter(dft_energy, m3gnet_energy, marker="x", label="m3gnet")
ax.scatter(dft_energy, chgnet_energy, marker="+", label="chgnet")
ax.legend()
plt.xlabel("MLIP [eV/atom]")
plt.ylabel("DFT [eV/atom]")

plt.show()