Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,22 @@ notebooks:
- ssl
- h5py
- lmdb
- name: sevennet
packages_pyodide:
# Packages with dependencies
- opt_einsum
- orjson
- pyyaml
- setuptools
# Packages without dependencies
- nodeps:opt_einsum_fx
- nodeps:e3nn>=0.5
- nodeps:ase
- nodeps:monty
- scikit-learn
# SevenNet slim wheel (stripped to 7net-0 model only)
- emfs:/drive/packages/sevenn-0.12.1-py3-none-any.whl
# Stubbed packages (patched by torch_pyodide with include_sevennet=True)
- ssl
- h5py
- lmdb
296 changes: 296 additions & 0 deletions other/experiments/jupyterlite/relax_structure_with_sevennet.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "33da1875",
"metadata": {},
"source": [
"# Relax Structure with SevenNet \u2014 E(3)-Equivariant GNN Potential\n",
"\n",
"This notebook demonstrates structural relaxation using **SevenNet** (7net-0),\n",
"an E(3)-equivariant graph neural network interatomic potential based on the NequIP architecture.\n",
"\n",
"The model supports all elements up to Z=89 and predicts energies, forces, and stresses."
]
},
{
"cell_type": "markdown",
"id": "d3ea9252",
"metadata": {},
"source": [
"## 1. Set Input Parameters\n",
"### 1.1. Structure and Relaxation"
]
},
{
"cell_type": "code",
"id": "d9ef36f6",
"metadata": {},
"source": [
"FOLDER = \"uploads\"\n",
"STRUCTURE_NAME = \"Interface\" # Name of the structure to load from local file\n",
"\n",
"RELAXATION_PARAMETERS = {\n",
" \"FMAX\": 0.05,\n",
"}"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "f5709f12",
"metadata": {},
"source": [
"## 2. Install Packages"
]
},
{
"cell_type": "code",
"id": "766bc77a",
"metadata": {},
"source": [
"from mat3ra.notebooks_utils.packages import install_packages\n",
"\n",
"await install_packages(\"made|api_examples|torch|sevennet\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"id": "0cedf7f5",
"metadata": {},
"source": [
"from mat3ra.notebooks_utils.pyodide.packages.torch import apply_all_patches\n",
"\n",
"apply_all_patches(include_sevennet=True)"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "b8624f00",
"metadata": {},
"source": [
"## 3. Load Materials"
]
},
{
"cell_type": "code",
"id": "b6c6efa8",
"metadata": {},
"source": [
"from mat3ra.made.material import Material\n",
"from mat3ra.notebooks_utils.material import load_material_from_folder\n",
"from mat3ra.standata.materials import Materials\n",
"\n",
"structure = load_material_from_folder(FOLDER, STRUCTURE_NAME) or Material.create(\n",
" Materials.get_by_name_first_match(STRUCTURE_NAME))\n",
"\n",
"print(f\"INFO: Found: '{structure.name}'\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "b0491324",
"metadata": {},
"source": [
"### 3.1. Visualize Input Structure"
]
},
{
"cell_type": "code",
"id": "630c1c78",
"metadata": {},
"source": [
"from mat3ra.notebooks_utils.ipython.entity.material.visualize import ViewersEnum, visualize_materials as visualize\n",
"\n",
"visualize(structure, repetitions=[1, 1, 1], rotation=\"-90x\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "00170e3a",
"metadata": {},
"source": [
"## 4. Apply Relaxation\n",
"### 4.1. Load SevenNet Model and Create Calculator"
]
},
{
"cell_type": "code",
"id": "4c06be2b",
"metadata": {},
"source": [
"from sevenn.calculator import SevenNetCalculator\n",
"\n",
"# Use the bundled pretrained 7net-0 model\n",
"calculator = SevenNetCalculator(model=\"7net-0\", device=\"cpu\")\n",
"\n",
"print(\"SevenNet 7net-0 model loaded\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "ebaa0f39",
"metadata": {},
"source": [
"### 4.2. Relax with SevenNet"
]
},
{
"cell_type": "code",
"id": "f17d5d6d",
"metadata": {},
"source": [
"import plotly.graph_objs as go\n",
"from IPython.display import display\n",
"from plotly.subplots import make_subplots\n",
"\n",
"from mat3ra.made.tools.convert import to_ase\n",
"from ase.optimize import BFGS\n",
"\n",
"ase_structure = to_ase(structure)\n",
"ase_structure.calc = calculator\n",
"dyn = BFGS(ase_structure)\n",
"\n",
"steps = []\n",
"energies = []\n",
"\n",
"fig = make_subplots(rows=1, cols=1, specs=[[{\"type\": \"scatter\"}]])\n",
"scatter = go.Scatter(x=[], y=[], mode=\"lines+markers\", name=\"Energy\")\n",
"fig.add_trace(scatter)\n",
"fig.update_layout(title_text=\"Real-time Optimization Progress\", xaxis_title=\"Step\", yaxis_title=\"Energy (eV)\")\n",
"\n",
"try:\n",
" f = go.FigureWidget(fig)\n",
"except ImportError:\n",
" f = go.Figure(fig)\n",
"display(f)\n",
"\n",
"\n",
"def plotly_callback():\n",
" step = dyn.nsteps\n",
" energy = ase_structure.get_total_energy()\n",
" steps.append(step)\n",
" energies.append(energy)\n",
" print(f\"Step: {step}, Energy: {energy:.4f} eV\")\n",
" if hasattr(f, \"batch_update\"):\n",
" with f.batch_update():\n",
" f.data[0].x = steps\n",
" f.data[0].y = energies\n",
" else:\n",
" f.data[0].x = steps\n",
" f.data[0].y = energies\n",
"\n",
"\n",
"dyn.attach(plotly_callback, interval=1)\n",
"dyn.run(fmax=RELAXATION_PARAMETERS[\"FMAX\"])\n",
"\n",
"ase_original_structure = to_ase(structure)\n",
"ase_original_structure.calc = calculator\n",
"ase_final_structure = ase_structure\n",
"\n",
"original_energy = ase_original_structure.get_total_energy()\n",
"relaxed_energy = ase_structure.get_total_energy()\n",
"\n",
"print(f\"The final energy is {float(relaxed_energy):.3f} eV.\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "e788e0e3",
"metadata": {},
"source": [
"## 5. Analyze Results\n",
"### 5.1. View Structure Before and After Relaxation"
]
},
{
"cell_type": "code",
"id": "0391a838",
"metadata": {},
"source": [
"from mat3ra.made.tools.convert import from_ase\n",
"\n",
"material_original = Material.create(from_ase(ase_original_structure))\n",
"material_relaxed = Material.create(from_ase(ase_final_structure))\n",
"material_original.name = structure.name\n",
"material_relaxed.name = structure.name + \" (SevenNet Relaxed)\"\n",
"\n",
"visualize([material_original, material_relaxed], viewer=ViewersEnum.wave)"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "41bba468",
"metadata": {},
"source": [
"### 5.2. Output interlayer distance before and after relaxation"
]
},
{
"cell_type": "code",
"id": "3f19487a",
"metadata": {},
"source": [
"from mat3ra.made.tools.analyze.other import get_average_interlayer_distance\n",
"\n",
"SUBSTRATE_TAG = 0\n",
"FILM_TAG = 1\n",
"\n",
"print(\n",
" f\"Interlayer distance before relaxation: {get_average_interlayer_distance(material_original, SUBSTRATE_TAG, FILM_TAG):.4f} \u00c5\")\n",
"print(\n",
" f\"Interlayer distance after relaxation: {get_average_interlayer_distance(material_relaxed, SUBSTRATE_TAG, FILM_TAG):.4f} \u00c5\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "8c7ae982",
"metadata": {},
"source": [
"## References\n",
"\n",
"[1] SevenNet: https://github.com/MDIL-SNU/SevenNet\n",
"\n",
"[2] Yutack Park et al., \"Scalable Parallel Algorithm for Graph Neural Network Interatomic Potentials,\" J. Chem. Theory Comput. (2024)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python (Pyodide)",
"language": "python",
"name": "python"
},
"language_info": {
"codemirror_mode": {
"name": "python",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading
Loading