flashmd 0.2.4__tar.gz → 0.2.6__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.2.4 → flashmd-0.2.6}/PKG-INFO +51 -60
- {flashmd-0.2.4 → flashmd-0.2.6}/README.md +45 -58
- {flashmd-0.2.4 → flashmd-0.2.6}/pyproject.toml +37 -2
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/__init__.py +3 -1
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/ase/bussi.py +9 -7
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/ase/langevin.py +17 -9
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/ase/velocity_verlet.py +13 -13
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/ipi.py +12 -11
- flashmd-0.2.6/src/flashmd/models.py +102 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/stepper.py +4 -5
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd.egg-info/PKG-INFO +51 -60
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd.egg-info/SOURCES.txt +3 -2
- flashmd-0.2.6/src/flashmd.egg-info/requires.txt +8 -0
- flashmd-0.2.6/tests/test_models.py +65 -0
- flashmd-0.2.6/tests/test_readme.py +37 -0
- flashmd-0.2.4/src/flashmd/ase/npt.py +0 -0
- flashmd-0.2.4/src/flashmd/models.py +0 -61
- flashmd-0.2.4/src/flashmd.egg-info/requires.txt +0 -3
- {flashmd-0.2.4 → flashmd-0.2.6}/LICENSE +0 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/setup.cfg +0 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/ase/__init__.py +0 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd/constraints.py +0 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/src/flashmd.egg-info/dependency_links.txt +0 -0
- {flashmd-0.2.4 → flashmd-0.2.6}/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.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Accelerated molecular dynamics with large-time-step predictions
|
|
5
5
|
Author: flashmd developers
|
|
6
6
|
License: Apache-2.0
|
|
@@ -22,9 +22,13 @@ 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==
|
|
25
|
+
Requires-Dist: metatrain==2026.1
|
|
26
26
|
Requires-Dist: ase
|
|
27
27
|
Requires-Dist: huggingface_hub
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy; extra == "dev"
|
|
28
32
|
Dynamic: license-file
|
|
29
33
|
|
|
30
34
|
FlashMD: universal long-stride molecular dynamics
|
|
@@ -32,13 +36,13 @@ FlashMD: universal long-stride molecular dynamics
|
|
|
32
36
|
|
|
33
37
|
This repository contains custom integrators to run MD trajectories with FlashMD models. These models are
|
|
34
38
|
designed to learn and predict molecular dynamics trajectories using long strides, therefore allowing
|
|
35
|
-
very large time steps.
|
|
39
|
+
very large time steps. When using this method, make sure you are aware of its limitations, which are
|
|
36
40
|
discussed in [this preprint](http://arxiv.org/abs/2505.19350).
|
|
37
41
|
|
|
38
42
|
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
39
43
|
|
|
40
|
-
Quickstart
|
|
41
|
-
|
|
44
|
+
ASE Quickstart (see below for LAMMPS)
|
|
45
|
+
-------------------------------------
|
|
42
46
|
|
|
43
47
|
You can install the package with
|
|
44
48
|
|
|
@@ -46,7 +50,7 @@ You can install the package with
|
|
|
46
50
|
pip install flashmd
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
After installation, you can run accelerated molecular dynamics
|
|
53
|
+
After installation, you can run accelerated molecular dynamics as follows:
|
|
50
54
|
|
|
51
55
|
```py
|
|
52
56
|
import ase.build
|
|
@@ -71,7 +75,7 @@ atoms.set_velocities( # it is generally a good idea to remove any net velocity
|
|
|
71
75
|
|
|
72
76
|
# Load models
|
|
73
77
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
74
|
-
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
78
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes-v2", time_step)
|
|
75
79
|
|
|
76
80
|
# Set the energy model (see below for more precise usage)
|
|
77
81
|
calculator = MetatomicCalculator(energy_model, device=device)
|
|
@@ -99,6 +103,11 @@ Other available integrators:
|
|
|
99
103
|
from flashmd.ase.bussi import Bussi
|
|
100
104
|
```
|
|
101
105
|
|
|
106
|
+
Along with all FlashMD models, we also provide the potential energy model whose
|
|
107
|
+
dynamics they are trained to reproduce. See this short [guide](docs/energy.md) on how to
|
|
108
|
+
best use the energy models if you want to enforce exact energy conservation during
|
|
109
|
+
FlashMD runs, run traditional MD with the energy model, and more.
|
|
110
|
+
|
|
102
111
|
Common pitfalls
|
|
103
112
|
---------------
|
|
104
113
|
|
|
@@ -107,77 +116,59 @@ above is good for metals. However,
|
|
|
107
116
|
- for most materials: try 32 fs (aggressive) or 16 fs (conservative)
|
|
108
117
|
- for aqueous and/or organic systems: try 16 fs (aggressive) or 8 fs (conservative)
|
|
109
118
|
|
|
119
|
+
Using FlashMD in LAMMPS
|
|
120
|
+
-----------------------
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
but also an energy model, which is itself just a machine-learned interatomic potential.
|
|
116
|
-
This is the energy model that the FlashMD model was trained on. You might want to use it
|
|
117
|
-
if...
|
|
118
|
-
|
|
119
|
-
Case 1: you want to run FlashMD with exact energy conservation, available through the
|
|
120
|
-
integrator's (``dyn`` above) parameter ``rescale_energy=True`` (this is enabled by
|
|
121
|
-
default only when targeting the NVE ensemble with ``VelocityVerlet``). In that case,
|
|
122
|
-
besides setting this flag, you should attach the energy calculator to the atoms before
|
|
123
|
-
running FlashMD, exactly as shown above (and below with the more precise
|
|
124
|
-
``do_gradients_with_energy=False`` which will save you memory and computation):
|
|
122
|
+
LAMMPS can allow you to run FlashMD with better computational and memory efficiency.
|
|
123
|
+
Furthermore, it will give you access to more sophisticated types of simulations, such as
|
|
124
|
+
simulations in the NPT ensemble and metadynamics. See [here](docs/lammps.md) for a guide
|
|
125
|
+
on using FlashMD in LAMMPS.
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
... # setting up atoms
|
|
130
|
-
calculator = MetatomicCalculator(energy_model, device=device, do_gradients_with_energy=False)
|
|
131
|
-
atoms.calc = calculator
|
|
132
|
-
... # running FlashMD
|
|
133
|
-
```
|
|
127
|
+
Using FlashMD in i-PI
|
|
128
|
+
---------------------
|
|
134
129
|
|
|
135
|
-
|
|
136
|
-
this
|
|
137
|
-
|
|
130
|
+
You can see
|
|
131
|
+
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
132
|
+
for usage examples. i-PI is our most mature interface, and the one that was used to
|
|
133
|
+
generate all our published results.
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
the energy calculator:
|
|
135
|
+
Models
|
|
136
|
+
------
|
|
142
137
|
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
See [here](docs/models.md) for the complete list of the models we provide. If you are
|
|
139
|
+
new to FlashMD, we recommend starting with the ``pet-omatpes-v2`` models.
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
atoms.calc = calculator
|
|
149
|
-
... # running MD
|
|
150
|
-
```
|
|
141
|
+
Training/fine-tuning your own FlashMD models
|
|
142
|
+
--------------------------------------------
|
|
151
143
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
to
|
|
144
|
+
FlashMD models can be trained from the metatrain library. This
|
|
145
|
+
[tutorial](https://docs.metatensor.org/metatrain/latest/generated_examples/1-advanced/04-flashmd.html)
|
|
146
|
+
shows how to train your own FlashMD model, either from scratch or by fine-tuning of one of our universal models.
|
|
155
147
|
|
|
156
148
|
Disclaimer
|
|
157
149
|
----------
|
|
158
150
|
|
|
159
|
-
This is experimental software and should only be used if you know what you
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
thermostat, and to monitor the temperature of different atomic types or different
|
|
167
|
-
parts of the simulated system.
|
|
151
|
+
This is experimental software and should only be used if you know what you are doing.
|
|
152
|
+
Given that the main issue we observe in FlashMD is loss of equipartition
|
|
153
|
+
of energy between different degrees of freedom, we recommend using a Langevin
|
|
154
|
+
thermostat, possibly monitoring the temperature of different atomic types or different
|
|
155
|
+
parts of the simulated system. For the time being, we also recommend checking all
|
|
156
|
+
FlashMD-powered findings with traditional MD. The energy models that were used to train
|
|
157
|
+
FlashMD, and that we make available in this repository, can be used for this purpose.
|
|
168
158
|
|
|
169
159
|
|
|
170
160
|
Publication
|
|
171
161
|
-----------
|
|
172
162
|
|
|
173
|
-
If you found FlashMD useful, you can cite the corresponding article:
|
|
163
|
+
If you found FlashMD useful, you can cite the corresponding [article](https://arxiv.org/abs/2505.19350):
|
|
174
164
|
|
|
175
165
|
```
|
|
176
|
-
@
|
|
177
|
-
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
178
|
-
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
179
|
-
|
|
180
|
-
year={2025}
|
|
166
|
+
@inproceedings{FlashMD,
|
|
167
|
+
title = {FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
168
|
+
author = {Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
169
|
+
booktitle = {Advances in Neural Information Processing Systems},
|
|
170
|
+
year = {2025},
|
|
171
|
+
url = {https://arxiv.org/abs/2505.19350}
|
|
181
172
|
}
|
|
182
173
|
```
|
|
183
174
|
|
|
@@ -3,13 +3,13 @@ FlashMD: universal long-stride molecular dynamics
|
|
|
3
3
|
|
|
4
4
|
This repository contains custom integrators to run MD trajectories with FlashMD models. These models are
|
|
5
5
|
designed to learn and predict molecular dynamics trajectories using long strides, therefore allowing
|
|
6
|
-
very large time steps.
|
|
6
|
+
very large time steps. When 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
9
|
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
10
10
|
|
|
11
|
-
Quickstart
|
|
12
|
-
|
|
11
|
+
ASE Quickstart (see below for LAMMPS)
|
|
12
|
+
-------------------------------------
|
|
13
13
|
|
|
14
14
|
You can install the package with
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ You can install the package with
|
|
|
17
17
|
pip install flashmd
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
After installation, you can run accelerated molecular dynamics
|
|
20
|
+
After installation, you can run accelerated molecular dynamics as follows:
|
|
21
21
|
|
|
22
22
|
```py
|
|
23
23
|
import ase.build
|
|
@@ -42,7 +42,7 @@ atoms.set_velocities( # it is generally a good idea to remove any net velocity
|
|
|
42
42
|
|
|
43
43
|
# Load models
|
|
44
44
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
45
|
-
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
45
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes-v2", time_step)
|
|
46
46
|
|
|
47
47
|
# Set the energy model (see below for more precise usage)
|
|
48
48
|
calculator = MetatomicCalculator(energy_model, device=device)
|
|
@@ -70,6 +70,11 @@ Other available integrators:
|
|
|
70
70
|
from flashmd.ase.bussi import Bussi
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Along with all FlashMD models, we also provide the potential energy model whose
|
|
74
|
+
dynamics they are trained to reproduce. See this short [guide](docs/energy.md) on how to
|
|
75
|
+
best use the energy models if you want to enforce exact energy conservation during
|
|
76
|
+
FlashMD runs, run traditional MD with the energy model, and more.
|
|
77
|
+
|
|
73
78
|
Common pitfalls
|
|
74
79
|
---------------
|
|
75
80
|
|
|
@@ -78,77 +83,59 @@ above is good for metals. However,
|
|
|
78
83
|
- for most materials: try 32 fs (aggressive) or 16 fs (conservative)
|
|
79
84
|
- for aqueous and/or organic systems: try 16 fs (aggressive) or 8 fs (conservative)
|
|
80
85
|
|
|
86
|
+
Using FlashMD in LAMMPS
|
|
87
|
+
-----------------------
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
but also an energy model, which is itself just a machine-learned interatomic potential.
|
|
87
|
-
This is the energy model that the FlashMD model was trained on. You might want to use it
|
|
88
|
-
if...
|
|
89
|
-
|
|
90
|
-
Case 1: you want to run FlashMD with exact energy conservation, available through the
|
|
91
|
-
integrator's (``dyn`` above) parameter ``rescale_energy=True`` (this is enabled by
|
|
92
|
-
default only when targeting the NVE ensemble with ``VelocityVerlet``). In that case,
|
|
93
|
-
besides setting this flag, you should attach the energy calculator to the atoms before
|
|
94
|
-
running FlashMD, exactly as shown above (and below with the more precise
|
|
95
|
-
``do_gradients_with_energy=False`` which will save you memory and computation):
|
|
89
|
+
LAMMPS can allow you to run FlashMD with better computational and memory efficiency.
|
|
90
|
+
Furthermore, it will give you access to more sophisticated types of simulations, such as
|
|
91
|
+
simulations in the NPT ensemble and metadynamics. See [here](docs/lammps.md) for a guide
|
|
92
|
+
on using FlashMD in LAMMPS.
|
|
96
93
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
... # setting up atoms
|
|
101
|
-
calculator = MetatomicCalculator(energy_model, device=device, do_gradients_with_energy=False)
|
|
102
|
-
atoms.calc = calculator
|
|
103
|
-
... # running FlashMD
|
|
104
|
-
```
|
|
94
|
+
Using FlashMD in i-PI
|
|
95
|
+
---------------------
|
|
105
96
|
|
|
106
|
-
|
|
107
|
-
this
|
|
108
|
-
|
|
97
|
+
You can see
|
|
98
|
+
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
99
|
+
for usage examples. i-PI is our most mature interface, and the one that was used to
|
|
100
|
+
generate all our published results.
|
|
109
101
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
the energy calculator:
|
|
102
|
+
Models
|
|
103
|
+
------
|
|
113
104
|
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
See [here](docs/models.md) for the complete list of the models we provide. If you are
|
|
106
|
+
new to FlashMD, we recommend starting with the ``pet-omatpes-v2`` models.
|
|
116
107
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
atoms.calc = calculator
|
|
120
|
-
... # running MD
|
|
121
|
-
```
|
|
108
|
+
Training/fine-tuning your own FlashMD models
|
|
109
|
+
--------------------------------------------
|
|
122
110
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
to
|
|
111
|
+
FlashMD models can be trained from the metatrain library. This
|
|
112
|
+
[tutorial](https://docs.metatensor.org/metatrain/latest/generated_examples/1-advanced/04-flashmd.html)
|
|
113
|
+
shows how to train your own FlashMD model, either from scratch or by fine-tuning of one of our universal models.
|
|
126
114
|
|
|
127
115
|
Disclaimer
|
|
128
116
|
----------
|
|
129
117
|
|
|
130
|
-
This is experimental software and should only be used if you know what you
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
thermostat, and to monitor the temperature of different atomic types or different
|
|
138
|
-
parts of the simulated system.
|
|
118
|
+
This is experimental software and should only be used if you know what you are doing.
|
|
119
|
+
Given that the main issue we observe in FlashMD is loss of equipartition
|
|
120
|
+
of energy between different degrees of freedom, we recommend using a Langevin
|
|
121
|
+
thermostat, possibly monitoring the temperature of different atomic types or different
|
|
122
|
+
parts of the simulated system. For the time being, we also recommend checking all
|
|
123
|
+
FlashMD-powered findings with traditional MD. The energy models that were used to train
|
|
124
|
+
FlashMD, and that we make available in this repository, can be used for this purpose.
|
|
139
125
|
|
|
140
126
|
|
|
141
127
|
Publication
|
|
142
128
|
-----------
|
|
143
129
|
|
|
144
|
-
If you found FlashMD useful, you can cite the corresponding article:
|
|
130
|
+
If you found FlashMD useful, you can cite the corresponding [article](https://arxiv.org/abs/2505.19350):
|
|
145
131
|
|
|
146
132
|
```
|
|
147
|
-
@
|
|
148
|
-
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
149
|
-
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
150
|
-
|
|
151
|
-
year={2025}
|
|
133
|
+
@inproceedings{FlashMD,
|
|
134
|
+
title = {FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
135
|
+
author = {Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
136
|
+
booktitle = {Advances in Neural Information Processing Systems},
|
|
137
|
+
year = {2025},
|
|
138
|
+
url = {https://arxiv.org/abs/2505.19350}
|
|
152
139
|
}
|
|
153
140
|
```
|
|
154
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flashmd"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.6"
|
|
4
4
|
requires-python = ">=3.9"
|
|
5
5
|
|
|
6
6
|
readme = "README.md"
|
|
@@ -9,7 +9,7 @@ description = "Accelerated molecular dynamics with large-time-step predictions"
|
|
|
9
9
|
authors = [{name = "flashmd developers"}]
|
|
10
10
|
|
|
11
11
|
dependencies = [
|
|
12
|
-
"metatrain==
|
|
12
|
+
"metatrain==2026.1",
|
|
13
13
|
"ase",
|
|
14
14
|
"huggingface_hub",
|
|
15
15
|
]
|
|
@@ -44,5 +44,40 @@ build-backend = "setuptools.build_meta"
|
|
|
44
44
|
[tool.setuptools.packages.find]
|
|
45
45
|
where = ["src"]
|
|
46
46
|
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
dev = [
|
|
49
|
+
"pytest",
|
|
50
|
+
"ruff",
|
|
51
|
+
"mypy",
|
|
52
|
+
]
|
|
53
|
+
|
|
47
54
|
[tool.ruff]
|
|
48
55
|
line-length = 88
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
select = ["E", "F", "B", "I"]
|
|
59
|
+
ignore = ["B018", "B904", "E501"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint.per-file-ignores]
|
|
62
|
+
"**/{tests}/*" = ["D"]
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint.isort]
|
|
65
|
+
lines-after-imports = 2
|
|
66
|
+
known-first-party = ["flashmd"]
|
|
67
|
+
|
|
68
|
+
[tool.ruff.format]
|
|
69
|
+
docstring-code-format = true
|
|
70
|
+
|
|
71
|
+
[tool.mypy]
|
|
72
|
+
follow_imports = 'skip'
|
|
73
|
+
ignore_missing_imports = true
|
|
74
|
+
disable_error_code = ["union-attr"]
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
markers = [
|
|
78
|
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
79
|
+
]
|
|
80
|
+
filterwarnings = [
|
|
81
|
+
"error",
|
|
82
|
+
"ignore:custom data:UserWarning",
|
|
83
|
+
]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from .velocity_verlet import VelocityVerlet
|
|
2
|
-
import ase.units
|
|
3
|
-
from typing import List
|
|
4
|
-
from metatomic.torch import AtomisticModel
|
|
5
|
-
import torch
|
|
6
1
|
import ase
|
|
2
|
+
import ase.units
|
|
7
3
|
import numpy as np
|
|
4
|
+
import torch
|
|
5
|
+
from metatomic.torch import AtomisticModel
|
|
6
|
+
|
|
7
|
+
from .velocity_verlet import VelocityVerlet
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Bussi(VelocityVerlet):
|
|
@@ -13,14 +13,16 @@ class Bussi(VelocityVerlet):
|
|
|
13
13
|
atoms: ase.Atoms,
|
|
14
14
|
timestep: float,
|
|
15
15
|
temperature_K: float,
|
|
16
|
-
model: AtomisticModel
|
|
16
|
+
model: AtomisticModel,
|
|
17
17
|
time_constant: float = 10.0 * ase.units.fs,
|
|
18
18
|
device: str | torch.device = "auto",
|
|
19
19
|
rescale_energy: bool = False,
|
|
20
20
|
random_rotation: bool = False,
|
|
21
21
|
**kwargs,
|
|
22
22
|
):
|
|
23
|
-
super().__init__(
|
|
23
|
+
super().__init__(
|
|
24
|
+
atoms, timestep, model, device, rescale_energy, random_rotation, **kwargs
|
|
25
|
+
)
|
|
24
26
|
|
|
25
27
|
self.temperature_K = temperature_K
|
|
26
28
|
self.time_constant = time_constant
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from .velocity_verlet import VelocityVerlet
|
|
2
|
-
import ase.units
|
|
3
|
-
from typing import List
|
|
4
|
-
from metatomic.torch import AtomisticModel
|
|
5
|
-
import torch
|
|
6
1
|
import ase
|
|
2
|
+
import ase.units
|
|
7
3
|
import numpy as np
|
|
4
|
+
import torch
|
|
5
|
+
from metatomic.torch import AtomisticModel
|
|
6
|
+
|
|
7
|
+
from .velocity_verlet import VelocityVerlet
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Langevin(VelocityVerlet):
|
|
@@ -13,7 +13,7 @@ class Langevin(VelocityVerlet):
|
|
|
13
13
|
atoms: ase.Atoms,
|
|
14
14
|
timestep: float,
|
|
15
15
|
temperature_K: float,
|
|
16
|
-
model: AtomisticModel
|
|
16
|
+
model: AtomisticModel,
|
|
17
17
|
time_constant: float = 100.0 * ase.units.fs,
|
|
18
18
|
fixcm: bool = True,
|
|
19
19
|
device: str | torch.device = "auto",
|
|
@@ -21,13 +21,18 @@ class Langevin(VelocityVerlet):
|
|
|
21
21
|
random_rotation: bool = False,
|
|
22
22
|
**kwargs,
|
|
23
23
|
):
|
|
24
|
-
super().__init__(
|
|
24
|
+
super().__init__(
|
|
25
|
+
atoms, timestep, model, device, rescale_energy, random_rotation, **kwargs
|
|
26
|
+
)
|
|
25
27
|
|
|
26
28
|
self.temperature_K = temperature_K
|
|
27
29
|
self.friction = 1.0 / time_constant
|
|
28
30
|
self.fixcm = fixcm
|
|
29
31
|
if self.fixcm:
|
|
30
|
-
self.atoms.set_velocities(
|
|
32
|
+
self.atoms.set_velocities(
|
|
33
|
+
self.atoms.get_velocities()
|
|
34
|
+
- self.atoms.get_momenta().sum(axis=0) / self.atoms.get_masses().sum()
|
|
35
|
+
)
|
|
31
36
|
|
|
32
37
|
def step(self):
|
|
33
38
|
self.apply_langevin_half_step()
|
|
@@ -43,4 +48,7 @@ class Langevin(VelocityVerlet):
|
|
|
43
48
|
) * np.random.randn(*old_momenta.shape)
|
|
44
49
|
self.atoms.set_momenta(new_momenta)
|
|
45
50
|
if self.fixcm:
|
|
46
|
-
self.atoms.set_velocities(
|
|
51
|
+
self.atoms.set_velocities(
|
|
52
|
+
self.atoms.get_velocities()
|
|
53
|
+
- self.atoms.get_momenta().sum(axis=0) / self.atoms.get_masses().sum()
|
|
54
|
+
)
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import List
|
|
3
|
-
from metatomic.torch import AtomisticModel
|
|
4
|
-
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
1
|
+
import ase
|
|
5
2
|
import ase.units
|
|
3
|
+
import numpy as np
|
|
6
4
|
import torch
|
|
5
|
+
from ase.md.md import MolecularDynamics
|
|
6
|
+
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
7
|
+
from metatomic.torch import AtomisticModel, System
|
|
7
8
|
from metatomic.torch.ase_calculator import _ase_to_torch_data
|
|
8
|
-
from metatomic.torch import System
|
|
9
|
-
import ase
|
|
10
|
-
from ..stepper import FlashMDStepper
|
|
11
|
-
import numpy as np
|
|
12
9
|
from scipy.spatial.transform import Rotation
|
|
13
10
|
|
|
11
|
+
from ..stepper import FlashMDStepper
|
|
12
|
+
|
|
14
13
|
|
|
15
14
|
class VelocityVerlet(MolecularDynamics):
|
|
16
15
|
def __init__(
|
|
17
16
|
self,
|
|
18
17
|
atoms: ase.Atoms,
|
|
19
18
|
timestep: float,
|
|
20
|
-
model: AtomisticModel
|
|
19
|
+
model: AtomisticModel,
|
|
21
20
|
device: str | torch.device = "auto",
|
|
22
21
|
rescale_energy: bool = True,
|
|
23
22
|
random_rotation: bool = False,
|
|
@@ -66,8 +65,8 @@ class VelocityVerlet(MolecularDynamics):
|
|
|
66
65
|
system.positions = system.positions @ R.T
|
|
67
66
|
# change momentum TensorMap in place
|
|
68
67
|
system.get_data("momenta").block().values[:] = (
|
|
69
|
-
|
|
70
|
-
)
|
|
68
|
+
system.get_data("momenta").block().values.squeeze(-1) @ R.T
|
|
69
|
+
).unsqueeze(-1)
|
|
71
70
|
|
|
72
71
|
new_system = self.stepper.step(system)
|
|
73
72
|
|
|
@@ -76,8 +75,8 @@ class VelocityVerlet(MolecularDynamics):
|
|
|
76
75
|
new_system.cell = old_cell
|
|
77
76
|
new_system.positions = new_system.positions @ R
|
|
78
77
|
new_system.get_data("momenta").block().values[:] = (
|
|
79
|
-
|
|
80
|
-
)
|
|
78
|
+
new_system.get_data("momenta").block().values.squeeze(-1) @ R
|
|
79
|
+
).unsqueeze(-1)
|
|
81
80
|
|
|
82
81
|
self.atoms.set_positions(new_system.positions.detach().cpu().numpy())
|
|
83
82
|
self.atoms.set_momenta(
|
|
@@ -127,6 +126,7 @@ class VelocityVerlet(MolecularDynamics):
|
|
|
127
126
|
for _ in self.irun(steps=steps):
|
|
128
127
|
pass
|
|
129
128
|
|
|
129
|
+
|
|
130
130
|
def _convert_atoms_to_system(
|
|
131
131
|
atoms: ase.Atoms, dtype: str, device: str | torch.device
|
|
132
132
|
) -> System:
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
import ase.data
|
|
2
|
+
import ase.units
|
|
3
|
+
import numpy as np
|
|
4
|
+
import torch
|
|
5
|
+
from ipi.engine.motion.dynamics import NPTIntegrator, NVEIntegrator, NVTIntegrator
|
|
1
6
|
from ipi.utils.depend import dstrip
|
|
2
|
-
from ipi.utils.units import Constants
|
|
3
|
-
from ipi.utils.messages import verbosity, info
|
|
4
7
|
from ipi.utils.mathtools import random_rotation as random_rotation_matrix
|
|
5
|
-
from ipi.
|
|
8
|
+
from ipi.utils.messages import info, verbosity
|
|
9
|
+
from ipi.utils.units import Constants
|
|
10
|
+
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
11
|
+
from metatomic.torch import System
|
|
6
12
|
|
|
7
13
|
from flashmd.stepper import FlashMDStepper
|
|
8
|
-
import ase.units
|
|
9
|
-
import torch
|
|
10
|
-
import numpy as np
|
|
11
|
-
import ase.data
|
|
12
|
-
|
|
13
|
-
from metatomic.torch import System
|
|
14
|
-
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
def get_standard_vv_step(
|
|
@@ -56,7 +55,9 @@ def get_standard_vv_step(
|
|
|
56
55
|
return vv_step
|
|
57
56
|
|
|
58
57
|
|
|
59
|
-
def get_flashmd_vv_step(
|
|
58
|
+
def get_flashmd_vv_step(
|
|
59
|
+
sim, model, device, rescale_energy=False, random_rotation=False
|
|
60
|
+
):
|
|
60
61
|
capabilities = model.capabilities()
|
|
61
62
|
|
|
62
63
|
model_timestep = float(model.module.timestep)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
from huggingface_hub import hf_hub_download
|
|
7
|
+
from metatomic.torch import AtomisticModel, load_atomistic_model
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
AVAILABLE_MLIPS = ["pet-omatpes", "pet-omatpes-v2"]
|
|
11
|
+
AVAILABLE_TIME_STEPS = {
|
|
12
|
+
"pet-omatpes": [1, 2, 4, 8, 16, 32, 64, 128],
|
|
13
|
+
"pet-omatpes-v2": [1, 2, 4, 8, 16, 32, 64, 128],
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_pretrained(mlip: str = "pet-omatpes-v2", time_step: int = 16) -> AtomisticModel:
|
|
18
|
+
if mlip not in AVAILABLE_MLIPS:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
f"MLIP '{mlip}' is not available. "
|
|
21
|
+
f"Available MLIPs are: {', '.join(AVAILABLE_MLIPS)}."
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if time_step not in AVAILABLE_TIME_STEPS[mlip]:
|
|
25
|
+
raise ValueError(
|
|
26
|
+
f"Pre-trained FlashMD models based on the {mlip} MLIP are only available "
|
|
27
|
+
f"for time steps of {', '.join(map(str, AVAILABLE_TIME_STEPS[mlip]))} fs."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Get checkpoints corresponding to the selected MLIP and FlashMD models
|
|
31
|
+
mlip_path = hf_hub_download(
|
|
32
|
+
repo_id="lab-cosmo/flashmd",
|
|
33
|
+
filename=f"mlip_{mlip}.ckpt",
|
|
34
|
+
cache_dir=None,
|
|
35
|
+
revision="main",
|
|
36
|
+
)
|
|
37
|
+
flashmd_path = hf_hub_download(
|
|
38
|
+
repo_id="lab-cosmo/flashmd",
|
|
39
|
+
filename=f"flashmd_{mlip}_{time_step}fs.ckpt",
|
|
40
|
+
cache_dir=None,
|
|
41
|
+
revision="main",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Now we need to export both using metatrain. However, we don't want to do it if
|
|
45
|
+
# HuggingFace hasn't downloaded a new version of the files, so we only re-export
|
|
46
|
+
# if the files above have changed in the last 10 seconds.
|
|
47
|
+
reexport = False
|
|
48
|
+
exported_mlip_path = mlip_path.replace(".ckpt", ".pt")
|
|
49
|
+
exported_flashmd_path = flashmd_path.replace(".ckpt", ".pt")
|
|
50
|
+
if not os.path.exists(exported_mlip_path) or not os.path.exists(
|
|
51
|
+
exported_flashmd_path
|
|
52
|
+
):
|
|
53
|
+
reexport = True
|
|
54
|
+
mlip_mtime = os.path.getmtime(mlip_path)
|
|
55
|
+
flashmd_mtime = os.path.getmtime(flashmd_path)
|
|
56
|
+
if (time.time() - mlip_mtime < 10) or (time.time() - flashmd_mtime < 10):
|
|
57
|
+
reexport = True
|
|
58
|
+
if reexport:
|
|
59
|
+
subprocess.run(
|
|
60
|
+
["mtt", "export", mlip_path, "-o", exported_mlip_path], capture_output=True
|
|
61
|
+
)
|
|
62
|
+
subprocess.run(
|
|
63
|
+
["mtt", "export", flashmd_path, "-o", exported_flashmd_path],
|
|
64
|
+
capture_output=True,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Load as AtomisticModel instances.
|
|
68
|
+
# If it doesn't work, try to re-export once and load again (this will, among
|
|
69
|
+
# others, catch upgrades in metatomic that break compatibility)
|
|
70
|
+
try:
|
|
71
|
+
mlip_model = load_atomistic_model(exported_mlip_path)
|
|
72
|
+
flashmd_model = load_atomistic_model(exported_flashmd_path)
|
|
73
|
+
except Exception:
|
|
74
|
+
subprocess.run(
|
|
75
|
+
["mtt", "export", mlip_path, "-o", exported_mlip_path], capture_output=True
|
|
76
|
+
)
|
|
77
|
+
subprocess.run(
|
|
78
|
+
["mtt", "export", flashmd_path, "-o", exported_flashmd_path],
|
|
79
|
+
capture_output=True,
|
|
80
|
+
)
|
|
81
|
+
mlip_model = load_atomistic_model(exported_mlip_path)
|
|
82
|
+
flashmd_model = load_atomistic_model(exported_flashmd_path)
|
|
83
|
+
|
|
84
|
+
return mlip_model, flashmd_model
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def save_checkpoint(mlip: str = "pet-omatpes-v2", time_step: int = 16):
|
|
88
|
+
if time_step not in AVAILABLE_TIME_STEPS[mlip]:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f"Pre-trained FlashMD models based on the {mlip} MLIP are only available "
|
|
91
|
+
f"for time steps of {', '.join(map(str, AVAILABLE_TIME_STEPS[mlip]))} fs."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
checkpoint_path = hf_hub_download(
|
|
95
|
+
repo_id="lab-cosmo/flashmd",
|
|
96
|
+
filename=f"flashmd_{mlip}_{time_step}fs.ckpt",
|
|
97
|
+
cache_dir=None,
|
|
98
|
+
revision="main",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Copy it to the current directory
|
|
102
|
+
shutil.copyfile(checkpoint_path, f"flashmd_{mlip}_{time_step}fs.ckpt")
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# from ..utils.pretrained import load_pretrained_models
|
|
2
|
-
|
|
3
|
-
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
2
|
+
import ase.units
|
|
4
3
|
import torch
|
|
5
|
-
from
|
|
4
|
+
from metatensor.torch import Labels, TensorBlock, TensorMap
|
|
5
|
+
from metatomic.torch import AtomisticModel, ModelEvaluationOptions, ModelOutput, System
|
|
6
6
|
from metatrain.utils.neighbor_lists import get_system_with_neighbor_lists
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
from .constraints import enforce_physical_constraints
|
|
9
|
-
import ase.units
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class FlashMDStepper:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flashmd
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Accelerated molecular dynamics with large-time-step predictions
|
|
5
5
|
Author: flashmd developers
|
|
6
6
|
License: Apache-2.0
|
|
@@ -22,9 +22,13 @@ 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==
|
|
25
|
+
Requires-Dist: metatrain==2026.1
|
|
26
26
|
Requires-Dist: ase
|
|
27
27
|
Requires-Dist: huggingface_hub
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy; extra == "dev"
|
|
28
32
|
Dynamic: license-file
|
|
29
33
|
|
|
30
34
|
FlashMD: universal long-stride molecular dynamics
|
|
@@ -32,13 +36,13 @@ FlashMD: universal long-stride molecular dynamics
|
|
|
32
36
|
|
|
33
37
|
This repository contains custom integrators to run MD trajectories with FlashMD models. These models are
|
|
34
38
|
designed to learn and predict molecular dynamics trajectories using long strides, therefore allowing
|
|
35
|
-
very large time steps.
|
|
39
|
+
very large time steps. When using this method, make sure you are aware of its limitations, which are
|
|
36
40
|
discussed in [this preprint](http://arxiv.org/abs/2505.19350).
|
|
37
41
|
|
|
38
42
|
The pre-trained models we make available are trained to reproduce ab-initio MD at the r2SCAN level of theory.
|
|
39
43
|
|
|
40
|
-
Quickstart
|
|
41
|
-
|
|
44
|
+
ASE Quickstart (see below for LAMMPS)
|
|
45
|
+
-------------------------------------
|
|
42
46
|
|
|
43
47
|
You can install the package with
|
|
44
48
|
|
|
@@ -46,7 +50,7 @@ You can install the package with
|
|
|
46
50
|
pip install flashmd
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
After installation, you can run accelerated molecular dynamics
|
|
53
|
+
After installation, you can run accelerated molecular dynamics as follows:
|
|
50
54
|
|
|
51
55
|
```py
|
|
52
56
|
import ase.build
|
|
@@ -71,7 +75,7 @@ atoms.set_velocities( # it is generally a good idea to remove any net velocity
|
|
|
71
75
|
|
|
72
76
|
# Load models
|
|
73
77
|
device="cuda" if torch.cuda.is_available() else "cpu"
|
|
74
|
-
energy_model, flashmd_model = get_pretrained("pet-omatpes", time_step)
|
|
78
|
+
energy_model, flashmd_model = get_pretrained("pet-omatpes-v2", time_step)
|
|
75
79
|
|
|
76
80
|
# Set the energy model (see below for more precise usage)
|
|
77
81
|
calculator = MetatomicCalculator(energy_model, device=device)
|
|
@@ -99,6 +103,11 @@ Other available integrators:
|
|
|
99
103
|
from flashmd.ase.bussi import Bussi
|
|
100
104
|
```
|
|
101
105
|
|
|
106
|
+
Along with all FlashMD models, we also provide the potential energy model whose
|
|
107
|
+
dynamics they are trained to reproduce. See this short [guide](docs/energy.md) on how to
|
|
108
|
+
best use the energy models if you want to enforce exact energy conservation during
|
|
109
|
+
FlashMD runs, run traditional MD with the energy model, and more.
|
|
110
|
+
|
|
102
111
|
Common pitfalls
|
|
103
112
|
---------------
|
|
104
113
|
|
|
@@ -107,77 +116,59 @@ above is good for metals. However,
|
|
|
107
116
|
- for most materials: try 32 fs (aggressive) or 16 fs (conservative)
|
|
108
117
|
- for aqueous and/or organic systems: try 16 fs (aggressive) or 8 fs (conservative)
|
|
109
118
|
|
|
119
|
+
Using FlashMD in LAMMPS
|
|
120
|
+
-----------------------
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
but also an energy model, which is itself just a machine-learned interatomic potential.
|
|
116
|
-
This is the energy model that the FlashMD model was trained on. You might want to use it
|
|
117
|
-
if...
|
|
118
|
-
|
|
119
|
-
Case 1: you want to run FlashMD with exact energy conservation, available through the
|
|
120
|
-
integrator's (``dyn`` above) parameter ``rescale_energy=True`` (this is enabled by
|
|
121
|
-
default only when targeting the NVE ensemble with ``VelocityVerlet``). In that case,
|
|
122
|
-
besides setting this flag, you should attach the energy calculator to the atoms before
|
|
123
|
-
running FlashMD, exactly as shown above (and below with the more precise
|
|
124
|
-
``do_gradients_with_energy=False`` which will save you memory and computation):
|
|
122
|
+
LAMMPS can allow you to run FlashMD with better computational and memory efficiency.
|
|
123
|
+
Furthermore, it will give you access to more sophisticated types of simulations, such as
|
|
124
|
+
simulations in the NPT ensemble and metadynamics. See [here](docs/lammps.md) for a guide
|
|
125
|
+
on using FlashMD in LAMMPS.
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
... # setting up atoms
|
|
130
|
-
calculator = MetatomicCalculator(energy_model, device=device, do_gradients_with_energy=False)
|
|
131
|
-
atoms.calc = calculator
|
|
132
|
-
... # running FlashMD
|
|
133
|
-
```
|
|
127
|
+
Using FlashMD in i-PI
|
|
128
|
+
---------------------
|
|
134
129
|
|
|
135
|
-
|
|
136
|
-
this
|
|
137
|
-
|
|
130
|
+
You can see
|
|
131
|
+
[this cookbook recipe](https://atomistic-cookbook.org/examples/flashmd/flashmd-demo.html)
|
|
132
|
+
for usage examples. i-PI is our most mature interface, and the one that was used to
|
|
133
|
+
generate all our published results.
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
the energy calculator:
|
|
135
|
+
Models
|
|
136
|
+
------
|
|
142
137
|
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
See [here](docs/models.md) for the complete list of the models we provide. If you are
|
|
139
|
+
new to FlashMD, we recommend starting with the ``pet-omatpes-v2`` models.
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
atoms.calc = calculator
|
|
149
|
-
... # running MD
|
|
150
|
-
```
|
|
141
|
+
Training/fine-tuning your own FlashMD models
|
|
142
|
+
--------------------------------------------
|
|
151
143
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
to
|
|
144
|
+
FlashMD models can be trained from the metatrain library. This
|
|
145
|
+
[tutorial](https://docs.metatensor.org/metatrain/latest/generated_examples/1-advanced/04-flashmd.html)
|
|
146
|
+
shows how to train your own FlashMD model, either from scratch or by fine-tuning of one of our universal models.
|
|
155
147
|
|
|
156
148
|
Disclaimer
|
|
157
149
|
----------
|
|
158
150
|
|
|
159
|
-
This is experimental software and should only be used if you know what you
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
thermostat, and to monitor the temperature of different atomic types or different
|
|
167
|
-
parts of the simulated system.
|
|
151
|
+
This is experimental software and should only be used if you know what you are doing.
|
|
152
|
+
Given that the main issue we observe in FlashMD is loss of equipartition
|
|
153
|
+
of energy between different degrees of freedom, we recommend using a Langevin
|
|
154
|
+
thermostat, possibly monitoring the temperature of different atomic types or different
|
|
155
|
+
parts of the simulated system. For the time being, we also recommend checking all
|
|
156
|
+
FlashMD-powered findings with traditional MD. The energy models that were used to train
|
|
157
|
+
FlashMD, and that we make available in this repository, can be used for this purpose.
|
|
168
158
|
|
|
169
159
|
|
|
170
160
|
Publication
|
|
171
161
|
-----------
|
|
172
162
|
|
|
173
|
-
If you found FlashMD useful, you can cite the corresponding article:
|
|
163
|
+
If you found FlashMD useful, you can cite the corresponding [article](https://arxiv.org/abs/2505.19350):
|
|
174
164
|
|
|
175
165
|
```
|
|
176
|
-
@
|
|
177
|
-
title={FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
178
|
-
author={Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
179
|
-
|
|
180
|
-
year={2025}
|
|
166
|
+
@inproceedings{FlashMD,
|
|
167
|
+
title = {FlashMD: long-stride, universal prediction of molecular dynamics},
|
|
168
|
+
author = {Bigi, Filippo and Chong, Sanggyu and Kristiadi, Agustinus and Ceriotti, Michele},
|
|
169
|
+
booktitle = {Advances in Neural Information Processing Systems},
|
|
170
|
+
year = {2025},
|
|
171
|
+
url = {https://arxiv.org/abs/2505.19350}
|
|
181
172
|
}
|
|
182
173
|
```
|
|
183
174
|
|
|
@@ -14,5 +14,6 @@ src/flashmd.egg-info/top_level.txt
|
|
|
14
14
|
src/flashmd/ase/__init__.py
|
|
15
15
|
src/flashmd/ase/bussi.py
|
|
16
16
|
src/flashmd/ase/langevin.py
|
|
17
|
-
src/flashmd/ase/
|
|
18
|
-
|
|
17
|
+
src/flashmd/ase/velocity_verlet.py
|
|
18
|
+
tests/test_models.py
|
|
19
|
+
tests/test_readme.py
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from flashmd.models import AVAILABLE_MLIPS, AVAILABLE_TIME_STEPS
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_available_mlips():
|
|
7
|
+
"""Test that AVAILABLE_MLIPS is defined and contains expected values."""
|
|
8
|
+
assert isinstance(AVAILABLE_MLIPS, list)
|
|
9
|
+
assert len(AVAILABLE_MLIPS) > 0
|
|
10
|
+
assert "pet-omatpes" in AVAILABLE_MLIPS
|
|
11
|
+
assert "pet-omatpes-v2" in AVAILABLE_MLIPS
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_available_time_steps():
|
|
15
|
+
"""Test that AVAILABLE_TIME_STEPS is defined and contains expected values."""
|
|
16
|
+
assert isinstance(AVAILABLE_TIME_STEPS, dict)
|
|
17
|
+
assert len(AVAILABLE_TIME_STEPS) > 0
|
|
18
|
+
|
|
19
|
+
# Check that each MLIP has time steps defined
|
|
20
|
+
for mlip in AVAILABLE_MLIPS:
|
|
21
|
+
assert mlip in AVAILABLE_TIME_STEPS
|
|
22
|
+
assert isinstance(AVAILABLE_TIME_STEPS[mlip], list)
|
|
23
|
+
assert len(AVAILABLE_TIME_STEPS[mlip]) > 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_get_pretrained_invalid_mlip():
|
|
27
|
+
"""Test that get_pretrained raises ValueError for invalid MLIP."""
|
|
28
|
+
from flashmd.models import get_pretrained
|
|
29
|
+
|
|
30
|
+
with pytest.raises(ValueError, match="MLIP 'invalid_mlip' is not available"):
|
|
31
|
+
get_pretrained(mlip="invalid_mlip", time_step=16)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_pretrained_invalid_time_step():
|
|
35
|
+
"""Test that get_pretrained raises ValueError for invalid time step."""
|
|
36
|
+
from flashmd.models import get_pretrained
|
|
37
|
+
|
|
38
|
+
with pytest.raises(ValueError, match="Pre-trained FlashMD models"):
|
|
39
|
+
get_pretrained(mlip="pet-omatpes", time_step=999)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_save_checkpoint_invalid_time_step():
|
|
43
|
+
"""Test that save_checkpoint raises ValueError for invalid time step."""
|
|
44
|
+
from flashmd.models import save_checkpoint
|
|
45
|
+
|
|
46
|
+
with pytest.raises(ValueError, match="Pre-trained FlashMD models"):
|
|
47
|
+
save_checkpoint(mlip="pet-omatpes-v2", time_step=999)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_save_checkpoint(monkeypatch):
|
|
51
|
+
"""Test that save_checkpoint saves the checkpoint file."""
|
|
52
|
+
from flashmd.models import save_checkpoint
|
|
53
|
+
|
|
54
|
+
# Mock hf_hub_download and shutil.copyfile
|
|
55
|
+
def mock_hf_hub_download(repo_id, filename, cache_dir, revision):
|
|
56
|
+
return f"/path/to/{filename}"
|
|
57
|
+
|
|
58
|
+
def mock_copyfile(src, dst):
|
|
59
|
+
assert src == "/path/to/flashmd_pet-omatpes-v2_16fs.ckpt"
|
|
60
|
+
assert dst == "flashmd_pet-omatpes-v2_16fs.ckpt"
|
|
61
|
+
|
|
62
|
+
monkeypatch.setattr("flashmd.models.hf_hub_download", mock_hf_hub_download)
|
|
63
|
+
monkeypatch.setattr("flashmd.models.shutil.copyfile", mock_copyfile)
|
|
64
|
+
|
|
65
|
+
save_checkpoint(mlip="pet-omatpes-v2", time_step=16)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Test that the README example works correctly."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def extract_python_code_from_readme():
|
|
8
|
+
"""Extract the first Python code block from README.md."""
|
|
9
|
+
readme_path = Path(__file__).parent.parent / "README.md"
|
|
10
|
+
content = readme_path.read_text()
|
|
11
|
+
|
|
12
|
+
# Find the first ```py or ```python code block
|
|
13
|
+
pattern = r"```(?:py|python)\n(.*?)\n```"
|
|
14
|
+
matches = re.findall(pattern, content, re.DOTALL)
|
|
15
|
+
|
|
16
|
+
if not matches:
|
|
17
|
+
raise ValueError("No Python code block found in README.md")
|
|
18
|
+
|
|
19
|
+
# Return the first code block (the ASE usage example)
|
|
20
|
+
return matches[0]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_readme_example():
|
|
24
|
+
"""Test that the README example runs successfully with 10 steps instead of 1000."""
|
|
25
|
+
# Extract the code from README
|
|
26
|
+
code = extract_python_code_from_readme()
|
|
27
|
+
|
|
28
|
+
# Modify the code to run for only 10 steps instead of 1000
|
|
29
|
+
modified_code = code.replace("dyn.run(1000)", "dyn.run(10)")
|
|
30
|
+
|
|
31
|
+
# Execute the code
|
|
32
|
+
exec_globals = {}
|
|
33
|
+
exec(modified_code, exec_globals)
|
|
34
|
+
|
|
35
|
+
# Basic validation: check that the dynamics object was created
|
|
36
|
+
assert "dyn" in exec_globals
|
|
37
|
+
assert exec_globals["dyn"] is not None
|
|
File without changes
|
|
@@ -1,61 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|