BUCToolkit 1.0b0__py3-none-any.whl
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.
- BUCToolkit/BatchGenerate/CheckStructures.py +198 -0
- BUCToolkit/BatchGenerate/__init__.py +6 -0
- BUCToolkit/BatchGenerate/coords_interp.py +127 -0
- BUCToolkit/BatchGenerate/initial_ads_structures.py +351 -0
- BUCToolkit/BatchGenerate/random_replace.py +88 -0
- BUCToolkit/BatchMC/MetropolisMC.py +210 -0
- BUCToolkit/BatchMC/_BaseMC.py +863 -0
- BUCToolkit/BatchMC/__init__.py +8 -0
- BUCToolkit/BatchMD/BiasedMD.py +276 -0
- BUCToolkit/BatchMD/NVE.py +92 -0
- BUCToolkit/BatchMD/NVT.py +510 -0
- BUCToolkit/BatchMD/_BaseMD.py +1251 -0
- BUCToolkit/BatchMD/__init__.py +18 -0
- BUCToolkit/BatchMD/constrained_md/BiasedMD.py +273 -0
- BUCToolkit/BatchMD/constrained_md/ConstrNVE.py +169 -0
- BUCToolkit/BatchMD/constrained_md/ConstrNVT.py +462 -0
- BUCToolkit/BatchMD/constrained_md/NVE.py +78 -0
- BUCToolkit/BatchMD/constrained_md/NVT.py +346 -0
- BUCToolkit/BatchMD/constrained_md/_BaseMD.py +440 -0
- BUCToolkit/BatchMD/constrained_md/_ConstrBaseMD.py +607 -0
- BUCToolkit/BatchMD/constrained_md/__init__.py +18 -0
- BUCToolkit/BatchOptim/TS/CI_NEB.py +286 -0
- BUCToolkit/BatchOptim/TS/Dimer.py +950 -0
- BUCToolkit/BatchOptim/TS/__init__.py +10 -0
- BUCToolkit/BatchOptim/_BaseOpt.py +702 -0
- BUCToolkit/BatchOptim/__init__.py +22 -0
- BUCToolkit/BatchOptim/_utils/__init__.py +6 -0
- BUCToolkit/BatchOptim/_utils/_line_search.py +972 -0
- BUCToolkit/BatchOptim/_utils/_warnings.py +11 -0
- BUCToolkit/BatchOptim/frequency.py +496 -0
- BUCToolkit/BatchOptim/minimize/CG.py +256 -0
- BUCToolkit/BatchOptim/minimize/FIRE.py +310 -0
- BUCToolkit/BatchOptim/minimize/QN.py +205 -0
- BUCToolkit/BatchOptim/minimize/__init__.py +17 -0
- BUCToolkit/BatchStructures/BatchStructuresBase.py +2261 -0
- BUCToolkit/BatchStructures/StructuresIO.py +1394 -0
- BUCToolkit/BatchStructures/__init__.py +15 -0
- BUCToolkit/Preprocessing/__init__.py +7 -0
- BUCToolkit/Preprocessing/load_files.py +1680 -0
- BUCToolkit/Preprocessing/preprocessing.py +923 -0
- BUCToolkit/Preprocessing/sampling.py +299 -0
- BUCToolkit/Preprocessing/supercells.py +140 -0
- BUCToolkit/Preprocessing/write_files.py +524 -0
- BUCToolkit/StandardTemplate.py +417 -0
- BUCToolkit/__init__.py +33 -0
- BUCToolkit/_version.py +7 -0
- BUCToolkit/api/ConstrainedMolecularDynamics.py +347 -0
- BUCToolkit/api/DataLoaders.py +321 -0
- BUCToolkit/api/Losses.py +170 -0
- BUCToolkit/api/Metrics.py +84 -0
- BUCToolkit/api/ModelOptims.py +296 -0
- BUCToolkit/api/MolecularDynamics.py +282 -0
- BUCToolkit/api/MonteCarlo.py +280 -0
- BUCToolkit/api/NEB.py +325 -0
- BUCToolkit/api/Predictor.py +292 -0
- BUCToolkit/api/StructureOptimization.py +484 -0
- BUCToolkit/api/Trainer.py +635 -0
- BUCToolkit/api/VibrationAnalysis.py +279 -0
- BUCToolkit/api/__init__.py +38 -0
- BUCToolkit/api/_io.py +1026 -0
- BUCToolkit/cli/__init__.py +20 -0
- BUCToolkit/cli/cli.py +934 -0
- BUCToolkit/cli/input_stub.py +140 -0
- BUCToolkit/cli/main.py +368 -0
- BUCToolkit/cli/print_logo.py +149 -0
- BUCToolkit/cli/template_model.py +6 -0
- BUCToolkit/io.py +30 -0
- BUCToolkit/utils/AtomSelector.py +64 -0
- BUCToolkit/utils/AtomicNumber2Properties.py +39 -0
- BUCToolkit/utils/ElemListReduce.py +52 -0
- BUCToolkit/utils/Ewald.py +210 -0
- BUCToolkit/utils/IrregularTensorReformat.py +59 -0
- BUCToolkit/utils/_CheckModules.py +30 -0
- BUCToolkit/utils/_Element_info.py +527 -0
- BUCToolkit/utils/__init__.py +22 -0
- BUCToolkit/utils/_para_flatt_list.py +131 -0
- BUCToolkit/utils/_print_formatter.py +59 -0
- BUCToolkit/utils/check_structures.py +204 -0
- BUCToolkit/utils/function_utils.py +147 -0
- BUCToolkit/utils/grad_functions.py +69 -0
- BUCToolkit/utils/index_ops.py +432 -0
- BUCToolkit/utils/setup_loggers.py +137 -0
- buctoolkit-1.0b0.dist-info/METADATA +28 -0
- buctoolkit-1.0b0.dist-info/RECORD +88 -0
- buctoolkit-1.0b0.dist-info/WHEEL +5 -0
- buctoolkit-1.0b0.dist-info/entry_points.txt +6 -0
- buctoolkit-1.0b0.dist-info/licenses/LICENSE +21 -0
- buctoolkit-1.0b0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
""" Canonical ensemble (NVT) Molecular Dynamics via Verlet algo. """
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024-2025.7.4, BUCToolkit.
|
|
4
|
+
# Authors: Pu Pengxin, Song Xin
|
|
5
|
+
# Version: 0.9a
|
|
6
|
+
# File: NVT.py
|
|
7
|
+
# Environment: Python 3.12
|
|
8
|
+
|
|
9
|
+
from typing import Iterable, Dict, Any, List, Literal, Optional, Callable, Sequence, Tuple # noqa: F401
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
import torch as th
|
|
13
|
+
|
|
14
|
+
from BUCToolkit.utils.index_ops import index_reduce
|
|
15
|
+
from ._BaseMD import _rBaseMD
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NVT(_rBaseMD):
|
|
19
|
+
"""
|
|
20
|
+
Canonical ensemble (NVT) molecular dynamics.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
time_step: float, time per step (ps).
|
|
24
|
+
max_step: maxmimum steps.
|
|
25
|
+
thermostat: str, the thermostat of NVT ensemble.
|
|
26
|
+
thermostat_config: Dict|None, configs of thermostat. {'damping_coeff': float} for Langevin, {'time_const': float} for CSVR, {'virt_mass': float} for Nose-Hoover.
|
|
27
|
+
T_init: initial temperature, only to generate initial velocities of atoms by Maxwell-Boltzmann distribution. If V_init is given, T_init will be ignored.
|
|
28
|
+
output_structures_per_step: int, output structures per output_structures_per_step steps.
|
|
29
|
+
device: device that the program rum on.
|
|
30
|
+
verbose: control the detailed degree of output information. 0 for silence, 1 for output Energy and Forces per step, 2 for output all structures.
|
|
31
|
+
|
|
32
|
+
Methods:
|
|
33
|
+
run: run the NVT ensemble BatchMD.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self,
|
|
37
|
+
time_step: float,
|
|
38
|
+
max_step: int,
|
|
39
|
+
thermostat: Literal['Langevin', 'VR', 'Nose-Hoover', 'CSVR'],
|
|
40
|
+
thermostat_config: Dict | None = None,
|
|
41
|
+
T_init: float = 298.15,
|
|
42
|
+
output_file: str | None = None,
|
|
43
|
+
output_structures_per_step: int = 1,
|
|
44
|
+
device: str | th.device = 'cpu',
|
|
45
|
+
verbose: int = 2) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Parameters:
|
|
48
|
+
time_step: float, time per step (ps).
|
|
49
|
+
max_step: maxmimum steps.
|
|
50
|
+
thermostat: str, the thermostat of NVT ensemble.
|
|
51
|
+
thermostat_config: Dict|None, configs of thermostat. {'damping_coeff': float} for Langevin, {'time_const': float} for CSVR, {'virt_mass': float} for Nose-Hoover.
|
|
52
|
+
T_init: initial temperature, only to generate initial velocities of atoms by Maxwell-Boltzmann distribution. If V_init is given, T_init will be ignored.
|
|
53
|
+
output_structures_per_step: int, output structures per output_structures_per_step steps.
|
|
54
|
+
device: device that program run on.
|
|
55
|
+
verbose: control the detailed degree of output information. 0 for silence, 1 for output Energy and Forces per step, 2 for output all structures.
|
|
56
|
+
"""
|
|
57
|
+
super().__init__(
|
|
58
|
+
time_step,
|
|
59
|
+
max_step,
|
|
60
|
+
T_init,
|
|
61
|
+
output_file,
|
|
62
|
+
output_structures_per_step,
|
|
63
|
+
device,
|
|
64
|
+
verbose
|
|
65
|
+
)
|
|
66
|
+
__ENSEMBLES_DICT = {'Langevin': None, 'VR': None, 'Nose-Hoover': None, 'CSVR': None}
|
|
67
|
+
if thermostat not in {'Langevin', 'Langevin_old', 'test', 'VR', 'CSVR', 'Nose-Hoover'}: raise ValueError(f'Unknown Thermostat {thermostat}')
|
|
68
|
+
self.thermostat = thermostat
|
|
69
|
+
if thermostat_config is None:
|
|
70
|
+
thermostat_config = dict()
|
|
71
|
+
self.update_scheme = self.__resolve_update_scheme()
|
|
72
|
+
self.thermostat_config = thermostat_config
|
|
73
|
+
|
|
74
|
+
def __resolve_update_scheme(self):
|
|
75
|
+
"""
|
|
76
|
+
resolve different iteration scheme
|
|
77
|
+
Returns:
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
if self.thermostat == "Langevin":
|
|
81
|
+
return self.__Langevin
|
|
82
|
+
elif self.thermostat == "VR":
|
|
83
|
+
return self.__VR
|
|
84
|
+
elif self.thermostat == "Nose-Hoover":
|
|
85
|
+
return self.__NoseHoover
|
|
86
|
+
elif self.thermostat == "CSVR":
|
|
87
|
+
return self.__CSVR
|
|
88
|
+
else:
|
|
89
|
+
raise NotImplementedError("Unknown Thermostat Type.")
|
|
90
|
+
|
|
91
|
+
def __Langevin(
|
|
92
|
+
self,
|
|
93
|
+
X,
|
|
94
|
+
V,
|
|
95
|
+
Force,
|
|
96
|
+
func,
|
|
97
|
+
grad_func_,
|
|
98
|
+
func_args,
|
|
99
|
+
func_kwargs,
|
|
100
|
+
grad_func_args,
|
|
101
|
+
grad_func_kwargs,
|
|
102
|
+
masses,
|
|
103
|
+
atom_masks,
|
|
104
|
+
is_grad_func_contain_y,
|
|
105
|
+
batch_indices
|
|
106
|
+
)-> (th.Tensor, th.Tensor, th.Tensor, th.Tensor):
|
|
107
|
+
# read thermostat configs
|
|
108
|
+
X = X.detach()
|
|
109
|
+
with th.no_grad():
|
|
110
|
+
damp_coeff = self.thermostat_config.get('damping_coeff', 0.01) # Unit: fs^-1
|
|
111
|
+
alpha = th.e ** (- damp_coeff * self.time_step)
|
|
112
|
+
# half-step
|
|
113
|
+
V.add_(Force / (2. * masses), alpha = self.time_step * 9.64853329045427e-3)
|
|
114
|
+
X.add_(V, alpha = 0.5 * self.time_step)
|
|
115
|
+
# stochastic update velocity
|
|
116
|
+
V.mul_(alpha)
|
|
117
|
+
V.add_(th.sqrt((8314.462618 * self.T_init * (1 - alpha ** 2)) / masses) * 1e-5 * th.randn_like(V))
|
|
118
|
+
#V = alpha * V + th.sqrt((8314.462618 * self.T_init * (1 - alpha ** 2)) / masses) * 1e-5 * th.randn_like(V)
|
|
119
|
+
# the rest half-step
|
|
120
|
+
X.add_(V, alpha = 0.5 * self.time_step)
|
|
121
|
+
V.add_(Force / (2. * masses), alpha = self.time_step * 9.64853329045427e-3)
|
|
122
|
+
# update energy & forces
|
|
123
|
+
with th.set_grad_enabled(self.require_grad):
|
|
124
|
+
X.requires_grad_(self.require_grad)
|
|
125
|
+
Energy = func(X, *func_args, **func_kwargs)
|
|
126
|
+
if is_grad_func_contain_y:
|
|
127
|
+
Force = - grad_func_(X, Energy, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
128
|
+
else:
|
|
129
|
+
Force = - grad_func_(X, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
130
|
+
|
|
131
|
+
return X, V, Energy, Force
|
|
132
|
+
|
|
133
|
+
def __VR(
|
|
134
|
+
self,
|
|
135
|
+
X,
|
|
136
|
+
V,
|
|
137
|
+
Force,
|
|
138
|
+
func,
|
|
139
|
+
grad_func_,
|
|
140
|
+
func_args,
|
|
141
|
+
func_kwargs,
|
|
142
|
+
grad_func_args,
|
|
143
|
+
grad_func_kwargs,
|
|
144
|
+
masses,
|
|
145
|
+
atom_masks,
|
|
146
|
+
is_grad_func_contain_y,
|
|
147
|
+
batch_indices
|
|
148
|
+
)-> (th.Tensor, th.Tensor, th.Tensor, th.Tensor):
|
|
149
|
+
# NVE Step
|
|
150
|
+
X = X.detach()
|
|
151
|
+
with th.no_grad():
|
|
152
|
+
X = X + V * self.time_step + (Force / (2. * masses)) * self.time_step ** 2 * 9.64853329045427e-3
|
|
153
|
+
V = V + (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 # half-step veloc. update, to avoid saving 2 Forces Tensors.
|
|
154
|
+
with th.set_grad_enabled(self.require_grad):
|
|
155
|
+
X.requires_grad_(self.require_grad)
|
|
156
|
+
Energy = func(X, *func_args, **func_kwargs)
|
|
157
|
+
if is_grad_func_contain_y:
|
|
158
|
+
Force = - grad_func_(X, Energy, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
159
|
+
else:
|
|
160
|
+
Force = - grad_func_(X, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
161
|
+
|
|
162
|
+
V = V + (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3
|
|
163
|
+
if batch_indices is not None:
|
|
164
|
+
# Rescaling factor
|
|
165
|
+
alpha = th.sqrt(self.EK_TARGET / self.Ek).unsqueeze(-1).unsqueeze(-1) # (n_batch, 1, 1) | (irregular n_batch, 1, 1)
|
|
166
|
+
V *= alpha.transpose(0, 1)[:, self.batch_scatter, :]
|
|
167
|
+
else:
|
|
168
|
+
# Rescaling factor
|
|
169
|
+
alpha = th.sqrt(self.EK_TARGET / self.Ek).unsqueeze(-1).unsqueeze(-1) # (n_batch, 1, 1) | (irregular n_batch, 1, 1)
|
|
170
|
+
V *= alpha # (n_batch, n_atom, n_dim) * (n_batch, 1, 1)
|
|
171
|
+
|
|
172
|
+
return X, V, Energy, Force
|
|
173
|
+
|
|
174
|
+
def __CSVR(
|
|
175
|
+
self,
|
|
176
|
+
X,
|
|
177
|
+
V,
|
|
178
|
+
Force,
|
|
179
|
+
func,
|
|
180
|
+
grad_func_,
|
|
181
|
+
func_args,
|
|
182
|
+
func_kwargs,
|
|
183
|
+
grad_func_args,
|
|
184
|
+
grad_func_kwargs,
|
|
185
|
+
masses,
|
|
186
|
+
atom_masks,
|
|
187
|
+
is_grad_func_contain_y,
|
|
188
|
+
batch_indices
|
|
189
|
+
)-> (th.Tensor, th.Tensor, th.Tensor, th.Tensor):
|
|
190
|
+
n_batch, n_atom, n_dim = X.shape
|
|
191
|
+
# read thermostat configs
|
|
192
|
+
time_const = self.thermostat_config.get('time_const', 10 * self.time_step) # Unit: fs^-1
|
|
193
|
+
# NVE Step
|
|
194
|
+
X: th.Tensor = X.detach()
|
|
195
|
+
with th.no_grad():
|
|
196
|
+
#X += V * self.time_step + (Force / (2. * masses)) * self.time_step ** 2 * 9.64853329045427e-3
|
|
197
|
+
X.add_(V, alpha=self.time_step)
|
|
198
|
+
X.add_(Force / (2. * masses), alpha=self.time_step ** 2 * 9.64853329045427e-3)
|
|
199
|
+
#V += (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 # half-step veloc. update, to avoid saving 2 Forces Tensors.
|
|
200
|
+
V.add_(Force / (2. * masses), alpha=self.time_step * 9.64853329045427e-3)
|
|
201
|
+
with th.set_grad_enabled(self.require_grad):
|
|
202
|
+
X.requires_grad_(self.require_grad)
|
|
203
|
+
Energy = func(X, *func_args, **func_kwargs)
|
|
204
|
+
if is_grad_func_contain_y:
|
|
205
|
+
Force = - grad_func_(X, Energy, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
206
|
+
else:
|
|
207
|
+
Force = - grad_func_(X, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
208
|
+
|
|
209
|
+
#V += (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3
|
|
210
|
+
V.add_(Force / (2. * masses), alpha=self.time_step * 9.64853329045427e-3)
|
|
211
|
+
|
|
212
|
+
# Kinetic Energy Redistribution, Rescale Velocities
|
|
213
|
+
# sigma = th.sqrt((2. * masses * self.T_init / (self.time_step * time_const)) * (0.138064853 / (6.022140857 * 1.602176634 ** 2)))
|
|
214
|
+
sigma = self.time_step ** 0.5
|
|
215
|
+
if batch_indices is not None:
|
|
216
|
+
self.Ekt_vir += (
|
|
217
|
+
(self.EK_TARGET - self.Ek) * self.time_step / time_const
|
|
218
|
+
+ 2. * th.sqrt(self.EK_TARGET * self.Ek / ((3 * self.batch_tensor - 3) * time_const))
|
|
219
|
+
* th.normal(0., sigma, size=(len(batch_indices),), device=self.device)
|
|
220
|
+
) # Unit: eV/Ang
|
|
221
|
+
self.Ekt_vir = th.where(self.Ekt_vir <= 0., 1e-6, self.Ekt_vir)
|
|
222
|
+
# Rescaling factor
|
|
223
|
+
alpha = th.sqrt(self.Ekt_vir / self.Ek).unsqueeze(-1).unsqueeze(-1) # (n_batch, 1, 1) | (irregular n_batch, 1, 1)
|
|
224
|
+
V *= alpha.transpose(0, 1)[:, self.batch_scatter, :]
|
|
225
|
+
else:
|
|
226
|
+
self.Ekt_vir += (
|
|
227
|
+
(self.EK_TARGET - self.Ek) * self.time_step / time_const
|
|
228
|
+
+ 2. * th.sqrt(self.EK_TARGET * self.Ek / ((3 * n_atom - 3) * time_const))
|
|
229
|
+
* th.normal(0., sigma, size=(n_batch,), device=self.device)
|
|
230
|
+
) # Unit: eV/Ang
|
|
231
|
+
# Rescaling factor
|
|
232
|
+
alpha = th.sqrt(self.Ekt_vir / self.Ek).unsqueeze(-1).unsqueeze(-1) # (n_batch, 1, 1) | (irregular n_batch, 1, 1)
|
|
233
|
+
V *= alpha # (n_batch, n_atom, n_dim) * (n_batch, 1, 1)
|
|
234
|
+
|
|
235
|
+
return X, V, Energy, Force
|
|
236
|
+
|
|
237
|
+
def __NoseHoover(
|
|
238
|
+
self,
|
|
239
|
+
X,
|
|
240
|
+
V,
|
|
241
|
+
Force,
|
|
242
|
+
func,
|
|
243
|
+
grad_func_,
|
|
244
|
+
func_args,
|
|
245
|
+
func_kwargs,
|
|
246
|
+
grad_func_args,
|
|
247
|
+
grad_func_kwargs,
|
|
248
|
+
masses,
|
|
249
|
+
atom_masks,
|
|
250
|
+
is_grad_func_contain_y,
|
|
251
|
+
batch_indices
|
|
252
|
+
) -> (th.Tensor, th.Tensor, th.Tensor, th.Tensor):
|
|
253
|
+
n_batch, n_atom, n_dim = X.shape
|
|
254
|
+
# freedom degree
|
|
255
|
+
n_free = n_dim * (self.batch_tensor - 1) if batch_indices is not None else n_dim * (n_atom - 1)
|
|
256
|
+
# read thermostat config
|
|
257
|
+
smass = self.thermostat_config.get('virt_mass', n_free * 8.617333262145e-5 * self.T_init * 40 ** 2)
|
|
258
|
+
if isinstance(smass, float):
|
|
259
|
+
smass = th.tensor(smass, device=self.device).view(1, 1, 1)
|
|
260
|
+
if batch_indices is not None:
|
|
261
|
+
smass = smass.expand((1, len(batch_indices), 1))
|
|
262
|
+
smass.squeeze_(-1)
|
|
263
|
+
else:
|
|
264
|
+
smass = smass.expand(n_batch, 1, n_dim)
|
|
265
|
+
elif batch_indices is not None:
|
|
266
|
+
smass = smass.unsqueeze(0).expand((1, len(batch_indices)))
|
|
267
|
+
else:
|
|
268
|
+
smass = smass.unsqueeze(-1).expand(n_batch, 1)
|
|
269
|
+
# Main update
|
|
270
|
+
with th.no_grad():
|
|
271
|
+
if batch_indices is not None:
|
|
272
|
+
_iota = self.p_iota[:, self.batch_scatter, None]
|
|
273
|
+
else:
|
|
274
|
+
_iota = self.p_iota
|
|
275
|
+
V += (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 - 0.5 * _iota * V * self.time_step
|
|
276
|
+
X += V * self.time_step
|
|
277
|
+
|
|
278
|
+
with th.set_grad_enabled(self.require_grad):
|
|
279
|
+
X.requires_grad_(self.require_grad)
|
|
280
|
+
_Energy = func(X, *func_args, **func_kwargs)
|
|
281
|
+
if batch_indices is not None:
|
|
282
|
+
Energy = th.sum(_Energy, ).unsqueeze(0)
|
|
283
|
+
else:
|
|
284
|
+
Energy = _Energy
|
|
285
|
+
if is_grad_func_contain_y:
|
|
286
|
+
Force = - grad_func_(X, Energy, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
287
|
+
else:
|
|
288
|
+
Force = - grad_func_(X, *grad_func_args, **grad_func_kwargs) * atom_masks
|
|
289
|
+
|
|
290
|
+
if batch_indices is not None:
|
|
291
|
+
self.p_iota += 0.5 / smass * (
|
|
292
|
+
th.sum(index_reduce(masses * V ** 2 * 103.642696562621738, self.batch_scatter, 1), -1)
|
|
293
|
+
- n_free * 8.617333262145e-5 * self.T_init
|
|
294
|
+
) * self.time_step # (1, n_batch)
|
|
295
|
+
_iota = self.p_iota[:, self.batch_scatter, None] # (1, n_batch*n_atom, 1)
|
|
296
|
+
V += (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 - 0.5 * _iota * V * self.time_step
|
|
297
|
+
self.p_iota += 0.5 / smass * (
|
|
298
|
+
th.sum(index_reduce(masses * V ** 2 * 103.642696562621738, self.batch_scatter, 1), -1)
|
|
299
|
+
- n_free * 8.617333262145e-5 * self.T_init
|
|
300
|
+
) * self.time_step # (1, n_batch)
|
|
301
|
+
else:
|
|
302
|
+
self.p_iota += 0.5 / smass * (
|
|
303
|
+
th.sum(masses * V ** 2 * 103.642696562621738, dim=(-1, -2), keepdim=True) - n_free * 8.617333262145e-5 * self.T_init
|
|
304
|
+
) * self.time_step # (n_batch, 1, n_dim)
|
|
305
|
+
V += (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 - 0.5 * self.p_iota * V * self.time_step
|
|
306
|
+
self.p_iota += 0.5 / smass * (
|
|
307
|
+
th.sum(masses * V ** 2 * 103.642696562621738, dim=(-1, -2), keepdim=True) - n_free * 8.617333262145e-5 * self.T_init
|
|
308
|
+
) * self.time_step # (n_batch, 1, n_dim)
|
|
309
|
+
|
|
310
|
+
return X, V, _Energy, Force
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _updateXV(
|
|
314
|
+
self,
|
|
315
|
+
X,
|
|
316
|
+
V,
|
|
317
|
+
Force,
|
|
318
|
+
func,
|
|
319
|
+
grad_func_,
|
|
320
|
+
func_args,
|
|
321
|
+
func_kwargs,
|
|
322
|
+
grad_func_args,
|
|
323
|
+
grad_func_kwargs,
|
|
324
|
+
masses,
|
|
325
|
+
atom_masks,
|
|
326
|
+
is_grad_func_contain_y,
|
|
327
|
+
batch_indices
|
|
328
|
+
) -> (th.Tensor, th.Tensor, th.Tensor, th.Tensor):
|
|
329
|
+
|
|
330
|
+
x, v, energy, forces = self.update_scheme(
|
|
331
|
+
X,
|
|
332
|
+
V,
|
|
333
|
+
Force,
|
|
334
|
+
func,
|
|
335
|
+
grad_func_,
|
|
336
|
+
func_args,
|
|
337
|
+
func_kwargs,
|
|
338
|
+
grad_func_args,
|
|
339
|
+
grad_func_kwargs,
|
|
340
|
+
masses,
|
|
341
|
+
atom_masks,
|
|
342
|
+
is_grad_func_contain_y,
|
|
343
|
+
batch_indices
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return x, v, energy, forces
|