Skip to content

Commit 4e6aef2

Browse files
Merge pull request #249 from Exabyte-io/dev
Dev
2 parents d4638ff + 26669e9 commit 4e6aef2

7 files changed

Lines changed: 409 additions & 0 deletions

File tree

other/experiments/mtrsm/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## Usage
2+
3+
### With standalone scripts
4+
5+
Install dependencies (using pyenv):
6+
7+
```bash
8+
pyenv local 3.10.13
9+
python -m venv .venv-3.10.13
10+
source .venv-3.10.13/bin/activate
11+
pip install mattersim
12+
```
13+
14+
Run the script(s):
15+
16+
```bash
17+
source .venv-3.10.13/bin/activate
18+
python <script_name.py>
19+
```
20+
21+
### With JupyterLab
22+
23+
Install dependencies:
24+
25+
```bash
26+
pyenv local 3.10.13
27+
python -m venv .venv-3.10.13
28+
source .venv-3.10.13/bin/activate
29+
pip install "mat3ra-api-examples[forcefields]"
30+
```
31+
32+
As below. With `pyenv`.
33+
34+
```bash
35+
pyenv local 3.10.13
36+
python -m venv .venv-3.10.13
37+
source .venv-3.10.13/bin/activate
38+
pip install mattersim
39+
```
40+
41+
See the included notebook.
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "ba05a8b053f7ed1f",
6+
"metadata": {},
7+
"source": [
8+
"# Calculate Vacancy Formation Energy in Silicon using MatterSim Potential\n",
9+
"\n",
10+
"This notebook demonstrates how to compute the vacancy formation energy in silicon using the MatterSim potential within the Mat3ra framework.\n",
11+
"\n",
12+
"## Methodology\n",
13+
"\n",
14+
"The vacancy formation energy is calculated using the following approach:\n",
15+
"\n",
16+
"1. **Create pristine supercell**: Build a silicon supercell from the unit cell and relax it using MatterSim potential\n",
17+
"2. **Create vacancy**: Remove a single atom from the center of the supercell\n",
18+
"3. **Relax vacancy structure**: Optimize the geometry of the defective supercell\n",
19+
"4. **Calculate formation energy**: Compute the energy difference according to the formula:\n",
20+
" \n",
21+
" E_formation = E_vacancy - (N_vacancy/N_bulk) × E_bulk\n",
22+
" \n",
23+
" where:\n",
24+
" - E_vacancy: Total energy of the supercell with vacancy\n",
25+
" - E_bulk: Total energy of the pristine supercell\n",
26+
" - N_vacancy: Number of atoms in vacancy supercell\n",
27+
" - N_bulk: Number of atoms in pristine supercell"
28+
]
29+
},
30+
{
31+
"cell_type": "code",
32+
"id": "39067e0f5d2c0ffb",
33+
"metadata": {},
34+
"source": [
35+
"# Install required packages if not already installed\n",
36+
"# INFO: if not installed correctly, clear environment and run `pip install .[forcefields]` in the terminal\n",
37+
"try:\n",
38+
" import mattersim\n",
39+
"except ImportError:\n",
40+
" import subprocess, sys\n",
41+
" subprocess.run([sys.executable, \"-m\", \"pip\", \"install\", \".[forcefields]\", \"--quiet\"], check=False)\n",
42+
" import mattersim"
43+
],
44+
"outputs": [],
45+
"execution_count": null
46+
},
47+
{
48+
"cell_type": "markdown",
49+
"id": "ad71b3bcdb13e36a",
50+
"metadata": {},
51+
"source": [
52+
"## 1. Prepare materials\n",
53+
"### 1.1. Load material data"
54+
]
55+
},
56+
{
57+
"cell_type": "code",
58+
"id": "2819d078b48216b9",
59+
"metadata": {},
60+
"source": [
61+
"from mat3ra.standata.materials import Materials\n",
62+
"from mat3ra.made.material import Material\n",
63+
"\n",
64+
"material = Material.create(Materials.get_by_name_first_match(\"Si\"))"
65+
],
66+
"outputs": [],
67+
"execution_count": null
68+
},
69+
{
70+
"cell_type": "markdown",
71+
"id": "f011303e40ab0ee5",
72+
"metadata": {},
73+
"source": [
74+
"### 1.2. Add vacancy to material"
75+
]
76+
},
77+
{
78+
"cell_type": "code",
79+
"id": "b7e53d295d59fe89",
80+
"metadata": {},
81+
"source": [
82+
"from mat3ra.made.tools.helpers import create_vacancy, create_supercell\n",
83+
"\n",
84+
"supercell = create_supercell(material, scaling_factor=[2,2,2])\n",
85+
"material_with_vacancy = create_vacancy(supercell, coordinate=[0.5, 0.5, 0.5], placement_method=\"closest_site\")"
86+
],
87+
"outputs": [],
88+
"execution_count": null
89+
},
90+
{
91+
"cell_type": "markdown",
92+
"id": "45c3dade8bcd52b3",
93+
"metadata": {},
94+
"source": [
95+
"## 1.3. Visualize materials"
96+
]
97+
},
98+
{
99+
"cell_type": "code",
100+
"id": "4b91a2ae59c983a3",
101+
"metadata": {},
102+
"source": [
103+
"from utils.visualize import visualize_materials\n",
104+
"\n",
105+
"visualize_materials([material, supercell, material_with_vacancy], rotation=\"-90x,-90y\")"
106+
],
107+
"outputs": [],
108+
"execution_count": null
109+
},
110+
{
111+
"cell_type": "markdown",
112+
"id": "8ce27a1c8864c29f",
113+
"metadata": {},
114+
"source": [
115+
"## 2. Setup calculation\n",
116+
"### 2.1. Convert to ASE atoms"
117+
]
118+
},
119+
{
120+
"cell_type": "code",
121+
"id": "62b389e5458ce7c2",
122+
"metadata": {},
123+
"source": [
124+
"from mat3ra.made.tools.convert import to_ase\n",
125+
"\n",
126+
"material_atoms = to_ase(material)\n",
127+
"material_with_vacancy_atoms = to_ase(material_with_vacancy)"
128+
],
129+
"outputs": [],
130+
"execution_count": null
131+
},
132+
{
133+
"cell_type": "markdown",
134+
"id": "c4c3b2a928a369ad",
135+
"metadata": {},
136+
"source": [
137+
"### 2.2. Setup MatterSim calculator"
138+
]
139+
},
140+
{
141+
"cell_type": "code",
142+
"id": "361cd269cb3e2db4",
143+
"metadata": {},
144+
"source": [
145+
"from mattersim.forcefield.potential import MatterSimCalculator\n",
146+
"from mattersim.applications.relax import Relaxer\n",
147+
"\n",
148+
"material_atoms.calc = MatterSimCalculator()\n",
149+
"material_with_vacancy_atoms.calc = MatterSimCalculator()\n"
150+
],
151+
"outputs": [],
152+
"execution_count": null
153+
},
154+
{
155+
"cell_type": "markdown",
156+
"id": "8119275fe9ffb1d8",
157+
"metadata": {},
158+
"source": [
159+
"### 2.3. Relax structures"
160+
]
161+
},
162+
{
163+
"cell_type": "code",
164+
"id": "48cbd2f29d0cbd2c",
165+
"metadata": {},
166+
"source": [
167+
"relaxer = Relaxer(optimizer=\"BFGS\", constrain_symmetry=True)\n",
168+
"relaxer.relax(material_atoms, steps=500) # In-place relaxation\n",
169+
"relaxer.relax(material_with_vacancy_atoms, steps=500) # In-place relaxation\n"
170+
],
171+
"outputs": [],
172+
"execution_count": null
173+
},
174+
{
175+
"cell_type": "markdown",
176+
"id": "116af57af6793bb",
177+
"metadata": {},
178+
"source": [
179+
"### 2.4. Visualize relaxed structures"
180+
]
181+
},
182+
{
183+
"cell_type": "code",
184+
"id": "6426cc56c5d51eef",
185+
"metadata": {},
186+
"source": [
187+
"from mat3ra.made.tools.convert import from_ase\n",
188+
"\n",
189+
"relaxed_material = Material.create(from_ase(material_atoms))\n",
190+
"relaxed_material_with_vacancy = Material.create(from_ase(material_with_vacancy_atoms))\n",
191+
"\n",
192+
"visualize_materials([relaxed_material, supercell, relaxed_material_with_vacancy], rotation=\"-90x,-90y\")"
193+
],
194+
"outputs": [],
195+
"execution_count": null
196+
},
197+
{
198+
"cell_type": "markdown",
199+
"id": "7754f5d01964b082",
200+
"metadata": {},
201+
"source": [
202+
"## 3. Calculate vacancy formation energy\n",
203+
"\n",
204+
"### 3.1. Get energies and atom counts"
205+
]
206+
},
207+
{
208+
"cell_type": "code",
209+
"id": "2f4694776e7d1430",
210+
"metadata": {},
211+
"source": [
212+
"energy_bulk = material_atoms.get_potential_energy()\n",
213+
"n_atoms_bulk = len(material_atoms)\n",
214+
"energy_vacancy = material_with_vacancy_atoms.get_potential_energy()\n",
215+
"n_atoms_vac = len(material_with_vacancy_atoms)"
216+
],
217+
"outputs": [],
218+
"execution_count": null
219+
},
220+
{
221+
"cell_type": "markdown",
222+
"id": "baae670f86c9b639",
223+
"metadata": {},
224+
"source": [
225+
"### 3.2. Calculate vacancy formation energy"
226+
]
227+
},
228+
{
229+
"cell_type": "code",
230+
"id": "430936d099f5b816",
231+
"metadata": {},
232+
"source": [
233+
"e_vacancy = energy_vacancy - (n_atoms_vac / n_atoms_bulk * energy_bulk)\n",
234+
"print(f\"Vacancy formation energy: {e_vacancy:.4f} eV\")\n"
235+
],
236+
"outputs": [],
237+
"execution_count": null
238+
},
239+
{
240+
"metadata": {},
241+
"cell_type": "code",
242+
"source": "",
243+
"id": "fa73a94409748e1c",
244+
"outputs": [],
245+
"execution_count": null
246+
}
247+
],
248+
"metadata": {
249+
"kernelspec": {
250+
"display_name": "Python 3",
251+
"language": "python",
252+
"name": "python3"
253+
},
254+
"language_info": {
255+
"codemirror_mode": {
256+
"name": "ipython",
257+
"version": 2
258+
},
259+
"file_extension": ".py",
260+
"mimetype": "text/x-python",
261+
"name": "python",
262+
"nbconvert_exporter": "python",
263+
"pygments_lexer": "ipython2",
264+
"version": "2.7.6"
265+
}
266+
},
267+
"nbformat": 4,
268+
"nbformat_minor": 5
269+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import torch
2+
from loguru import logger
3+
from ase.build import bulk
4+
from ase.units import GPa
5+
from mattersim.forcefield import MatterSimCalculator
6+
7+
device = "cuda" if torch.cuda.is_available() else "cpu"
8+
logger.info(f"Running MatterSim on {device}")
9+
10+
si = bulk("Si", "diamond", a=5.43)
11+
si.calc = MatterSimCalculator(device=device)
12+
logger.info(f"Energy (eV) = {si.get_potential_energy()}")
13+
logger.info(f"Energy per atom (eV/atom) = {si.get_potential_energy()/len(si)}")
14+
logger.info(f"Forces of first atom (eV/A) = {si.get_forces()[0]}")
15+
logger.info(f"Stress[0][0] (eV/A^3) = {si.get_stress(voigt=False)[0][0]}")
16+
logger.info(f"Stress[0][0] (GPa) = {si.get_stress(voigt=False)[0][0] / GPa}")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import numpy as np
2+
from ase.build import bulk
3+
from ase.units import GPa
4+
from ase.visualize import view
5+
from mattersim.forcefield.potential import MatterSimCalculator
6+
from mattersim.applications.phonon import PhononWorkflow
7+
8+
# initialize the structure of silicon
9+
si = bulk("Si")
10+
11+
# attach the calculator to the atoms object
12+
si.calc = MatterSimCalculator()
13+
14+
ph = PhononWorkflow(
15+
atoms=si,
16+
find_prim = False,
17+
work_dir = "./tmp/phonon_si_example",
18+
amplitude = 0.01,
19+
supercell_matrix = np.diag([4,4,4]),
20+
)
21+
22+
has_imag, phonons = ph.run()
23+
print(f"Has imaginary phonon: {has_imag}")
24+
print(f"Phonon frequencies: {phonons}")
25+
26+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import numpy as np
2+
from ase.build import bulk
3+
from ase.units import GPa
4+
from mattersim.forcefield.potential import MatterSimCalculator
5+
from mattersim.applications.relax import Relaxer
6+
7+
# initialize the structure of silicon
8+
si = bulk("Si", "diamond", a=5.43)
9+
10+
# perturb the structure
11+
si.positions += 0.1 * np.random.randn(len(si), 3)
12+
13+
# attach the calculator to the atoms object
14+
si.calc = MatterSimCalculator()
15+
16+
# initialize the relaxation object
17+
relaxer = Relaxer(
18+
optimizer="BFGS", # the optimization method
19+
filter="ExpCellFilter", # filter to apply to the cell
20+
constrain_symmetry=True, # whether to constrain the symmetry
21+
)
22+
23+
relaxed_structure = relaxer.relax(si, steps=500)

0 commit comments

Comments
 (0)