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.
Files changed (88) hide show
  1. BUCToolkit/BatchGenerate/CheckStructures.py +198 -0
  2. BUCToolkit/BatchGenerate/__init__.py +6 -0
  3. BUCToolkit/BatchGenerate/coords_interp.py +127 -0
  4. BUCToolkit/BatchGenerate/initial_ads_structures.py +351 -0
  5. BUCToolkit/BatchGenerate/random_replace.py +88 -0
  6. BUCToolkit/BatchMC/MetropolisMC.py +210 -0
  7. BUCToolkit/BatchMC/_BaseMC.py +863 -0
  8. BUCToolkit/BatchMC/__init__.py +8 -0
  9. BUCToolkit/BatchMD/BiasedMD.py +276 -0
  10. BUCToolkit/BatchMD/NVE.py +92 -0
  11. BUCToolkit/BatchMD/NVT.py +510 -0
  12. BUCToolkit/BatchMD/_BaseMD.py +1251 -0
  13. BUCToolkit/BatchMD/__init__.py +18 -0
  14. BUCToolkit/BatchMD/constrained_md/BiasedMD.py +273 -0
  15. BUCToolkit/BatchMD/constrained_md/ConstrNVE.py +169 -0
  16. BUCToolkit/BatchMD/constrained_md/ConstrNVT.py +462 -0
  17. BUCToolkit/BatchMD/constrained_md/NVE.py +78 -0
  18. BUCToolkit/BatchMD/constrained_md/NVT.py +346 -0
  19. BUCToolkit/BatchMD/constrained_md/_BaseMD.py +440 -0
  20. BUCToolkit/BatchMD/constrained_md/_ConstrBaseMD.py +607 -0
  21. BUCToolkit/BatchMD/constrained_md/__init__.py +18 -0
  22. BUCToolkit/BatchOptim/TS/CI_NEB.py +286 -0
  23. BUCToolkit/BatchOptim/TS/Dimer.py +950 -0
  24. BUCToolkit/BatchOptim/TS/__init__.py +10 -0
  25. BUCToolkit/BatchOptim/_BaseOpt.py +702 -0
  26. BUCToolkit/BatchOptim/__init__.py +22 -0
  27. BUCToolkit/BatchOptim/_utils/__init__.py +6 -0
  28. BUCToolkit/BatchOptim/_utils/_line_search.py +972 -0
  29. BUCToolkit/BatchOptim/_utils/_warnings.py +11 -0
  30. BUCToolkit/BatchOptim/frequency.py +496 -0
  31. BUCToolkit/BatchOptim/minimize/CG.py +256 -0
  32. BUCToolkit/BatchOptim/minimize/FIRE.py +310 -0
  33. BUCToolkit/BatchOptim/minimize/QN.py +205 -0
  34. BUCToolkit/BatchOptim/minimize/__init__.py +17 -0
  35. BUCToolkit/BatchStructures/BatchStructuresBase.py +2261 -0
  36. BUCToolkit/BatchStructures/StructuresIO.py +1394 -0
  37. BUCToolkit/BatchStructures/__init__.py +15 -0
  38. BUCToolkit/Preprocessing/__init__.py +7 -0
  39. BUCToolkit/Preprocessing/load_files.py +1680 -0
  40. BUCToolkit/Preprocessing/preprocessing.py +923 -0
  41. BUCToolkit/Preprocessing/sampling.py +299 -0
  42. BUCToolkit/Preprocessing/supercells.py +140 -0
  43. BUCToolkit/Preprocessing/write_files.py +524 -0
  44. BUCToolkit/StandardTemplate.py +417 -0
  45. BUCToolkit/__init__.py +33 -0
  46. BUCToolkit/_version.py +7 -0
  47. BUCToolkit/api/ConstrainedMolecularDynamics.py +347 -0
  48. BUCToolkit/api/DataLoaders.py +321 -0
  49. BUCToolkit/api/Losses.py +170 -0
  50. BUCToolkit/api/Metrics.py +84 -0
  51. BUCToolkit/api/ModelOptims.py +296 -0
  52. BUCToolkit/api/MolecularDynamics.py +282 -0
  53. BUCToolkit/api/MonteCarlo.py +280 -0
  54. BUCToolkit/api/NEB.py +325 -0
  55. BUCToolkit/api/Predictor.py +292 -0
  56. BUCToolkit/api/StructureOptimization.py +484 -0
  57. BUCToolkit/api/Trainer.py +635 -0
  58. BUCToolkit/api/VibrationAnalysis.py +279 -0
  59. BUCToolkit/api/__init__.py +38 -0
  60. BUCToolkit/api/_io.py +1026 -0
  61. BUCToolkit/cli/__init__.py +20 -0
  62. BUCToolkit/cli/cli.py +934 -0
  63. BUCToolkit/cli/input_stub.py +140 -0
  64. BUCToolkit/cli/main.py +368 -0
  65. BUCToolkit/cli/print_logo.py +149 -0
  66. BUCToolkit/cli/template_model.py +6 -0
  67. BUCToolkit/io.py +30 -0
  68. BUCToolkit/utils/AtomSelector.py +64 -0
  69. BUCToolkit/utils/AtomicNumber2Properties.py +39 -0
  70. BUCToolkit/utils/ElemListReduce.py +52 -0
  71. BUCToolkit/utils/Ewald.py +210 -0
  72. BUCToolkit/utils/IrregularTensorReformat.py +59 -0
  73. BUCToolkit/utils/_CheckModules.py +30 -0
  74. BUCToolkit/utils/_Element_info.py +527 -0
  75. BUCToolkit/utils/__init__.py +22 -0
  76. BUCToolkit/utils/_para_flatt_list.py +131 -0
  77. BUCToolkit/utils/_print_formatter.py +59 -0
  78. BUCToolkit/utils/check_structures.py +204 -0
  79. BUCToolkit/utils/function_utils.py +147 -0
  80. BUCToolkit/utils/grad_functions.py +69 -0
  81. BUCToolkit/utils/index_ops.py +432 -0
  82. BUCToolkit/utils/setup_loggers.py +137 -0
  83. buctoolkit-1.0b0.dist-info/METADATA +28 -0
  84. buctoolkit-1.0b0.dist-info/RECORD +88 -0
  85. buctoolkit-1.0b0.dist-info/WHEEL +5 -0
  86. buctoolkit-1.0b0.dist-info/entry_points.txt +6 -0
  87. buctoolkit-1.0b0.dist-info/licenses/LICENSE +21 -0
  88. buctoolkit-1.0b0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,8 @@
