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,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']
|