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,205 @@
1
+ """
2
+ Quasi-Newton Algorithm for optimization.
3
+ """
4
+ # Copyright (c) 2024-2025.7.4, BUCToolkit.
5
+ # Authors: Pu Pengxin, Song Xin
6
+ # Version: 0.9a
7
+ # File: QN.py
8
+ # Environment: Python 3.12
9
+
10
+ from typing import Literal
11
+ import os
12
+
13
+ import torch as th
14
+
15
+ from BUCToolkit.BatchOptim._BaseOpt import _BaseOpt
16
+
17
+ os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'
18
+
19
+
20
+ class QN(_BaseOpt):
21
+ """
22
+ Quasi-Newton Algo.
23
+
24
+ Args:
25
+ iter_scheme: Literal['BFGS', 'Newton'],
26
+ E_threshold: float = 1e-3,
27
+ F_threshold: float = 0.05,
28
+ maxiter: int = 100,
29
+ linesearch: Literal['Backtrack', 'Wolfe', 'NWolfe', '2PT', '3PT', 'Golden', 'Newton', 'None'] = 'Backtrack',
30
+ linesearch_maxiter: int = 10,
31
+ linesearch_thres: float = 0.02,
32
+ linesearch_factor: float = 0.6,
33
+ steplength: float = 0.5,
34
+ use_bb: whether to use Barzilai-Borwein steplength (BB1 or long BB) as initial steplength instead of fixed one.
35
+ external_Hessian: manually input Hessian matrix as initial guess.
36
+ device: str | th.device = 'cpu',
37
+ verbose: int = 2
38
+
39
+ Methods:
40
+ run: launch the optimization.
41
+ set_update_batch: setting the method to update the taget function when variables change.
42
+ """
43
+ def __init__(
44
+ self,
45
+ iter_scheme: Literal['BFGS', ],
46
+ E_threshold: float = 1e-3,
47
+ F_threshold: float = 0.05,
48
+ maxiter: int = 100,
49
+ linesearch: Literal['Backtrack', 'B', 'Wolfe', 'W', 'MT', 'EXACT', 'None', 'N'] = 'Backtrack',
50
+ linesearch_maxiter: int = 10,
51
+ linesearch_thres: float = 0.02,
52
+ linesearch_factor: float = 0.6,
53
+ steplength: float = 0.5,
54
+ use_bb: bool = True,
55
+ external_Hessian: th.Tensor|None = None,
56
+ output_file: str | None = None,
57
+ device: str | th.device = 'cpu',
58
+ verbose: int = 2
59
+ ):
60
+ super().__init__(
61
+ iter_scheme,
62
+ E_threshold,
63
+ F_threshold,
64
+ maxiter,
65
+ linesearch,
66
+ linesearch_maxiter,
67
+ linesearch_thres,
68
+ linesearch_factor,
69
+ steplength,
70
+ use_bb,
71
+ output_file,
72
+ device,
73
+ verbose
74
+ )
75
+ self.external_Hessian = external_Hessian
76
+
77
+ def initialize_algo_param(self):
78
+ """
79
+ Override this method to initialize attribute variables for self._update_direction.
80
+
81
+ Returns: None
82
+ """
83
+ if self.external_Hessian is None:
84
+ # Initial quasi-inverse Hessian Matrix (n_batch, n_atom*n_dim, n_atom*n_dim)
85
+ self.H_inv = (th.eye(self.n_atom * self.n_dim, device=self.device).unsqueeze(0)).expand(self.n_batch, -1, -1)
86
+ self.H_inv = self.H_inv.reshape(self.n_batch, self.n_atom, self.n_dim, self.n_atom, self.n_dim).contiguous()
87
+ elif self.external_Hessian.shape == (self.n_batch, self.n_atom * self.n_dim, self.n_atom * self.n_dim):
88
+ # check positive definite
89
+ eigval, eigvec = th.linalg.eigh(self.external_Hessian)
90
+ if th.any(eigval < 0.):
91
+ self.logger.warning('Some external_Hessian are not positive definite. Their negative eigenvalues would be replaced by 1.')
92
+ eigval = th.where(eigval < 0., 1., eigval)
93
+ _external_Hessian = eigvec@th.diag_embed(eigval, 0, -2, -1)@eigvec.mH
94
+ else:
95
+ _external_Hessian = self.external_Hessian
96
+
97
+ self.H_inv = th.linalg.inv(_external_Hessian).reshape(self.n_batch, self.n_atom, self.n_dim, self.n_atom, self.n_dim).contiguous()
98
+ else:
99
+ self.logger.warning(f'Expected external Hessian has a shape of {(self.n_batch, self.n_atom * self.n_dim, self.n_atom * self.n_dim)}, '
100
+ f'but got {self.external_Hessian.shape}. Thus identity matrix would use instead.')
101
+ self.H_inv = (th.eye(self.n_atom * self.n_dim, device=self.device).unsqueeze(0)).expand(self.n_batch, -1, -1)
102
+ self.H_inv = self.H_inv.reshape(self.n_batch, self.n_atom, self.n_dim, self.n_atom, self.n_dim).contiguous()
103
+ # prepared identity matrix
104
+ self.Ident = (th.eye(self.n_atom * self.n_dim, device=self.device).unsqueeze(0)).expand(self.n_batch, -1, -1)
105
+ self.Ident = self.Ident.reshape(self.n_batch, self.n_atom, self.n_dim, self.n_atom, self.n_dim).contiguous()
106
+
107
+ def _update_direction(
108
+ self,
109
+ g: th.Tensor,
110
+ g_old: th.Tensor,
111
+ p: th.Tensor,
112
+ X: th.Tensor,
113
+ batch_scatter_indices: th.Tensor | None,
114
+ ) -> th.Tensor:
115
+ """
116
+ Override this method to implement X update algorithm.
117
+ Args:
118
+ g: (n_batch, n_atom*3, 1), the gradient of X at this step
119
+ g_old: (n_batch, n_atom*3, 1), the gradient of X at last step
120
+ p: (n_batch, n_atom*3, 1), the update direction of X at last step
121
+
122
+ Returns:
123
+ p: th.Tensor, the new update direction of X.
124
+ """
125
+ _shape = g.shape
126
+ if self.is_concat_X:
127
+ H_inv_now = self.H_inv[:, self.select_mask][..., self.select_mask, :]
128
+ else:
129
+ H_inv_now = self.H_inv[self.select_mask]
130
+ # QN scheme
131
+ if self.iterform == 'BFGS':
132
+ p = - th.einsum('ijklm, ilm -> ijk', H_inv_now, g) # (n_batch, n_atom*3, n_atom*3) @ (n_batch, n_atom*3, 1)
133
+ return p
134
+
135
+ else:
136
+ raise NotImplementedError
137
+
138
+ def _update_algo_param(
139
+ self,
140
+ select_mask: th.Tensor,
141
+ select_mask_short,
142
+ batch_scatter_indices,
143
+ g: th.Tensor,
144
+ g_old: th.Tensor,
145
+ p: th.Tensor,
146
+ displace: th.Tensor
147
+ ) -> None:
148
+ """
149
+ Override this method to update the parameters of X update algorithm i.e., self.iterform.
150
+
151
+ Returns: None
152
+ """
153
+ #g = g.flatten(-2, -1).unsqueeze(-1).contiguous()
154
+ #g_old = g_old.flatten(-2, -1).unsqueeze(-1).contiguous()
155
+ #displace = displace.flatten(-2, -1).unsqueeze(-1).contiguous()
156
+
157
+ if self.is_concat_X:
158
+ H_inv_now = self.H_inv[:, select_mask][..., select_mask, :]
159
+ Ident_now = self.Ident[:, select_mask][..., select_mask, :]
160
+ else:
161
+ H_inv_now = self.H_inv[select_mask]
162
+ Ident_now = self.Ident[select_mask]
163
+
164
+ # update H_inv
165
+ g_go = g - g_old
166
+ # check & ensure the positive determination of BFGS Matrix
167
+ ss = th.sum(displace**2, dim=(-2, -1), keepdim=True)
168
+ sy = th.sum(displace * g_go, dim=(-2, -1), keepdim=True)
169
+ non_pos_deter_mask = (sy < 0.2 * ss)
170
+ # damped BFGS
171
+ if th.any(non_pos_deter_mask):
172
+ phi = (0.2 * ss - sy)/ss
173
+ phi = th.where(phi > 0., phi, 0.)
174
+ g_go = th.where(non_pos_deter_mask, g_go + phi * displace, g_go)
175
+ sy = th.sum(displace * g_go, dim=(-2, -1), keepdim=True)
176
+ gamma = 1 / (sy + 1e-20) # (n_batch, n_atom, 3) * (n_batch, n_atom, 3) -sum-> (n_batch, 1, 1), 1e-20 to avoid 1/0
177
+ gamma = gamma.reshape(-1, 1, 1, 1, 1)
178
+ # BFGS Scheme:
179
+ # ((n_batch, n_atom*n_dim, n_atom*n_dim) - (n_batch, 1, 1) * (n_batch, n_atom*n_dim, 1)@(n_batch, 1, n_atom*n_dim)) -> (B, AD, AD)
180
+ # (B, AD, AD) @ (B, AD, AD)
181
+ # ((B, A, D, A, D) - (B, 1, 1, 1, 1) * (B, A, D, A, D)) @ (B, A, D, A, D) -(-2, -1)-> (B, A, D)
182
+
183
+ '''self.H_inv = (
184
+ (self.Ident - gamma * displace @ g_go.mT) @ H_inv_now @ (self.Ident - gamma * g_go @ displace.mT) + gamma * displace @ displace.mT
185
+ )'''
186
+ H_inv_now = th.einsum(
187
+ 'mijkl, mklqr -> mijqr',
188
+ th.einsum(
189
+ 'mijkl, mklqr -> mijqr',
190
+ (Ident_now - gamma * th.einsum('ijk, ilm-> ijklm', displace, g_go)),
191
+ H_inv_now
192
+ ),
193
+ (Ident_now - gamma * th.einsum('ijk, ilm-> ijklm', g_go, displace))
194
+ ) + gamma * th.einsum('ijk, ilm-> ijklm', displace, displace)
195
+
196
+ if self.is_concat_X:
197
+ tmp = self.H_inv[:, select_mask]
198
+ tmp[..., select_mask, :] = H_inv_now
199
+ self.H_inv[:, select_mask] = tmp
200
+ else:
201
+ self.H_inv[select_mask] = H_inv_now
202
+
203
+ pass
204
+
205
+
@@ -0,0 +1,17 @@
1
+ r"""
2
+ Batched structures optimization by pytorch models or functions.
3
+
4
+ 2024/6/24 PPX
5
+ """
6
+
7
+ # Copyright (c) 2024-2025.7.4, BUCToolkit.
8
+ # Authors: Pu Pengxin, Song Xin
9
+ # Version: 0.9a
10
+ # File: __init__.py
11
+ # Environment: Python 3.12
12
+
13
+ from .CG import CG
14
+ from .QN import QN
15
+ from .FIRE import FIRE
16
+
17
+ __all__ = ['CG', 'QN', 'FIRE']