flashmd 0.1.2__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flashmd-0.1.2/src/flashmd.egg-info → flashmd-0.2.0}/PKG-INFO +43 -11
- {flashmd-0.1.2 → flashmd-0.2.0}/README.md +41 -9
- {flashmd-0.1.2 → flashmd-0.2.0}/pyproject.toml +2 -2
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/__init__.py +1 -1
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ase/velocity_verlet.py +6 -12
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ipi.py +5 -9
- flashmd-0.2.0/src/flashmd/models.py +61 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/stepper.py +11 -35
- {flashmd-0.1.2 → flashmd-0.2.0/src/flashmd.egg-info}/PKG-INFO +43 -11
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd.egg-info/requires.txt +1 -1
- flashmd-0.1.2/src/flashmd/models.py +0 -18
- {flashmd-0.1.2 → flashmd-0.2.0}/LICENSE +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/setup.cfg +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ase/__init__.py +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ase/bussi.py +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ase/langevin.py +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd/ase/npt.py +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd.egg-info/SOURCES.txt +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd.egg-info/dependency_links.txt +0 -0
- {flashmd-0.1.2 → flashmd-0.2.0}/src/flashmd.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flashmd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Accelerated molecular dynamics with large-time-step predictions
|
|
5
5
|
Author: flashmd developers
|
|
6
6
|
License: Apache-2.0
|
|
@@ -22,8 +22,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
22
22
|
Requires-Python: >=3.9
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
+
Requires-Dist: metatrain==2025.11
|
|
25
26
|
Requires-Dist: ase
|
|
26
|
-
Requires-Dist: pet-mad>=1.2.0
|
|
27
27
|
Requires-Dist: huggingface_hub
|
|
28
28
|
Dynamic: license-file
|
|
29
29
|
|
|
@@ -35,6 +35,8 @@ designed to learn and predict molecular dynamics trajectories using long strides
|
|
|
35
35
|
very large time steps. Before using this method, make sure you are aware of its limitations, which are
|
|
36
36
|
discussed in [this preprint](http://arxiv.org/abs/2505.19350).
|
|
37
37
|
|
|
38
|
+
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
39
|
+
|
|
38
40
|
Quickstart
|
|
39
41
|
----------
|
|
40
42
|
|
|
@@ -51,35 +53,41 @@ import ase.build
|
|
|
51
53
|
import ase.units
|
|
52
54
|
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
|
|
53
55
|
import torch
|
|
54
|
-
from
|
|
56
|
+
from metatomic.torch.ase_calculator import MetatomicCalculator
|
|
55
57
|
|
|
56
|
-
from flashmd import
|
|
58
|
+
from flashmd import get_pretrained
|
|
57
59
|
from flashmd.ase.langevin import Langevin
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
# Choose your time step (go for 10-30x what you would use in normal MD for your system)
|
|
63
|
+
time_step = 16 # 16 fs; also available: 1, 2, 4, 8, 32, 64, 128 fs
|
|
64
|
+
|
|
60
65
|
# Create a structure and initialize velocities
|
|
61
66
|
atoms = ase.build.bulk("Al", "fcc", cubic=True)
|
|
62
67
|
MaxwellBoltzmannDistribution(atoms, temperature_K=300)
|
|
63
68
|
|
|
64
69
|
# Load models
|
|
65
70
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
66
|
-
|
|
71
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
72
|
+
|
|
73
|
+
calculator = MetatomicCalculator(energy_model, device=device)
|
|
67
74
|
atoms.calc = calculator
|
|
68
|
-
model = get_universal_model(16) # 16 fs model; also available: 1, 4, 8, 32, 64 fs
|
|
69
|
-
model = model.to(device)
|
|
70
75
|
|
|
71
76
|
# Run MD
|
|
72
77
|
dyn = Langevin(
|
|
73
78
|
atoms=atoms,
|
|
74
|
-
timestep=
|
|
79
|
+
timestep=time_step*ase.units.fs,
|
|
75
80
|
temperature_K=300,
|
|
76
81
|
time_constant=100*ase.units.fs,
|
|
77
|
-
model=
|
|
82
|
+
model=flashmd_model,
|
|
78
83
|
device=device
|
|
79
84
|
)
|
|
80
85
|
dyn.run(1000)
|
|
81
86
|
```
|
|
82
87
|
|
|
88
|
+
[The first time you use this code and call the `get_pretrained` function, the
|
|
89
|
+
pre-trained models will be downloaded. This might take a bit.]
|
|
90
|
+
|
|
83
91
|
Other available integrators:
|
|
84
92
|
|
|
85
93
|
```py
|
|
@@ -91,11 +99,35 @@ Disclaimer
|
|
|
91
99
|
----------
|
|
92
100
|
|
|
93
101
|
This is experimental software and should only be used if you know what you're doing.
|
|
94
|
-
We recommend using the i-PI integrators for any serious work
|
|
95
|
-
pressure
|
|
102
|
+
We recommend using the i-PI integrators for any serious work and/or if you need to perform
|
|
103
|
+
constant-pressure (NPT) molecular dynamics. You can see
|
|
96
104
|
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
97
105
|
for a usage example.
|
|
98
106
|
Given that the main issue we observe in direct MD trajectories is loss of equipartition
|
|
99
107
|
of energy between different degrees of freedom, we recommend using a local Langevin
|
|
100
108
|
thermostat, and to monitor the temperature of different atomic types or different
|
|
101
109
|
parts of the simulated system.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
Publication
|
|
113
|
+
-----------
|
|
114
|
+
|
|
115
|
+
If you found FlashMD useful, you can cite the corresponding article:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
@article{FlashMD,
|
|
119
|
+
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
120
|
+
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
121
|
+
journal={arXiv preprint arXiv:2505.19350},
|
|
122
|
+
year={2025}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Reproducing the results in the article is supported with FlashMD v0.1.2:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install flashmd==0.1.2 ase==3.24.0 pet-mad==1.4.3
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
and using the "PET-MAD" models (PBEsol) from https://huggingface.co/lab-cosmo/flashmd.
|
|
133
|
+
Note that the results were obtained through the i-PI interface.
|
|
@@ -6,6 +6,8 @@ designed to learn and predict molecular dynamics trajectories using long strides
|
|
|
6
6
|
very large time steps. Before using this method, make sure you are aware of its limitations, which are
|
|
7
7
|
discussed in [this preprint](http://arxiv.org/abs/2505.19350).
|
|
8
8
|
|
|
9
|
+
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
10
|
+
|
|
9
11
|
Quickstart
|
|
10
12
|
----------
|
|
11
13
|
|
|
@@ -22,35 +24,41 @@ import ase.build
|
|
|
22
24
|
import ase.units
|
|
23
25
|
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
|
|
24
26
|
import torch
|
|
25
|
-
from
|
|
27
|
+
from metatomic.torch.ase_calculator import MetatomicCalculator
|
|
26
28
|
|
|
27
|
-
from flashmd import
|
|
29
|
+
from flashmd import get_pretrained
|
|
28
30
|
from flashmd.ase.langevin import Langevin
|
|
29
31
|
|
|
30
32
|
|
|
33
|
+
# Choose your time step (go for 10-30x what you would use in normal MD for your system)
|
|
34
|
+
time_step = 16 # 16 fs; also available: 1, 2, 4, 8, 32, 64, 128 fs
|
|
35
|
+
|
|
31
36
|
# Create a structure and initialize velocities
|
|
32
37
|
atoms = ase.build.bulk("Al", "fcc", cubic=True)
|
|
33
38
|
MaxwellBoltzmannDistribution(atoms, temperature_K=300)
|
|
34
39
|
|
|
35
40
|
# Load models
|
|
36
41
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
37
|
-
|
|
42
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
43
|
+
|
|
44
|
+
calculator = MetatomicCalculator(energy_model, device=device)
|
|
38
45
|
atoms.calc = calculator
|
|
39
|
-
model = get_universal_model(16) # 16 fs model; also available: 1, 4, 8, 32, 64 fs
|
|
40
|
-
model = model.to(device)
|
|
41
46
|
|
|
42
47
|
# Run MD
|
|
43
48
|
dyn = Langevin(
|
|
44
49
|
atoms=atoms,
|
|
45
|
-
timestep=
|
|
50
|
+
timestep=time_step*ase.units.fs,
|
|
46
51
|
temperature_K=300,
|
|
47
52
|
time_constant=100*ase.units.fs,
|
|
48
|
-
model=
|
|
53
|
+
model=flashmd_model,
|
|
49
54
|
device=device
|
|
50
55
|
)
|
|
51
56
|
dyn.run(1000)
|
|
52
57
|
```
|
|
53
58
|
|
|
59
|
+
[The first time you use this code and call the `get_pretrained` function, the
|
|
60
|
+
pre-trained models will be downloaded. This might take a bit.]
|
|
61
|
+
|
|
54
62
|
Other available integrators:
|
|
55
63
|
|
|
56
64
|
```py
|
|
@@ -62,11 +70,35 @@ Disclaimer
|
|
|
62
70
|
----------
|
|
63
71
|
|
|
64
72
|
This is experimental software and should only be used if you know what you're doing.
|
|
65
|
-
We recommend using the i-PI integrators for any serious work
|
|
66
|
-
pressure
|
|
73
|
+
We recommend using the i-PI integrators for any serious work and/or if you need to perform
|
|
74
|
+
constant-pressure (NPT) molecular dynamics. You can see
|
|
67
75
|
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
68
76
|
for a usage example.
|
|
69
77
|
Given that the main issue we observe in direct MD trajectories is loss of equipartition
|
|
70
78
|
of energy between different degrees of freedom, we recommend using a local Langevin
|
|
71
79
|
thermostat, and to monitor the temperature of different atomic types or different
|
|
72
80
|
parts of the simulated system.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
Publication
|
|
84
|
+
-----------
|
|
85
|
+
|
|
86
|
+
If you found FlashMD useful, you can cite the corresponding article:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
@article{FlashMD,
|
|
90
|
+
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
91
|
+
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
92
|
+
journal={arXiv preprint arXiv:2505.19350},
|
|
93
|
+
year={2025}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Reproducing the results in the article is supported with FlashMD v0.1.2:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install flashmd==0.1.2 ase==3.24.0 pet-mad==1.4.3
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
and using the "PET-MAD" models (PBEsol) from https://huggingface.co/lab-cosmo/flashmd.
|
|
104
|
+
Note that the results were obtained through the i-PI interface.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flashmd"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
requires-python = ">=3.9"
|
|
5
5
|
|
|
6
6
|
readme = "README.md"
|
|
@@ -9,8 +9,8 @@ description = "Accelerated molecular dynamics with large-time-step predictions"
|
|
|
9
9
|
authors = [{name = "flashmd developers"}]
|
|
10
10
|
|
|
11
11
|
dependencies = [
|
|
12
|
+
"metatrain==2025.11",
|
|
12
13
|
"ase",
|
|
13
|
-
"pet-mad>=1.2.0",
|
|
14
14
|
"huggingface_hub",
|
|
15
15
|
]
|
|
16
16
|
|
|
@@ -23,19 +23,13 @@ class VelocityVerlet(MolecularDynamics):
|
|
|
23
23
|
):
|
|
24
24
|
super().__init__(atoms, timestep, **kwargs)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
capabilities = models[0].capabilities()
|
|
26
|
+
capabilities = model.capabilities()
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
n_time_steps = int(
|
|
32
|
-
[k for k in capabilities.outputs.keys() if "mtt::delta_" in k][0].split(
|
|
33
|
-
"_"
|
|
34
|
-
)[1]
|
|
35
|
-
)
|
|
36
|
-
if n_time_steps != self.dt / base_timestep:
|
|
28
|
+
model_timestep = float(model.module.timestep)
|
|
29
|
+
if not np.allclose(model_timestep, self.dt / ase.units.fs):
|
|
37
30
|
raise ValueError(
|
|
38
|
-
f"Mismatch between timestep ({self.dt
|
|
31
|
+
f"Mismatch between timestep ({self.dt / ase.units.fs} fs) "
|
|
32
|
+
f"and model timestep ({model_timestep} fs)."
|
|
39
33
|
)
|
|
40
34
|
|
|
41
35
|
if device == "auto":
|
|
@@ -45,7 +39,7 @@ class VelocityVerlet(MolecularDynamics):
|
|
|
45
39
|
self.device = torch.device(device)
|
|
46
40
|
self.dtype = getattr(torch, capabilities.dtype)
|
|
47
41
|
|
|
48
|
-
self.stepper = FlashMDStepper(
|
|
42
|
+
self.stepper = FlashMDStepper(model, self.device)
|
|
49
43
|
self.rescale_energy = rescale_energy
|
|
50
44
|
|
|
51
45
|
def step(self):
|
|
@@ -39,7 +39,6 @@ def get_standard_vv_step(
|
|
|
39
39
|
info("@flashmd: Old energy", verbosity.debug)
|
|
40
40
|
old_energy = sim.properties("potential") + sim.properties("kinetic_md")
|
|
41
41
|
|
|
42
|
-
print(motion.integrator.pdt, motion.integrator.qdt)
|
|
43
42
|
motion.integrator.pstep(level=0)
|
|
44
43
|
motion.integrator.pconstraints()
|
|
45
44
|
motion.integrator.qcstep() # does two steps because qdt is halved in the i-PI integrator
|
|
@@ -60,21 +59,18 @@ def get_standard_vv_step(
|
|
|
60
59
|
def get_flashmd_vv_step(sim, model, device, rescale_energy=True, random_rotation=False):
|
|
61
60
|
capabilities = model.capabilities()
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
model_timestep = float(model.module.timestep)
|
|
64
63
|
|
|
65
|
-
dt = sim.syslist[0].motion.dt * 2.4188843e-17 * ase.units.s
|
|
64
|
+
dt = sim.syslist[0].motion.dt * 2.4188843e-17 * ase.units.s / ase.units.fs
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
[k for k in capabilities.outputs.keys() if "mtt::delta_" in k][0].split("_")[1]
|
|
69
|
-
)
|
|
70
|
-
if not np.allclose(dt, n_time_steps * base_timestep):
|
|
66
|
+
if not np.allclose(dt, model_timestep):
|
|
71
67
|
raise ValueError(
|
|
72
|
-
f"Mismatch between timestep ({dt}) and model timestep ({
|
|
68
|
+
f"Mismatch between timestep ({dt} fs) and model timestep ({model_timestep} fs)."
|
|
73
69
|
)
|
|
74
70
|
|
|
75
71
|
device = torch.device(device)
|
|
76
72
|
dtype = getattr(torch, capabilities.dtype)
|
|
77
|
-
stepper = FlashMDStepper(
|
|
73
|
+
stepper = FlashMDStepper(model, device)
|
|
78
74
|
|
|
79
75
|
def flashmd_vv(motion):
|
|
80
76
|
info("@flashmd: Starting VV", verbosity.debug)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from huggingface_hub import hf_hub_download
|
|
2
|
+
from metatomic.torch import AtomisticModel, load_atomistic_model
|
|
3
|
+
import subprocess
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
AVAILABLE_MLIPS = ["pet-omatpes"]
|
|
9
|
+
AVAILABLE_TIME_STEPS = {
|
|
10
|
+
"pet-omatpes": [1, 2, 4, 8, 16, 32, 64, 128]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_pretrained(mlip: str = "pet-omatpes", time_step: int = 16) -> AtomisticModel:
|
|
15
|
+
if mlip not in AVAILABLE_MLIPS:
|
|
16
|
+
raise ValueError(
|
|
17
|
+
f"MLIP '{mlip}' is not available. "
|
|
18
|
+
f"Available MLIPs are: {', '.join(AVAILABLE_MLIPS)}."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if time_step not in AVAILABLE_TIME_STEPS[mlip]:
|
|
22
|
+
raise ValueError(
|
|
23
|
+
f"Pretrained FlashMD models based on the {mlip} MLIP are only available "
|
|
24
|
+
f"for time steps of {', '.join(map(str, AVAILABLE_TIME_STEPS[mlip]))} fs."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Get checkpoints corresponding to the selected MLIP and FlashMD models
|
|
28
|
+
mlip_path = hf_hub_download(
|
|
29
|
+
repo_id="lab-cosmo/flashmd",
|
|
30
|
+
filename=f"mlip_{mlip}.ckpt",
|
|
31
|
+
cache_dir=None,
|
|
32
|
+
revision="main",
|
|
33
|
+
)
|
|
34
|
+
flashmd_path = hf_hub_download(
|
|
35
|
+
repo_id="lab-cosmo/flashmd",
|
|
36
|
+
filename=f"flashmd_{mlip}_{time_step}fs.ckpt",
|
|
37
|
+
cache_dir=None,
|
|
38
|
+
revision="main",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Now we need to export both using metatrain. However, we don't want to do it if
|
|
42
|
+
# HuggingFace hasn't downloaded a new version of the files, so we only re-export
|
|
43
|
+
# if the files above have changed in the last 10 seconds.
|
|
44
|
+
reexport = False
|
|
45
|
+
exported_mlip_path = mlip_path.replace(".ckpt", ".pt")
|
|
46
|
+
exported_flashmd_path = flashmd_path.replace(".ckpt", ".pt")
|
|
47
|
+
if not os.path.exists(exported_mlip_path) or not os.path.exists(exported_flashmd_path):
|
|
48
|
+
reexport = True
|
|
49
|
+
mlip_mtime = os.path.getmtime(mlip_path)
|
|
50
|
+
flashmd_mtime = os.path.getmtime(flashmd_path)
|
|
51
|
+
if (time.time() - mlip_mtime < 10) or (time.time() - flashmd_mtime < 10):
|
|
52
|
+
reexport = True
|
|
53
|
+
if reexport:
|
|
54
|
+
subprocess.run(["mtt", "export", mlip_path, "-o", exported_mlip_path], capture_output=True)
|
|
55
|
+
subprocess.run(["mtt", "export", flashmd_path, "-o", exported_flashmd_path], capture_output=True)
|
|
56
|
+
|
|
57
|
+
# Load as AtomisticModel instances
|
|
58
|
+
mlip_model = load_atomistic_model(exported_mlip_path)
|
|
59
|
+
flashmd_model = load_atomistic_model(exported_flashmd_path)
|
|
60
|
+
|
|
61
|
+
return mlip_model, flashmd_model
|
|
@@ -4,42 +4,27 @@ from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
|
4
4
|
import torch
|
|
5
5
|
from metatomic.torch import System
|
|
6
6
|
from metatrain.utils.neighbor_lists import get_system_with_neighbor_lists
|
|
7
|
-
from typing import List
|
|
8
7
|
from metatomic.torch import AtomisticModel
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class FlashMDStepper:
|
|
12
11
|
def __init__(
|
|
13
12
|
self,
|
|
14
|
-
|
|
15
|
-
n_time_steps: int,
|
|
13
|
+
model: AtomisticModel,
|
|
16
14
|
device: torch.device,
|
|
17
|
-
# q_error_threshold: float = 0.1,
|
|
18
|
-
# p_error_threshold: float = 0.1,
|
|
19
|
-
# energy_error_threshold: float = 0.1,
|
|
20
15
|
):
|
|
21
|
-
self.
|
|
22
|
-
|
|
23
|
-
# internally, turn list of models into a dict and send to device
|
|
24
|
-
self.models = {}
|
|
25
|
-
for model in models:
|
|
26
|
-
n_time_steps_model = int(
|
|
27
|
-
[k for k in model.capabilities().outputs.keys() if "mtt::delta_" in k][
|
|
28
|
-
0
|
|
29
|
-
].split("_")[1]
|
|
30
|
-
)
|
|
31
|
-
self.models[n_time_steps_model] = model.to(device)
|
|
16
|
+
self.model = model.to(device)
|
|
32
17
|
|
|
33
18
|
# one of these for each model:
|
|
34
19
|
self.evaluation_options = ModelEvaluationOptions(
|
|
35
20
|
length_unit="Angstrom",
|
|
36
21
|
outputs={
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
"positions": ModelOutput(per_atom=True),
|
|
23
|
+
"momenta": ModelOutput(per_atom=True),
|
|
39
24
|
},
|
|
40
25
|
)
|
|
41
26
|
|
|
42
|
-
self.dtype = getattr(torch, self.
|
|
27
|
+
self.dtype = getattr(torch, self.model.capabilities().dtype)
|
|
43
28
|
self.device = device
|
|
44
29
|
|
|
45
30
|
def step(self, system: System):
|
|
@@ -49,27 +34,18 @@ class FlashMDStepper:
|
|
|
49
34
|
raise ValueError("System dtype does not match stepper dtype.")
|
|
50
35
|
|
|
51
36
|
system = get_system_with_neighbor_lists(
|
|
52
|
-
system, self.
|
|
37
|
+
system, self.model.requested_neighbor_lists()
|
|
53
38
|
)
|
|
54
39
|
|
|
55
40
|
masses = system.get_data("masses").block().values
|
|
56
|
-
model_outputs = self.
|
|
41
|
+
model_outputs = self.model(
|
|
57
42
|
[system], self.evaluation_options, check_consistency=False
|
|
58
43
|
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.block()
|
|
62
|
-
.values.squeeze(-1)
|
|
63
|
-
)
|
|
64
|
-
p_scaled = (
|
|
65
|
-
model_outputs[f"mtt::p_{self.n_time_steps}"].block().values.squeeze(-1)
|
|
66
|
-
)
|
|
67
|
-
sqrt_masses = torch.sqrt(masses)
|
|
68
|
-
delta_q = delta_q_scaled / sqrt_masses
|
|
69
|
-
p = p_scaled * sqrt_masses
|
|
44
|
+
new_q = model_outputs["positions"].block().values.squeeze(-1)
|
|
45
|
+
new_p = model_outputs["momenta"].block().values.squeeze(-1)
|
|
70
46
|
|
|
71
47
|
new_system = System(
|
|
72
|
-
positions=
|
|
48
|
+
positions=new_q,
|
|
73
49
|
types=system.types,
|
|
74
50
|
cell=system.cell,
|
|
75
51
|
pbc=system.pbc,
|
|
@@ -80,7 +56,7 @@ class FlashMDStepper:
|
|
|
80
56
|
keys=Labels.single().to(self.device),
|
|
81
57
|
blocks=[
|
|
82
58
|
TensorBlock(
|
|
83
|
-
values=
|
|
59
|
+
values=new_p.unsqueeze(-1),
|
|
84
60
|
samples=Labels(
|
|
85
61
|
names=["system", "atom"],
|
|
86
62
|
values=torch.tensor(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flashmd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Accelerated molecular dynamics with large-time-step predictions
|
|
5
5
|
Author: flashmd developers
|
|
6
6
|
License: Apache-2.0
|
|
@@ -22,8 +22,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
22
22
|
Requires-Python: >=3.9
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
+
Requires-Dist: metatrain==2025.11
|
|
25
26
|
Requires-Dist: ase
|
|
26
|
-
Requires-Dist: pet-mad>=1.2.0
|
|
27
27
|
Requires-Dist: huggingface_hub
|
|
28
28
|
Dynamic: license-file
|
|
29
29
|
|
|
@@ -35,6 +35,8 @@ designed to learn and predict molecular dynamics trajectories using long strides
|
|
|
35
35
|
very large time steps. Before using this method, make sure you are aware of its limitations, which are
|
|
36
36
|
discussed in [this preprint](http://arxiv.org/abs/2505.19350).
|
|
37
37
|
|
|
38
|
+
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
39
|
+
|
|
38
40
|
Quickstart
|
|
39
41
|
----------
|
|
40
42
|
|
|
@@ -51,35 +53,41 @@ import ase.build
|
|
|
51
53
|
import ase.units
|
|
52
54
|
from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
|
|
53
55
|
import torch
|
|
54
|
-
from
|
|
56
|
+
from metatomic.torch.ase_calculator import MetatomicCalculator
|
|
55
57
|
|
|
56
|
-
from flashmd import
|
|
58
|
+
from flashmd import get_pretrained
|
|
57
59
|
from flashmd.ase.langevin import Langevin
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
# Choose your time step (go for 10-30x what you would use in normal MD for your system)
|
|
63
|
+
time_step = 16 # 16 fs; also available: 1, 2, 4, 8, 32, 64, 128 fs
|
|
64
|
+
|
|
60
65
|
# Create a structure and initialize velocities
|
|
61
66
|
atoms = ase.build.bulk("Al", "fcc", cubic=True)
|
|
62
67
|
MaxwellBoltzmannDistribution(atoms, temperature_K=300)
|
|
63
68
|
|
|
64
69
|
# Load models
|
|
65
70
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
66
|
-
|
|
71
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
72
|
+
|
|
73
|
+
calculator = MetatomicCalculator(energy_model, device=device)
|
|
67
74
|
atoms.calc = calculator
|
|
68
|
-
model = get_universal_model(16) # 16 fs model; also available: 1, 4, 8, 32, 64 fs
|
|
69
|
-
model = model.to(device)
|
|
70
75
|
|
|
71
76
|
# Run MD
|
|
72
77
|
dyn = Langevin(
|
|
73
78
|
atoms=atoms,
|
|
74
|
-
timestep=
|
|
79
|
+
timestep=time_step*ase.units.fs,
|
|
75
80
|
temperature_K=300,
|
|
76
81
|
time_constant=100*ase.units.fs,
|
|
77
|
-
model=
|
|
82
|
+
model=flashmd_model,
|
|
78
83
|
device=device
|
|
79
84
|
)
|
|
80
85
|
dyn.run(1000)
|
|
81
86
|
```
|
|
82
87
|
|
|
88
|
+
[The first time you use this code and call the `get_pretrained` function, the
|
|
89
|
+
pre-trained models will be downloaded. This might take a bit.]
|
|
90
|
+
|
|
83
91
|
Other available integrators:
|
|
84
92
|
|
|
85
93
|
```py
|
|
@@ -91,11 +99,35 @@ Disclaimer
|
|
|
91
99
|
----------
|
|
92
100
|
|
|
93
101
|
This is experimental software and should only be used if you know what you're doing.
|
|
94
|
-
We recommend using the i-PI integrators for any serious work
|
|
95
|
-
pressure
|
|
102
|
+
We recommend using the i-PI integrators for any serious work and/or if you need to perform
|
|
103
|
+
constant-pressure (NPT) molecular dynamics. You can see
|
|
96
104
|
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
97
105
|
for a usage example.
|
|
98
106
|
Given that the main issue we observe in direct MD trajectories is loss of equipartition
|
|
99
107
|
of energy between different degrees of freedom, we recommend using a local Langevin
|
|
100
108
|
thermostat, and to monitor the temperature of different atomic types or different
|
|
101
109
|
parts of the simulated system.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
Publication
|
|
113
|
+
-----------
|
|
114
|
+
|
|
115
|
+
If you found FlashMD useful, you can cite the corresponding article:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
@article{FlashMD,
|
|
119
|
+
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
120
|
+
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
121
|
+
journal={arXiv preprint arXiv:2505.19350},
|
|
122
|
+
year={2025}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Reproducing the results in the article is supported with FlashMD v0.1.2:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install flashmd==0.1.2 ase==3.24.0 pet-mad==1.4.3
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
and using the "PET-MAD" models (PBEsol) from https://huggingface.co/lab-cosmo/flashmd.
|
|
133
|
+
Note that the results were obtained through the i-PI interface.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from huggingface_hub import hf_hub_download
|
|
2
|
-
from metatomic.torch import AtomisticModel, load_atomistic_model
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def get_universal_model(time_step: int = 16) -> AtomisticModel:
|
|
6
|
-
if time_step not in [1, 4, 8, 16, 32, 64]:
|
|
7
|
-
raise ValueError(
|
|
8
|
-
"Universal FlashMD models are only available for"
|
|
9
|
-
" time steps of 1, 4, 8, 16, 32, 64 fs."
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
model_path = hf_hub_download(
|
|
13
|
-
repo_id="lab-cosmo/flashmd",
|
|
14
|
-
filename=f"flashmd_{time_step}fs.pt",
|
|
15
|
-
cache_dir=None,
|
|
16
|
-
revision="main",
|
|
17
|
-
)
|
|
18
|
-
return load_atomistic_model(model_path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|