1
+ # Copyright (c) 2025.7.4, BUCToolkit.
2
+ # Authors: Pu Pengxin, Song Xin
3
+ # Version: 0.9a
4
+ # File: __init__.py
5
+ # Environment: Python 3.12
6
+ from .MetropolisMC import MMC
7
+
8
+ __all__ = ['MMC',]
@@ -0,0 +1,276 @@
1
+ # Copyright (c) 2025.7.4, BUCToolkit.
2
+ # Authors: Pu Pengxin, Song Xin
3
+ # Version: 0.9a
4
+ # File: BiasedMD.py
5
+ # Environment: Python 3.12
6
+
7
+
8
+ from typing import Iterable, Dict, Any, List, Literal, Optional, Callable, Sequence, Tuple # noqa: F401
9
+ import warnings
10
+
11
+ import numpy as np
12
+ import torch as th
13
+ from torch import nn
14
+
15
+ from ._BaseMD import _BaseMD
16
+ from .NVT import NVT
17
+ from .NVE import NVE
18
+
19
+
20
+ class BiasedMD(NVT):
21
+ """
22
+ Performing MD with given external-biased potentials.
23
+ """
24
+ def __init__(
25
+ self,
26
+ time_step: float,
27
+ max_step: int,
28
+ thermostat: Literal['Langevin', 'VR', 'Nose-Hoover', 'CSVR'],
29
+ thermostat_config: Dict | None = None,
30
+ T_init: float = 298.15,
31
+ output_file: str | None = None,
32
+ output_structures_per_step: int = 1,
33
+ device: str | th.device = 'cpu',
34
+ verbose: int = 2
35
+ ):
36
+ super().__init__(
37
+ time_step,
38
+ max_step,
39
+ thermostat,
40
+ thermostat_config,
41
+ T_init,
42
+ output_file,
43
+ output_structures_per_step,
44
+ device,
45
+ verbose
46
+ )
47
+ self.ext_pot_grad_kwargs = None
48
+ self.ext_pot_grad_args = None
49
+ self.ext_pot_grad = None
50
+ self.ext_pot_kwargs = None
51
+ self.ext_pot_args = None
52
+ self.ext_pot = None
53
+ self.__is_set_ext_func = False
54
+
55
+ @staticmethod
56
+ def _auto_grad_func(X: th.Tensor, y: th.Tensor | None = None):
57
+ grad_shape = th.ones_like(y)
58
+ g = th.autograd.grad(y, X, grad_shape)
59
+ return g[0]
60
+
61
+ def set_external_potential(
62
+ self,
63
+ potential_func: Callable,
64
+ potential_grad_func: Callable | None = None,
65
+ func_args:Tuple = tuple(),
66
+ func_kwargs: None | Dict = None,
67
+ grad_func_args: Tuple = tuple(),
68
+ grad_func_kwargs: None | Dict = None,
69
+ is_grad_contain_y: bool = True,
70
+ #is_dynamic: bool = False
71
+ ):
72
+ """
73
+ Set the external potential function.
74
+ Args:
75
+ potential_func: the function of external potential
76
+ potential_grad_func: the gradient of external potential. if None, torch.autograd is applied.
77
+ func_args: arguments of `potential_func`
78
+ func_kwargs: key words arguments of `potential_func`
79
+ grad_func_args: arguments of `potential_grad_func`
80
+ grad_func_kwargs: key words arguments of `potential_grad_func`
81
+ is_grad_contain_y: whether `potential_grad_func` needs dependent variable y as input. if True, potential_grad_func = g(X, y), else g(X)
82
+ #is_dynamic: whether potential function containing time as independent variables. if True, potential_func = f(X, t), else f(X).
83
+
84
+ Returns:
85
+
86
+ """
87
+ if func_kwargs is None: func_kwargs = {}
88
+ if grad_func_kwargs is None: grad_func_kwargs = {}
89
+ self.ext_pot = potential_func
90
+ self.ext_pot_args = func_args
91
+ self.ext_pot_kwargs = func_kwargs
92
+ # ext_grad_func
93
+ if potential_grad_func is None:
94
+ self.ext_pot_grad = self._auto_grad_func
95
+ else:
96
+ self.ext_pot_grad = potential_grad_func
97
+
98
+ self.ext_pot_grad_args = grad_func_args
99
+ self.ext_pot_grad_kwargs = grad_func_kwargs
100
+ self.is_grad_contain_y = is_grad_contain_y
101
+ #self.is_dynamic = is_dynamic
102
+ self.__is_set_ext_func = True
103
+
104
+ def run(
105
+ self,
106
+ func: Any | nn.Module,
107
+ X: th.Tensor,
108
+ Element_list: List[List[str]] | List[List[int]],
109
+ V_init: th.Tensor | None = None,
110
+ grad_func: Any | nn.Module = None,
111
+ func_args: Tuple|List = tuple(),
112
+ func_kwargs: Dict | None = None,
113
+ grad_func_args: Tuple|List = tuple(),
114
+ grad_func_kwargs: Dict | None = None,
115
+ is_grad_func_contain_y: bool = True,
116
+ require_grad: bool = False,
117
+ batch_indices: List[int] | Tuple[int, ...] | th.Tensor | np.ndarray | None = None,
118
+ fixed_atom_tensor: Optional[th.Tensor] = None,
119
+ is_fix_mass_center: bool = False
120
+ ) -> None:
121
+ """
122
+
123
+ Args:
124
+ func:
125
+ X:
126
+ Element_list:
127
+ V_init:
128
+ grad_func:
129
+ func_args:
130
+ func_kwargs:
131
+ grad_func_args:
132
+ grad_func_kwargs:
133
+ is_grad_func_contain_y:
134
+ require_grad:
135
+ batch_indices:
136
+ fixed_atom_tensor:
137
+ is_fix_mass_center:
138
+
139
+ Returns:
140
+
141
+ """
142
+ if func_kwargs is None: func_kwargs = dict()
143
+ if grad_func_kwargs is None: grad_func_kwargs = dict()
144
+ if grad_func is not None:
145
+ _grad_func = grad_func
146
+ else:
147
+ _grad_func = self._auto_grad_func
148
+ is_grad_func_contain_y = True
149
+
150
+ if self.__is_set_ext_func:
151
+ wrapper = _FuncWrapperWithExtPot(
152
+ func,
153
+ self.ext_pot,
154
+ _grad_func,
155
+ self.ext_pot_grad,
156
+ len(func_args),
157
+ func_kwargs.keys(),
158
+ len(grad_func_args),
159
+ grad_func_kwargs.keys()
160
+ )
161
+ wrapped_args = func_args + self.ext_pot_args
162
+ wrapped_kwargs = func_kwargs.update(self.ext_pot_kwargs)
163
+ wrapped_grad_args = grad_func_args + self.ext_pot_grad_args
164
+ wrapped_grad_kwargs = grad_func_kwargs.update(self.ext_pot_grad_kwargs)
165
+
166
+ wrapped_func = wrapper.Energy
167
+ if self.is_grad_contain_y:
168
+ wrapped_grad_func = wrapper.Grad_y
169
+ else:
170
+ wrapped_grad_func = wrapper.Grad
171
+
172
+ res = super().run(
173
+ wrapped_func,
174
+ X,
175
+ Element_list,
176
+ V_init,
177
+ wrapped_grad_func,
178
+ wrapped_args,
179
+ wrapped_kwargs,
180
+ wrapped_grad_args,
181
+ wrapped_grad_kwargs,
182
+ is_grad_func_contain_y,
183
+ require_grad,
184
+ batch_indices,
185
+ fixed_atom_tensor,
186
+ is_fix_mass_center
187
+ )
188
+
189
+ return res
190
+ else:
191
+ raise RuntimeError(f'The external potential function is not set.')
192
+
193
+
194
+ class _FuncWrapperWithExtPot:
195
+ def __init__(
196
+ self,
197
+ func,
198
+ ext_func,
199
+ grad_func,
200
+ ext_grad_func,
201
+ n_func_args = 0,
202
+ k_func_kwargs = None,
203
+ n_grad_func_args = 0,
204
+ k_grad_func_kwargs = None,
205
+
206
+ ) -> None:
207
+ """
208
+ A wrapper to add external function
209
+ Wrap the f(X, ...) into f(X, ...) + ext_func(X, ...)
210
+
211
+ And the wrapped func_args would be the concatenation of `func_args` and `ext_func_args`.
212
+ Hence, the number of func_args, i.e., the `n_func_args` is required to determine that
213
+ the first `n_func_args`-th args belong to `func` and the rest belong to `ext_func`
214
+
215
+ Keyword Args is similar, that require the keys of `func_kwargs`, and the rest belongs to `ext_func`.
216
+
217
+ `grad_func` is so, too.
218
+
219
+ Args:
220
+ func: the original function
221
+ ext_func: the external adding function
222
+ n_func_args: number of args that belongs to `func`
223
+ k_func_kwargs: keywords list that belongs to `func`
224
+ n_grad_func_args,
225
+ k_grad_func_kwargs
226
+
227
+ Methods:
228
+ Energy: input Tensor `X` and PygData `graph`, it will update graph.pos into X and return model(graph)['energy'].
229
+ Grad: input Tensor `X` and PygData `graph`, it will update graph.pos into X and return model(graph)['forces'].
230
+
231
+ """
232
+ self._model = func
233
+ self._ext_func = ext_func
234
+ self._grad_func = grad_func
235
+ self._ext_grad_func = ext_grad_func
236
+ self.n_func_args = n_func_args
237
+ self.k_func_kwargs = set(k_func_kwargs) if k_func_kwargs is not None else set()
238
+ self.n_grad_func_args = n_grad_func_args
239
+ self.k_grad_func_kwargs = set(k_grad_func_kwargs) if k_grad_func_kwargs is not None else set()
240
+
241
+ self.forces = None
242
+
243
+ @staticmethod
244
+ def _auto_grad_func(X: th.Tensor, y: th.Tensor | None = None):
245
+ grad_shape = th.ones_like(y)
246
+ g = th.autograd.grad(y, X, grad_shape)
247
+ return g[0]
248
+
249
+ def Energy(self, X, *func_args, **func_kwargs, ):
250
+ self.X = X
251
+ true_func_args = func_args[:self.n_func_args]
252
+ ext_func_args = func_args[self.n_func_args:]
253
+ true_func_kwargs = {k:func_kwargs[k] for k in (func_kwargs.keys() & self.k_func_kwargs)}
254
+ ext_func_kwargs = {k:func_kwargs[k] for k in (func_kwargs.keys() - self.k_func_kwargs)}
255
+
256
+ self.y = self._model(self.X, *true_func_args, **true_func_kwargs) + self._ext_func(X, *ext_func_args, **ext_func_kwargs)
257
+
258
+ return self.y
259
+
260
+ def Grad(self, X, *grad_func_args, **grad_func_kwargs,):
261
+ true_func_args = grad_func_args[:self.n_func_args]
262
+ ext_func_args = grad_func_args[self.n_func_args:]
263
+ true_func_kwargs = {k: grad_func_kwargs[k] for k in (grad_func_kwargs.keys() & self.k_func_kwargs)}
264
+ ext_func_kwargs = {k: grad_func_kwargs[k] for k in (grad_func_kwargs.keys() - self.k_func_kwargs)}
265
+ g = self._grad_func(X, *true_func_args, **true_func_kwargs) + self._ext_grad_func(X, *ext_func_args, **ext_func_kwargs)
266
+
267
+ return g
268
+
269
+ def Grad_y(self, X, y, *grad_func_args, **grad_func_kwargs, ):
270
+ true_func_args = grad_func_args[:self.n_func_args]
271
+ ext_func_args = grad_func_args[self.n_func_args:]
272
+ true_func_kwargs = {k: grad_func_kwargs[k] for k in (grad_func_kwargs.keys() & self.k_func_kwargs)}
273
+ ext_func_kwargs = {k: grad_func_kwargs[k] for k in (grad_func_kwargs.keys() - self.k_func_kwargs)}
274
+ g = self._grad_func(X, y, *true_func_args, **true_func_kwargs) + self._ext_grad_func(X, y, *ext_func_args, **ext_func_kwargs)
275
+
276
+ return g
@@ -0,0 +1,92 @@
1
+ """ Micro canonical ensemble (NVE) 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: NVE.py
7
+ # Environment: Python 3.12
8
+
9
+ # ruff: noqa: E701, E702, E703
10
+ from typing import Iterable, Dict, Any, List, Literal, Optional, Callable, Sequence, Tuple # noqa: F401
11
+
12
+ import torch as th
13
+
14
+ from ._BaseMD import _BaseMD
15
+
16
+
17
+ class NVE(_BaseMD):
18
+ """
19
+ Micro canonical ensemble (NVE) molecular dynamics implemented via velocity Verlet algo.
20
+
21
+ Parameters:
22
+ time_step: float, time per step (fs).
23
+ max_step: int, maximum steps.
24
+ T_init: float, initial temperature, only to generate initial velocities of atoms by Maxwell-Boltzmann distribution. If V_init is given, T_init will be ignored.
25
+ output_structures_per_step: int, output structures per output_structures_per_step steps.
26
+ device: str|torch.device, device that program rum on.
27
+ verbose: int, control the detailed degree of output information. 0 for silence, 1 for output Energy and Forces per step, 2 for output all structures.
28
+ is_compile: whether to use jit to compile integrator or not.
29
+ compile_kwargs: keyword arguments passed to compile. Only work when is_compile is True.
30
+
31
+ Methods:
32
+ run: run BatchMD.
33
+
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ time_step: float,
39
+ max_step: int,
40
+ T_init: float = 298.15,
41
+ output_file: str | None = None,
42
+ output_structures_per_step: int = 1,
43
+ device: str | th.device = 'cpu',
44
+ verbose: int = 0,
45
+ is_compile: bool = False,
46
+ compile_kwargs: dict | None = None,
47
+ ):
48
+ super().__init__(
49
+ time_step,
50
+ max_step,
51
+ T_init,
52
+ output_file,
53
+ output_structures_per_step,
54
+ device,
55
+ verbose,
56
+ is_compile,
57
+ compile_kwargs
58
+ )
59
+
60
+ def _updateXV(
61
+ self, X, V, Force,
62
+ func, grad_func_, func_args, func_kwargs, grad_func_args, grad_func_kwargs,
63
+ masses, atom_masks, is_grad_func_contain_y, batch_indices,
64
+ ) -> Tuple[th.Tensor, th.Tensor, th.Tensor, th.Tensor]:
65
+ """ Update X, V, Force, and return X, V, Energy, Force. """
66
+ #X: th.Tensor = X.contiguous()
67
+ #V: th.Tensor = V.contiguous()
68
+ #masses: th.Tensor = masses.contiguous()
69
+ with th.no_grad():
70
+ # X = X + V * self.time_step + (Force / (2. * masses)) * self.time_step ** 2 * 9.64853329045427e-3
71
+ V.addcdiv_(Force, masses, value=0.5 * self.time_step * 9.64853329045427e-3)
72
+ X.add_(V, alpha=self.time_step)
73
+ # V = V + (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3 # half-step veloc. update, to avoid saving 2 Forces Tensors.
74
+ # Update V
75
+ Energy, Force = self._calc_EF(
76
+ X,
77
+ func,
78
+ func_args,
79
+ func_kwargs,
80
+ grad_func_,
81
+ grad_func_args,
82
+ grad_func_kwargs,
83
+ is_grad_func_contain_y
84
+ )
85
+ Force.mul_(atom_masks)
86
+
87
+ # V = V + (Force / (2. * masses)) * self.time_step * 9.64853329045427e-3
88
+ V.addcdiv_(Force, masses, value=0.5 * self.time_step * 9.64853329045427e-3)
89
+
90
+ return X, V, Energy, Force
91
+
92
+ return X, V, Energy, Force