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,417 @@
1
+ """
2
+ The standard template of input object and models.
3
+ """
4
+ # Copyright (c) 2026.4.3, BUCToolkit.
5
+ # Authors: Pu Pengxin, Song Xin
6
+ # Version: 1.0b
7
+ # File: StandardTemplate.py
8
+ # Environment: Python 3.12
9
+
10
+ from abc import ABC, abstractmethod
11
+ from typing import Dict, Tuple, Optional, List, Any
12
+
13
+ import torch as th
14
+
15
+
16
+ class StandardModel(ABC):
17
+ """
18
+ An abstract base class that convert arbitrary function into BUCToolkit supported format to structure opt, MD, and MC, etc.
19
+ It can receive any user-defined Callable object `model` which returns torch.Tensors, and convert it to the standard dict format
20
+ {'energy': energy, 'forces': forces} by user-override `initialize_model` (optional), `calc_energy`, and `calc_forces` with
21
+ input `args` and `kwargs`.
22
+ DO NOT SUPPORT FOR TRAINING.
23
+
24
+ """
25
+ def __init__(
26
+ self,
27
+ model,
28
+ args_for_init: Tuple = tuple(),
29
+ kwargs_for_init: Dict | None = None,
30
+ device: str = 'cpu',
31
+ *args,
32
+ **kwargs
33
+ ):
34
+ """
35
+ The original PyTorch model with (hyper-)parameters args and kwargs.
36
+ Args:
37
+ model: the main function
38
+ args_for_init: arguments passed to model
39
+ kwargs_for_init: keyword arguments passed to model
40
+ args: additional positional arguments for calc_energy or calc_forces, if necessary
41
+ kwargs: additional keyword arguments for calc_energy or calc_forces, if necessary
42
+ """
43
+ if kwargs_for_init is None: kwargs_for_init = {}
44
+ super().__init__()
45
+ self.model = model
46
+ self.args = args
47
+ self.kwargs = kwargs
48
+ self.device = th.device(device)
49
+
50
+ self.initialize_model(*args_for_init, **kwargs_for_init)
51
+
52
+ def initialize_model(self, *args, **kwargs):
53
+ """
54
+ Initialize & config the model, if necessary.
55
+ Args:
56
+ *args:
57
+ **kwargs:
58
+
59
+ Returns:
60
+
61
+ """
62
+ pass
63
+
64
+ @abstractmethod
65
+ def calc_energy(self, x) -> th.Tensor:
66
+ """
67
+ The method that calculates the energy of given x.
68
+ One may use input args/kwargs in __init__
69
+ Args:
70
+ x: input variable
71
+
72
+ Returns: energy
73
+
74
+ """
75
+ pass
76
+
77
+ @abstractmethod
78
+ def calc_forces(self, x) -> th.Tensor:
79
+ """
80
+ The method that calculates the forces of given x.
81
+ One may use input args/kwargs in __init__
82
+ Args:
83
+ x: input variable
84
+
85
+ Returns: forces
86
+
87
+ """
88
+ pass
89
+
90
+ def __call__(self, x):
91
+ with th.no_grad():
92
+ ener = th.as_tensor(self.calc_energy(x), device=self.device)
93
+ forc = th.as_tensor(self.calc_forces(x), device=self.device)
94
+ return {'energy': ener, 'forces': forc}
95
+
96
+
97
+ class StandardInput(ABC):
98
+ """
99
+ An abstract container as the standard input of advanced API `api`.
100
+ It is fully compatible with `torch-geometric.data.Batch` object.
101
+ Following properties with corresponding type are standard and may require by BUCToolkit:
102
+ _ATTR_TYPE = {
103
+ 'idx': '<U128', # optional, the list of sample names to log out
104
+
105
+ 'batch': '<i8', # shape (N, ), the sample sizes in a batch
106
+
107
+ 'cell': '<f4', # shape (N, 3, 3), cell vectors. N is the batch size
108
+
109
+ 'pos': '<f4', # shape (\sum_i n_atom_i, n_dim), batched structure coordinates
110
+
111
+ 'mask': '|i1', # mask of fixed atoms with the same shape as `pos`. 0 is for fixed and 1 is for free
112
+
113
+ 'atomic_numbers': '<i4', # shape (\sum_i n_atom_i, ), tensor of batched atomic numbers.
114
+
115
+ 'x_diff': '<f4', # optional, initial displacement direction for Dimer, etc.
116
+
117
+ 'velocity': '<f4', # optional, initial velocity for MD.
118
+ }
119
+
120
+ where '<' is for Little-endian order, 'i' is for integer, 'f' is for float, and the last number is the bytes of single element.
121
+ For example, `'pos': '<f4'` means each element of `pos` is 4-bytes float, i.e., float32 or single precision float.
122
+
123
+ It has properties that can be inquired by follow methods as the input arg `data`:
124
+ def get_batch_size(data):
125
+ # total batch size
126
+ return len(data)
127
+
128
+ def get_cell_vec(data):
129
+ # `batch_size` cell vectors stacked at the 1st dim.
130
+ return data.cell.numpy(force=True)
131
+
132
+ def get_atomic_number(data):
133
+ # `batch_size` atomic numbers tensor(int64) concatenated at the 1st dim.
134
+ return data.atomic_numbers.unsqueeze(0)
135
+
136
+ def get_indx(data):
137
+ # Python list object with `batch_size` elements of each sample's name.
138
+ # each name must have less than 128 bytes.
139
+ _indx: Dict = getattr(data, 'idx', None)
140
+ return _indx
141
+
142
+ def get_pos(data):
143
+ # Atomic coordinates tensor in dtype float32 concatenated at the 1st dim.
144
+ return data.pos.unsqueeze(0)
145
+
146
+ def get_fixed_mask(data):
147
+ # the same shape as `pos` with dtype int8. Exactly, only 0, 1.
148
+ # Optional. default is all ones.
149
+ mask = getattr(data, 'fixed', None)
150
+ if mask is not None:
151
+ mask = mask.unsqueeze(0)
152
+ return mask
153
+
154
+ def get_batch_indx(data):
155
+ # batch_indices in the form of 1d int64 th.Tensor [0, 0, 0, ..., 1, 1, ..., n]
156
+ # where the same number means the indexed data of the same sample.
157
+ return [len(dat.pos) for dat in data.to_data_list()] # or can directly store this attr and return `data.batch`
158
+
159
+ def get_init_dX(data):
160
+ # used for Dimer & other algo. requiring finite difference. Have the same shape & dtype as `pos`
161
+ # Optional.
162
+ return getattr(data, self.x_diff_attr, None)
163
+
164
+ def get_init_veloc(data):
165
+ # used for MD. The initial velocities that have the same shape & dtype as `pos`
166
+ # Optional.
167
+ veloc = getattr(data, 'velocity', None)
168
+ if veloc is not None:
169
+ veloc = veloc.unsqueeze(0)
170
+ return veloc
171
+
172
+ They are fully compatible with `torch_geometric.data.batch` object.
173
+ """
174
+ _ATTR_TYPE = {
175
+ 'idx': '<U128',
176
+ 'batch': '<i8',
177
+ 'cell': '<f4',
178
+ 'pos': '<f4',
179
+ 'mask': '|i1',
180
+ 'atomic_numbers': '<i4',
181
+ 'x_diff': '<f4',
182
+ 'velocity': '<f4',
183
+ }
184
+
185
+ def __init__(
186
+ self,
187
+ batch: th.Tensor,
188
+ cell: th.Tensor,
189
+ atomic_numbers: th.Tensor,
190
+ pos: th.Tensor,
191
+ idx: Optional[List[str]] = None,
192
+ fixed: Optional[th.Tensor] = None,
193
+ velocity: Optional[th.Tensor] = None,
194
+ x_diff: Optional[th.Tensor] = None,
195
+ **kwargs
196
+ ):
197
+ self._batch = batch
198
+ self._cell = cell
199
+ self._atomic_numbers = atomic_numbers
200
+ self._pos = pos
201
+ self.idx = idx
202
+ self.fixed = fixed
203
+ self.velocity = velocity
204
+ self.x_diff = x_diff
205
+ self.__dict__.update(kwargs)
206
+
207
+ # the following properties must be implemented.
208
+ @abstractmethod
209
+ def __len__(self) -> int:
210
+ """ return the sample number in one batch """
211
+ pass
212
+
213
+ @property
214
+ @abstractmethod
215
+ def batch(self) -> Optional[th.Tensor]:
216
+ """
217
+ batch indices tensor in the form of 1-D int64 th.Tensor [0, 0, 0, ..., 1, 1, ..., n]
218
+ where the same number means the indexed data of the same sample.
219
+ """
220
+ pass
221
+
222
+ @batch.setter
223
+ @abstractmethod
224
+ def batch(self, value: Optional[th.Tensor]) -> None:
225
+ pass
226
+
227
+ @property
228
+ @abstractmethod
229
+ def pos(self) -> th.Tensor:
230
+ """
231
+ Atomic coordinates tensor in dtype float32 concatenated at the 1st dim. shape: (sum_i^{n_batch} n_i, 3).
232
+ """
233
+ pass
234
+
235
+ @pos.setter
236
+ @abstractmethod
237
+ def pos(self, value: th.Tensor) -> None:
238
+ pass
239
+
240
+ @property
241
+ @abstractmethod
242
+ def cell(self) -> th.Tensor:
243
+ """
244
+ cell tensor in dtype float32 concatenated at the 1st dim. shape: (n_batch, 3, 3)
245
+ """
246
+ pass
247
+
248
+ @cell.setter
249
+ @abstractmethod
250
+ def cell(self, value: th.Tensor) -> None:
251
+ pass
252
+
253
+ @property
254
+ @abstractmethod
255
+ def atomic_numbers(self) -> th.Tensor:
256
+ """
257
+ Atomic number tensor in dtype int64 concatenated at the 1st dim. shape: (sum_i^{n_batch} n_i, ).
258
+ """
259
+ pass
260
+
261
+ @atomic_numbers.setter
262
+ @abstractmethod
263
+ def atomic_numbers(self, value: th.Tensor) -> None:
264
+ pass
265
+
266
+ @abstractmethod
267
+ def to_data_list(self) -> List[Any]:
268
+ """
269
+ Split batched data into the List of each sample.
270
+ Similar to torch_geometric.data.Batch.
271
+ Optional to override.
272
+ """
273
+ raise NotImplementedError(f'Please implement `self.to_data_list()` by overriding in the subclass.')
274
+
275
+ def to(self, target: th.dtype | th.device | str) -> None:
276
+ """
277
+ Move data of self to the given device or dtype.
278
+ Args:
279
+ target: the device or dtype to which to move the data.
280
+
281
+ """
282
+ # normal attr
283
+ for k, dat in self.__dict__.items():
284
+ if k.startswith('__') and k.endswith('__'):
285
+ continue
286
+ elif isinstance(dat, th.Tensor):
287
+ self.__setattr__(k, dat.to(target))
288
+
289
+ # properties
290
+ for k in self._ATTR_TYPE.keys():
291
+ _x = getattr(self, k)
292
+ if isinstance(_x, th.Tensor):
293
+ _x = _x.to(target)
294
+ try:
295
+ setattr(self, k, _x)
296
+ except AttributeError:
297
+ pass
298
+
299
+ def to_dict(self) -> Dict[str, Any]:
300
+ """
301
+ Convert self to the dict format.
302
+ Note that private and special attr (start with '_'/'__') would not put in.
303
+ Returns: Dict of attributes.
304
+ """
305
+ # normal attr
306
+ attr_dict = {k:dat for k, dat in self.__dict__.items() if not k.startswith('_')}
307
+ # properties
308
+ attr_dict.update({k: getattr(self, k) for k in self._ATTR_TYPE.keys() if not k.startswith('_')})
309
+
310
+ return attr_dict
311
+
312
+ class BatchData(StandardInput):
313
+ """
314
+ An example of `StandardInput` for Batched data.
315
+ """
316
+
317
+ def __init__(
318
+ self,
319
+ batch: th.Tensor,
320
+ cell: th.Tensor,
321
+ atomic_numbers: th.Tensor,
322
+ pos: th.Tensor,
323
+ idx: Optional[List[str]] = None,
324
+ fixed: Optional[th.Tensor] = None,
325
+ velocity: Optional[th.Tensor] = None,
326
+ x_diff: Optional[th.Tensor] = None,
327
+ **kwargs
328
+ ):
329
+ super(BatchData, self).__init__(
330
+ batch=batch,
331
+ cell=cell,
332
+ atomic_numbers=atomic_numbers,
333
+ pos=pos,
334
+ idx=idx,
335
+ fixed=fixed,
336
+ velocity=velocity,
337
+ x_diff=x_diff,
338
+ **kwargs
339
+ )
340
+
341
+ def __len__(self) -> int:
342
+ """ return the sample number in one batch """
343
+ return len(self._batch)
344
+
345
+ @property
346
+ def batch(self) -> th.Tensor:
347
+ """
348
+ batch indices tensor in the form of 1-D int64 th.Tensor [0, 0, 0, ..., 1, 1, ..., n]
349
+ where the same number means the indexed data of the same sample.
350
+ """
351
+ return self._batch
352
+
353
+ @batch.setter
354
+ def batch(self, value: th.Tensor) -> None:
355
+ if not isinstance(value, th.Tensor):
356
+ raise TypeError(f'Batch must be of type {th.Tensor}, not {type(value)}.')
357
+ elif value.dim() != 1:
358
+ raise ValueError(f'Batch must be a 1-D Tensor, but got {value.dim()}-D.')
359
+ elif th.sum(value) != self.pos.shape[0]:
360
+ raise ValueError(f'Atoms number given by `value` and `self.pos` do not match.')
361
+
362
+ self._batch = value.to(th.int64)
363
+
364
+ @property
365
+ def pos(self) -> th.Tensor:
366
+ """
367
+ Atomic coordinates tensor in dtype float32 concatenated at the 1st dim. shape: (sum_i^{n_batch} n_i, 3).
368
+ """
369
+ return self._pos
370
+
371
+ @pos.setter
372
+ def pos(self, value: th.Tensor) -> None:
373
+ if not isinstance(value, th.Tensor):
374
+ raise TypeError(f'`pos` must be of type {th.Tensor}, not {type(value)}.')
375
+ self._pos = value
376
+
377
+ @property
378
+ def cell(self) -> th.Tensor:
379
+ """
380
+ cell tensor in dtype float32 concatenated at the 1st dim. shape: (n_batch, 3, 3)
381
+ """
382
+ return self._cell
383
+
384
+ @cell.setter
385
+ def cell(self, value: th.Tensor) -> None:
386
+ if not isinstance(value, th.Tensor):
387
+ raise TypeError(f'`cell` must be of type {th.Tensor}, not {type(value)}.')
388
+ elif value.dim() != 3:
389
+ raise ValueError(f'`cell` must be a 3-D tensor, but got {value.dim()}-D.')
390
+ elif value.shape != (len(self._batch), 3, 3):
391
+ raise ValueError(f'batch size given by `value` and `self.batch` do not match.')
392
+ self._cell = value
393
+
394
+ @property
395
+ def atomic_numbers(self) -> th.Tensor:
396
+ """
397
+ Atomic number tensor in dtype int64 concatenated at the 1st dim. shape: (sum_i^{n_batch} n_i, ).
398
+ """
399
+ return self._atomic_numbers
400
+
401
+ @atomic_numbers.setter
402
+ def atomic_numbers(self, value: th.Tensor) -> None:
403
+ if not isinstance(value, th.Tensor):
404
+ raise TypeError(f"`atomic_numbers` must be of type {th.Tensor}, not {type(value)}.")
405
+ elif value.dim() != 1:
406
+ raise ValueError(f"`atomic_numbers` must be a 1-D tensor, but got {value.dim()}-D.")
407
+ elif len(value) != self.pos.shape[0]:
408
+ raise ValueError(f"Atomic number given by `value` and `self.pos` do not match.")
409
+ self._atomic_numbers = value.to(th.int32)
410
+
411
+ def to_data_list(self) -> List[Any]:
412
+ """
413
+ Split batched data into the List of each sample.
414
+ Similar to torch_geometric.data.Batch.
415
+ Optional to override.
416
+ """
417
+ raise NotImplementedError(f'Please implement `self.to_data_list()` by overriding in the subclass.')
BUCToolkit/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2024-2026.3.27, BUCToolkit.
2
+ # Authors: Pu Pengxin, Song Xin
3
+ # Version: 1.0b
4
+ # File: __init__.py
5
+ # Environment: Python 3.12
6
+
7
+ from BUCToolkit.BatchStructures.BatchStructuresBase import BatchStructures as Structures
8
+ from BUCToolkit import utils
9
+ from BUCToolkit.utils._Element_info import TRANSITION_METALS, TRANSITION_P_METALS, NOBLE_METALS, NONRADIOACTIVE_METALS
10
+ from BUCToolkit.Preprocessing import load_files
11
+ from BUCToolkit.Preprocessing.load_files import load_from_structures as load
12
+ from BUCToolkit.Preprocessing import preprocessing
13
+ from BUCToolkit import io
14
+ from BUCToolkit import api
15
+ from BUCToolkit import BatchMC, BatchMD, BatchOptim, BatchStructures
16
+
17
+ __all__ = [
18
+ 'Structures',
19
+ 'load',
20
+ 'load_files',
21
+ 'preprocessing',
22
+ 'TRANSITION_METALS',
23
+ 'TRANSITION_P_METALS',
24
+ 'NOBLE_METALS',
25
+ 'NONRADIOACTIVE_METALS',
26
+ 'utils',
27
+ 'io',
28
+ 'api',
29
+ 'BatchMC',
30
+ 'BatchMD',
31
+ 'BatchOptim',
32
+ 'BatchStructures'
33
+ ]
BUCToolkit/_version.py ADDED
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2026.3.4, BUCToolkit.
2
+ # Authors: Pu Pengxin, Song Xin
3
+ # Version: 0.9a
4
+ # File: _version.py
5
+ # Environment: Python 3.12
6
+
7
+ __version__ = '1.0'