MultiOptPy 1.20.2__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 (246) hide show
  1. multioptpy/Calculator/__init__.py +0 -0
  2. multioptpy/Calculator/ase_calculation_tools.py +424 -0
  3. multioptpy/Calculator/ase_tools/__init__.py +0 -0
  4. multioptpy/Calculator/ase_tools/fairchem.py +28 -0
  5. multioptpy/Calculator/ase_tools/gamess.py +19 -0
  6. multioptpy/Calculator/ase_tools/gaussian.py +165 -0
  7. multioptpy/Calculator/ase_tools/mace.py +28 -0
  8. multioptpy/Calculator/ase_tools/mopac.py +19 -0
  9. multioptpy/Calculator/ase_tools/nwchem.py +31 -0
  10. multioptpy/Calculator/ase_tools/orca.py +22 -0
  11. multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
  12. multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
  13. multioptpy/Calculator/emt_calculation_tools.py +458 -0
  14. multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
  15. multioptpy/Calculator/lj_calculation_tools.py +314 -0
  16. multioptpy/Calculator/psi4_calculation_tools.py +334 -0
  17. multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
  18. multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
  19. multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
  20. multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
  21. multioptpy/Calculator/tblite_calculation_tools.py +352 -0
  22. multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
  23. multioptpy/Constraint/__init__.py +0 -0
  24. multioptpy/Constraint/constraint_condition.py +834 -0
  25. multioptpy/Coordinate/__init__.py +0 -0
  26. multioptpy/Coordinate/polar_coordinate.py +199 -0
  27. multioptpy/Coordinate/redundant_coordinate.py +638 -0
  28. multioptpy/IRC/__init__.py +0 -0
  29. multioptpy/IRC/converge_criteria.py +28 -0
  30. multioptpy/IRC/dvv.py +544 -0
  31. multioptpy/IRC/euler.py +439 -0
  32. multioptpy/IRC/hpc.py +564 -0
  33. multioptpy/IRC/lqa.py +540 -0
  34. multioptpy/IRC/modekill.py +662 -0
  35. multioptpy/IRC/rk4.py +579 -0
  36. multioptpy/Interpolation/__init__.py +0 -0
  37. multioptpy/Interpolation/adaptive_interpolation.py +283 -0
  38. multioptpy/Interpolation/binomial_interpolation.py +179 -0
  39. multioptpy/Interpolation/geodesic_interpolation.py +785 -0
  40. multioptpy/Interpolation/interpolation.py +156 -0
  41. multioptpy/Interpolation/linear_interpolation.py +473 -0
  42. multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
  43. multioptpy/Interpolation/spline_interpolation.py +353 -0
  44. multioptpy/MD/__init__.py +0 -0
  45. multioptpy/MD/thermostat.py +185 -0
  46. multioptpy/MEP/__init__.py +0 -0
  47. multioptpy/MEP/pathopt_bneb_force.py +443 -0
  48. multioptpy/MEP/pathopt_dmf_force.py +448 -0
  49. multioptpy/MEP/pathopt_dneb_force.py +130 -0
  50. multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
  51. multioptpy/MEP/pathopt_gpneb_force.py +512 -0
  52. multioptpy/MEP/pathopt_lup_force.py +113 -0
  53. multioptpy/MEP/pathopt_neb_force.py +225 -0
  54. multioptpy/MEP/pathopt_nesb_force.py +205 -0
  55. multioptpy/MEP/pathopt_om_force.py +153 -0
  56. multioptpy/MEP/pathopt_qsm_force.py +174 -0
  57. multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
  58. multioptpy/ModelFunction/__init__.py +7 -0
  59. multioptpy/ModelFunction/avoiding_model_function.py +29 -0
  60. multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
  61. multioptpy/ModelFunction/conical_model_function.py +26 -0
  62. multioptpy/ModelFunction/opt_meci.py +50 -0
  63. multioptpy/ModelFunction/opt_mesx.py +47 -0
  64. multioptpy/ModelFunction/opt_mesx_2.py +49 -0
  65. multioptpy/ModelFunction/seam_model_function.py +27 -0
  66. multioptpy/ModelHessian/__init__.py +0 -0
  67. multioptpy/ModelHessian/approx_hessian.py +147 -0
  68. multioptpy/ModelHessian/calc_params.py +227 -0
  69. multioptpy/ModelHessian/fischer.py +236 -0
  70. multioptpy/ModelHessian/fischerd3.py +360 -0
  71. multioptpy/ModelHessian/fischerd4.py +398 -0
  72. multioptpy/ModelHessian/gfn0xtb.py +633 -0
  73. multioptpy/ModelHessian/gfnff.py +709 -0
  74. multioptpy/ModelHessian/lindh.py +165 -0
  75. multioptpy/ModelHessian/lindh2007d2.py +707 -0
  76. multioptpy/ModelHessian/lindh2007d3.py +822 -0
  77. multioptpy/ModelHessian/lindh2007d4.py +1030 -0
  78. multioptpy/ModelHessian/morse.py +106 -0
  79. multioptpy/ModelHessian/schlegel.py +144 -0
  80. multioptpy/ModelHessian/schlegeld3.py +322 -0
  81. multioptpy/ModelHessian/schlegeld4.py +559 -0
  82. multioptpy/ModelHessian/shortrange.py +346 -0
  83. multioptpy/ModelHessian/swartd2.py +496 -0
  84. multioptpy/ModelHessian/swartd3.py +706 -0
  85. multioptpy/ModelHessian/swartd4.py +918 -0
  86. multioptpy/ModelHessian/tshess.py +40 -0
  87. multioptpy/Optimizer/QHAdam.py +61 -0
  88. multioptpy/Optimizer/__init__.py +0 -0
  89. multioptpy/Optimizer/abc_fire.py +83 -0
  90. multioptpy/Optimizer/adabelief.py +58 -0
  91. multioptpy/Optimizer/adabound.py +68 -0
  92. multioptpy/Optimizer/adadelta.py +65 -0
  93. multioptpy/Optimizer/adaderivative.py +56 -0
  94. multioptpy/Optimizer/adadiff.py +68 -0
  95. multioptpy/Optimizer/adafactor.py +70 -0
  96. multioptpy/Optimizer/adam.py +65 -0
  97. multioptpy/Optimizer/adamax.py +62 -0
  98. multioptpy/Optimizer/adamod.py +83 -0
  99. multioptpy/Optimizer/adamw.py +65 -0
  100. multioptpy/Optimizer/adiis.py +523 -0
  101. multioptpy/Optimizer/afire_neb.py +282 -0
  102. multioptpy/Optimizer/block_hessian_update.py +709 -0
  103. multioptpy/Optimizer/c2diis.py +491 -0
  104. multioptpy/Optimizer/component_wise_scaling.py +405 -0
  105. multioptpy/Optimizer/conjugate_gradient.py +82 -0
  106. multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
  107. multioptpy/Optimizer/coordinate_locking.py +405 -0
  108. multioptpy/Optimizer/dic_rsirfo.py +1015 -0
  109. multioptpy/Optimizer/ediis.py +417 -0
  110. multioptpy/Optimizer/eve.py +76 -0
  111. multioptpy/Optimizer/fastadabelief.py +61 -0
  112. multioptpy/Optimizer/fire.py +77 -0
  113. multioptpy/Optimizer/fire2.py +249 -0
  114. multioptpy/Optimizer/fire_neb.py +92 -0
  115. multioptpy/Optimizer/gan_step.py +486 -0
  116. multioptpy/Optimizer/gdiis.py +609 -0
  117. multioptpy/Optimizer/gediis.py +203 -0
  118. multioptpy/Optimizer/geodesic_step.py +433 -0
  119. multioptpy/Optimizer/gpmin.py +633 -0
  120. multioptpy/Optimizer/gpr_step.py +364 -0
  121. multioptpy/Optimizer/gradientdescent.py +78 -0
  122. multioptpy/Optimizer/gradientdescent_neb.py +52 -0
  123. multioptpy/Optimizer/hessian_update.py +433 -0
  124. multioptpy/Optimizer/hybrid_rfo.py +998 -0
  125. multioptpy/Optimizer/kdiis.py +625 -0
  126. multioptpy/Optimizer/lars.py +21 -0
  127. multioptpy/Optimizer/lbfgs.py +253 -0
  128. multioptpy/Optimizer/lbfgs_neb.py +355 -0
  129. multioptpy/Optimizer/linesearch.py +236 -0
  130. multioptpy/Optimizer/lookahead.py +40 -0
  131. multioptpy/Optimizer/nadam.py +64 -0
  132. multioptpy/Optimizer/newton.py +200 -0
  133. multioptpy/Optimizer/prodigy.py +70 -0
  134. multioptpy/Optimizer/purtubation.py +16 -0
  135. multioptpy/Optimizer/quickmin_neb.py +245 -0
  136. multioptpy/Optimizer/radam.py +75 -0
  137. multioptpy/Optimizer/rfo_neb.py +302 -0
  138. multioptpy/Optimizer/ric_rfo.py +842 -0
  139. multioptpy/Optimizer/rl_step.py +627 -0
  140. multioptpy/Optimizer/rmspropgrave.py +65 -0
  141. multioptpy/Optimizer/rsirfo.py +1647 -0
  142. multioptpy/Optimizer/rsprfo.py +1056 -0
  143. multioptpy/Optimizer/sadam.py +60 -0
  144. multioptpy/Optimizer/samsgrad.py +63 -0
  145. multioptpy/Optimizer/tr_lbfgs.py +678 -0
  146. multioptpy/Optimizer/trim.py +273 -0
  147. multioptpy/Optimizer/trust_radius.py +207 -0
  148. multioptpy/Optimizer/trust_radius_neb.py +121 -0
  149. multioptpy/Optimizer/yogi.py +60 -0
  150. multioptpy/OtherMethod/__init__.py +0 -0
  151. multioptpy/OtherMethod/addf.py +1150 -0
  152. multioptpy/OtherMethod/dimer.py +895 -0
  153. multioptpy/OtherMethod/elastic_image_pair.py +629 -0
  154. multioptpy/OtherMethod/modelfunction.py +456 -0
  155. multioptpy/OtherMethod/newton_traj.py +454 -0
  156. multioptpy/OtherMethod/twopshs.py +1095 -0
  157. multioptpy/PESAnalyzer/__init__.py +0 -0
  158. multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
  159. multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
  160. multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
  161. multioptpy/PESAnalyzer/pca_analysis.py +314 -0
  162. multioptpy/Parameters/__init__.py +0 -0
  163. multioptpy/Parameters/atomic_mass.py +20 -0
  164. multioptpy/Parameters/atomic_number.py +22 -0
  165. multioptpy/Parameters/covalent_radii.py +44 -0
  166. multioptpy/Parameters/d2.py +61 -0
  167. multioptpy/Parameters/d3.py +63 -0
  168. multioptpy/Parameters/d4.py +103 -0
  169. multioptpy/Parameters/dreiding.py +34 -0
  170. multioptpy/Parameters/gfn0xtb_param.py +137 -0
  171. multioptpy/Parameters/gfnff_param.py +315 -0
  172. multioptpy/Parameters/gnb.py +104 -0
  173. multioptpy/Parameters/parameter.py +22 -0
  174. multioptpy/Parameters/uff.py +72 -0
  175. multioptpy/Parameters/unit_values.py +20 -0
  176. multioptpy/Potential/AFIR_potential.py +55 -0
  177. multioptpy/Potential/LJ_repulsive_potential.py +345 -0
  178. multioptpy/Potential/__init__.py +0 -0
  179. multioptpy/Potential/anharmonic_keep_potential.py +28 -0
  180. multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
  181. multioptpy/Potential/electrostatic_potential.py +69 -0
  182. multioptpy/Potential/flux_potential.py +30 -0
  183. multioptpy/Potential/gaussian_potential.py +101 -0
  184. multioptpy/Potential/idpp.py +516 -0
  185. multioptpy/Potential/keep_angle_potential.py +146 -0
  186. multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
  187. multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
  188. multioptpy/Potential/keep_potential.py +99 -0
  189. multioptpy/Potential/mechano_force_potential.py +74 -0
  190. multioptpy/Potential/nanoreactor_potential.py +52 -0
  191. multioptpy/Potential/potential.py +896 -0
  192. multioptpy/Potential/spacer_model_potential.py +221 -0
  193. multioptpy/Potential/switching_potential.py +258 -0
  194. multioptpy/Potential/universal_potential.py +34 -0
  195. multioptpy/Potential/value_range_potential.py +36 -0
  196. multioptpy/Potential/void_point_potential.py +25 -0
  197. multioptpy/SQM/__init__.py +0 -0
  198. multioptpy/SQM/sqm1/__init__.py +0 -0
  199. multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
  200. multioptpy/SQM/sqm2/__init__.py +0 -0
  201. multioptpy/SQM/sqm2/calc_tools.py +95 -0
  202. multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
  203. multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
  204. multioptpy/SQM/sqm2/sqm2_core.py +303 -0
  205. multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
  206. multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
  207. multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
  208. multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
  209. multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
  210. multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
  211. multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
  212. multioptpy/Thermo/__init__.py +0 -0
  213. multioptpy/Thermo/normal_mode_analyzer.py +865 -0
  214. multioptpy/Utils/__init__.py +0 -0
  215. multioptpy/Utils/bond_connectivity.py +264 -0
  216. multioptpy/Utils/calc_tools.py +884 -0
  217. multioptpy/Utils/oniom.py +96 -0
  218. multioptpy/Utils/pbc.py +48 -0
  219. multioptpy/Utils/riemann_curvature.py +208 -0
  220. multioptpy/Utils/symmetry_analyzer.py +482 -0
  221. multioptpy/Visualization/__init__.py +0 -0
  222. multioptpy/Visualization/visualization.py +156 -0
  223. multioptpy/WFAnalyzer/MO_analysis.py +104 -0
  224. multioptpy/WFAnalyzer/__init__.py +0 -0
  225. multioptpy/Wrapper/__init__.py +0 -0
  226. multioptpy/Wrapper/autots.py +1239 -0
  227. multioptpy/Wrapper/ieip_wrapper.py +93 -0
  228. multioptpy/Wrapper/md_wrapper.py +92 -0
  229. multioptpy/Wrapper/neb_wrapper.py +94 -0
  230. multioptpy/Wrapper/optimize_wrapper.py +76 -0
  231. multioptpy/__init__.py +5 -0
  232. multioptpy/entrypoints.py +916 -0
  233. multioptpy/fileio.py +660 -0
  234. multioptpy/ieip.py +340 -0
  235. multioptpy/interface.py +1086 -0
  236. multioptpy/irc.py +529 -0
  237. multioptpy/moleculardynamics.py +432 -0
  238. multioptpy/neb.py +1267 -0
  239. multioptpy/optimization.py +1553 -0
  240. multioptpy/optimizer.py +709 -0
  241. multioptpy-1.20.2.dist-info/METADATA +438 -0
  242. multioptpy-1.20.2.dist-info/RECORD +246 -0
  243. multioptpy-1.20.2.dist-info/WHEEL +5 -0
  244. multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
  245. multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
  246. multioptpy-1.20.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,512 @@
1
+ import numpy as np
2
+ import copy
3
+ from scipy.optimize import minimize
4
+ from scipy.signal import argrelextrema
5
+ from multioptpy.Coordinate.redundant_coordinate import calc_int_grad_from_pBmat, calc_cart_grad_from_pBmat
6
+
7
+ def extremum_list_index(energy_list):
8
+ local_max_energy_list_index = argrelextrema(energy_list, np.greater)
9
+ inverse_energy_list = (-1)*energy_list
10
+ local_min_energy_list_index = argrelextrema(inverse_energy_list, np.greater)
11
+
12
+ local_max_energy_list_index = local_max_energy_list_index[0].tolist()
13
+ local_min_energy_list_index = local_min_energy_list_index[0].tolist()
14
+ local_max_energy_list_index.append(0)
15
+ local_min_energy_list_index.append(0)
16
+ local_max_energy_list_index.append(0)
17
+ local_min_energy_list_index.append(0)
18
+ return local_max_energy_list_index, local_min_energy_list_index
19
+
20
+ #########################
21
+ # Chunked RBF Kernel Utilities
22
+ #########################
23
+ def rbf_kernel_chunked(X1, X2, sigma_f, length_scale, chunk_size=1024):
24
+ """
25
+ Compute the RBF kernel matrix between X1 (N1, d) and X2 (N2, d) in chunks
26
+ to reduce memory usage.
27
+ Args:
28
+ X1: (N1, d) array
29
+ X2: (N2, d) array
30
+ sigma_f: scalar, kernel amplitude
31
+ length_scale: scalar, kernel length scale
32
+ chunk_size: int, number of X1 rows to process in each chunk
33
+ Returns:
34
+ (N1, N2) RBF kernel matrix
35
+ """
36
+ N1, d = X1.shape
37
+ N2 = X2.shape[0]
38
+ K = np.zeros((N1, N2), dtype=np.float64)
39
+
40
+ # Precompute norms for X2 to help with chunk-based distance calculations
41
+ X2_sq = np.sum(X2**2, axis=1).reshape(1, -1)
42
+
43
+ start = 0
44
+ while start < N1:
45
+ end = min(start + chunk_size, N1)
46
+ X1_chunk = X1[start:end]
47
+
48
+ # Compute squared distances for chunk
49
+ X1_sq = np.sum(X1_chunk**2, axis=1).reshape(-1, 1)
50
+ dist_sq = X1_sq + X2_sq - 2.0 * np.dot(X1_chunk, X2.T)
51
+
52
+ exponent = -0.5 * dist_sq / (length_scale**2)
53
+ # Clip the exponent to avoid overflow in exp. The upper bound 700 is conservative.
54
+ exponent_clipped = np.clip(exponent, -1000, 1000)
55
+ K[start:end, :] = (sigma_f**2) * np.exp(exponent_clipped)
56
+ start = end
57
+
58
+ return K
59
+
60
+ def rbf_kernel_grad_x_chunked(X1, X2, sigma_f, length_scale, chunk_size=1024):
61
+ """
62
+ Compute gradient of the RBF kernel with respect to X1 in a chunked manner.
63
+ Output shape: (N1, N2, d).
64
+
65
+ Args:
66
+ X1: (N1, d)
67
+ X2: (N2, d)
68
+ sigma_f: float
69
+ length_scale: float
70
+ chunk_size: int
71
+
72
+ Returns:
73
+ grad: (N1, N2, d) array
74
+ """
75
+ N1, d = X1.shape
76
+ N2 = X2.shape[0]
77
+ grad = np.zeros((N1, N2, d), dtype=np.float64)
78
+
79
+ start = 0
80
+ while start < N1:
81
+ end = min(start + chunk_size, N1)
82
+ X1_chunk = X1[start:end] # (chunk_section, d)
83
+
84
+ # Kernel block for chunk
85
+ K_chunk = rbf_kernel_chunked(X1_chunk, X2, sigma_f, length_scale, chunk_size=chunk_size)
86
+
87
+ # diff array for chunk => shape (chunk_section, N2, d)
88
+ diff_chunk = X1_chunk[:, np.newaxis, :] - X2[np.newaxis, :, :]
89
+
90
+ # Gradient formula: (∂k/∂x1) = -diff / l^2 * k
91
+ K_chunk_3d = K_chunk[..., np.newaxis] # shape becomes (chunk_section, N2, 1)
92
+ grad_chunk = -diff_chunk / (length_scale**2) * K_chunk_3d
93
+
94
+ grad[start:end, :, :] = grad_chunk
95
+ start = end
96
+
97
+ return grad
98
+
99
+ def rbf_kernel_hessian_chunked(X1, X2, sigma_f, length_scale, chunk_size=512):
100
+ """
101
+ Compute Hessian of the RBF kernel with respect to x1, x2:
102
+ Each entry H[a,b] = ∂^2 k(x1, x2) / (∂x1_a ∂x2_b),
103
+ for all pairs in X1, X2. Returns array of shape (N1, N2, d, d).
104
+
105
+ Args:
106
+ X1: (N1, d)
107
+ X2: (N2, d)
108
+ sigma_f: float
109
+ length_scale: float
110
+ chunk_size: int
111
+
112
+ Returns:
113
+ hessian: (N1, N2, d, d)
114
+ """
115
+ N1, d = X1.shape
116
+ N2 = X2.shape[0]
117
+ hessian = np.zeros((N1, N2, d, d), dtype=np.float64)
118
+
119
+ # We'll compute the kernel block and then apply the known Hessian formula:
120
+ # H[a,b] = k * [ δ(a,b) / l^2 - (x1[a] - x2[a])*(x1[b] - x2[b]) / l^4 ]
121
+ start = 0
122
+ while start < N1:
123
+ end = min(start + chunk_size, N1)
124
+ X1_chunk = X1[start:end] # shape (chunk_section, d)
125
+
126
+ # k values (chunk_section, N2)
127
+ K_chunk = rbf_kernel_chunked(X1_chunk, X2, sigma_f, length_scale, chunk_size=chunk_size)
128
+ diff_chunk = X1_chunk[:, np.newaxis, :] - X2[np.newaxis, :, :] # (chunk_section, N2, d)
129
+
130
+ # Expand for shape (chunk_section, N2, 1, 1)
131
+ K_4d = K_chunk[:, :, np.newaxis, np.newaxis]
132
+
133
+ # diff outer product => (chunk_section, N2, d, d)
134
+ diff_outer = np.einsum('...i,...j->...ij', diff_chunk, diff_chunk)
135
+
136
+ # Identity for each (d, d)
137
+ eye_d = np.eye(d, dtype=np.float64).reshape(1, 1, d, d)
138
+
139
+ # Hessian formula
140
+ # H = K * [ (I / l^2) - (diff_outer / l^4) ]
141
+ factor1 = eye_d / (length_scale**2)
142
+ factor2 = diff_outer / (length_scale**4)
143
+
144
+ hess_block = K_4d * (factor1 - factor2)
145
+ hessian[start:end] = hess_block
146
+ start = end
147
+
148
+ return hessian
149
+
150
+ ##################################
151
+ # Full Gaussian Process Regressor for Energy and Force
152
+ ##################################
153
+
154
+ class GaussianProcessRegressor:
155
+ """
156
+ Gaussian Process Regressor for energies and forces with full kernel
157
+ computations. The training block matrix is built as:
158
+ K = [ K_EE K_EF ]
159
+ [ K_FE K_FF ]
160
+ where:
161
+ - K_EE[i,j] = k(x_i, x_j)
162
+ - K_EF[i, j] = -∂k(x_i, x_j)/∂x_j (each block is 1 x d)
163
+ - K_FE[i, j] = -∂k(x_i, x_j)/∂x_i (each block is d x 1)
164
+ - K_FF[i,j] = ∂^2k(x_i, x_j)/(∂x_i ∂x_j) (each block is d x d)
165
+ The target vector is: Y = [E; F] where energies E are (N,) and forces F are (N,d).
166
+ """
167
+
168
+ def __init__(self):
169
+ """
170
+ Args:
171
+ sigma_f: RBF kernel amplitude.
172
+ length_scale: RBF kernel length scale.
173
+ noise_e: Noise standard deviation for energies.
174
+ noise_f: Noise standard deviation for forces.
175
+ chunk_size: Chunk size for kernel computations.
176
+ """
177
+ # Training data
178
+ self.X = None # shape (N, d)
179
+ self.E = None # shape (N,)
180
+ self.F = None # shape (N, d)
181
+
182
+ # Optimized hyperparameters and alpha for predictions
183
+ self.theta_opt = None
184
+ self.alpha = None
185
+
186
+ def _build_block_matrix_chunked(self, X, E, F, sigma_f, length_scale, noise_e, noise_f):
187
+ """
188
+ Build the full block kernel matrix in a chunked manner.
189
+ Returns:
190
+ K_full: (N + N*d, N + N*d) kernel matrix.
191
+ Y: (N + N*d,) target vector.
192
+ """
193
+ N, d = X.shape
194
+
195
+ # K_EE: Energy vs Energy, shape (N, N)
196
+ K_EE = rbf_kernel_chunked(X, X, sigma_f, length_scale, chunk_size=self.chunk_size)
197
+
198
+ # K_EF: Energy vs Force, shape (N, N*d)
199
+ # For each training pair (i,j), block = -∂k(x_i, x_j)/∂x_j.
200
+ # Compute gradient with respect to first argument for (X, X) then use symmetry.
201
+ grad_X = rbf_kernel_grad_x_chunked(X, X, sigma_f, length_scale, chunk_size=self.chunk_size) # shape (N, N, d)
202
+ # For derivative w.r.t second argument, we have: ∂k(x_i, x_j)/∂x_j = -∂k(x_j, x_i)/∂x_j.
203
+ # Therefore, K_EF[i, j] = -∂k(x_i, x_j)/∂x_j = grad_X[j, i]
204
+ K_EF = np.zeros((N, N * d), dtype=np.float64)
205
+ for i in range(N):
206
+ for j in range(N):
207
+ K_EF[i, j * d:(j + 1) * d] = grad_X[j, i]
208
+
209
+ # K_FE: Force vs Energy, shape (N*d, N)
210
+ # For each training pair (i,j), block = -∂k(x_i, x_j)/∂x_i.
211
+ # That is simply: K_FE[i, j] = -grad_X[i, j]
212
+ K_FE = np.zeros((N * d, N), dtype=np.float64)
213
+ for i in range(N):
214
+ for j in range(N):
215
+ K_FE[i * d:(i + 1) * d, j] = -grad_X[i, j]
216
+
217
+ # K_FF: Force vs Force, shape (N*d, N*d)
218
+ # For each pair (i,j), block = ∂^2 k(x_i, x_j)/(∂x_i ∂x_j)
219
+ H = rbf_kernel_hessian_chunked(X, X, sigma_f, length_scale, chunk_size=self.chunk_size) # shape (N, N, d, d)
220
+ K_FF = np.zeros((N * d, N * d), dtype=np.float64)
221
+ for i in range(N):
222
+ for j in range(N):
223
+ K_FF[i * d:(i + 1) * d, j * d:(j + 1) * d] = H[i, j]
224
+
225
+ # Add noise to diagonal blocks
226
+ K_EE += (noise_e**2) * np.eye(N, dtype=np.float64)
227
+ K_FF += (noise_f**2) * np.eye(N * d, dtype=np.float64)
228
+
229
+ # Combine blocks into full matrix:
230
+ # K_full = [ K_EE K_EF ]
231
+ # [ K_FE K_FF ]
232
+ top = np.hstack((K_EE, K_EF))
233
+ bottom = np.hstack((K_FE, K_FF))
234
+ K_full = np.vstack((top, bottom))
235
+
236
+ # Construct target vector Y = [E; F_vectorized]
237
+ Y = np.concatenate([E, F.reshape(-1)], axis=0)
238
+ return K_full, Y
239
+
240
+ def _neg_log_marginal_likelihood(self, params):
241
+ """
242
+ Negative log marginal likelihood function.
243
+ params: [sigma_f, length_scale, noise_e, noise_f]
244
+ """
245
+ sigma_f, length_scale, noise_e, noise_f = params
246
+ K, Y = self._build_block_matrix_chunked(self.X, self.E, self.F,
247
+ sigma_f, length_scale, noise_e, noise_f)
248
+ N, d = self.X.shape
249
+ n_data = N + N * d
250
+ try:
251
+ L = np.linalg.cholesky(K)
252
+ alpha = np.linalg.solve(L.T, np.linalg.solve(L, Y))
253
+ logdetK = 2.0 * np.sum(np.log(np.diag(L)))
254
+ except np.linalg.LinAlgError:
255
+ return 1e20
256
+
257
+ nll = 0.5 * np.dot(Y, alpha) + 0.5 * logdetK + 0.5 * n_data * np.log(2.0 * np.pi)
258
+ print("NLML func:", nll)
259
+ return nll
260
+
261
+ def fit(self, X, E, F, initial_params=(1.0, 1.0, 1e-3, 1e-3)):
262
+ """
263
+ Fit the GPR model to energy and force data.
264
+ Args:
265
+ X: (N, d) array of positions.
266
+ E: (N,) array of energy values.
267
+ F: (N, d) array of force values.
268
+ initial_params: Tuple of initial hyperparameters (sigma_f, length_scale, noise_e, noise_f).
269
+ """
270
+ self.X = X
271
+ self.E = E
272
+ self.F = F
273
+
274
+ bounds = [(1e-9, None), (1e-9, None), (1e-9, None), (1e-9, None)]
275
+ res = minimize(self._neg_log_marginal_likelihood, x0=initial_params, bounds=bounds, method='L-BFGS-B', tol=1e-10)
276
+ self.theta_opt = res.x
277
+ self._compute_alpha()
278
+
279
+ self.sigma_f, self.length_scale, self.noise_e, self.noise_f = self.theta_opt
280
+
281
+ def _compute_alpha(self):
282
+ """
283
+ Compute alpha = K^{-1} Y with the optimized hyperparameters.
284
+ """
285
+ sigma_f, length_scale, noise_e, noise_f = self.theta_opt
286
+ K, Y = self._build_block_matrix_chunked(self.X, self.E, self.F,
287
+ sigma_f, length_scale, noise_e, noise_f)
288
+ L = np.linalg.cholesky(K)
289
+ self.alpha = np.linalg.solve(L.T, np.linalg.solve(L, Y))
290
+
291
+ def predict_energy_and_forces(self, X_star):
292
+ """
293
+ Predict the energy and forces at new positions X_star.
294
+ For each test point s:
295
+ E(s) = k(s, X) * alpha_E + [-∂k(s, X)/∂x] * alpha_F,
296
+ F(s) = [-∂k(s, X)/∂s] * alpha_E + [∂^2k(s, X)/(∂s ∂x)] * alpha_F,
297
+ where alpha_E = self.alpha[:N] and alpha_F = self.alpha[N:].reshape(N, d).
298
+ Args:
299
+ X_star: (M, d) array of positions.
300
+ Returns:
301
+ E_pred: (M,) predicted energies.
302
+ F_pred: (M, d) predicted forces.
303
+ """
304
+ sigma_f, length_scale, noise_e, noise_f = self.theta_opt
305
+ X_train = self.X
306
+ N, d = X_train.shape
307
+ M = X_star.shape[0]
308
+
309
+ # Compute K_star_EE: k(X_star, X_train), shape (M, N)
310
+ K_star_EE = rbf_kernel_chunked(X_star, X_train, sigma_f, length_scale, chunk_size=self.chunk_size)
311
+
312
+ # Compute derivative of k w.r.t test input: ∇_{s} k(s, x)
313
+ # This is used for K_star_FE: -∇_s k(s, x)
314
+ grad_test = rbf_kernel_grad_x_chunked(X_star, X_train, sigma_f, length_scale, chunk_size=self.chunk_size)
315
+ # K_star_FE = -∇_{s} k(s,x), shape (M, N, d)
316
+ K_star_FE = -grad_test
317
+
318
+ # Compute derivative of k w.r.t training input: ∇_{x} k(x, s)
319
+ # Using symmetry, ∇_{x} k(s, x) = -∇_{x} k(x, s)
320
+ grad_train = rbf_kernel_grad_x_chunked(X_train, X_star, sigma_f, length_scale, chunk_size=self.chunk_size)
321
+ # Transpose grad_train to shape (M, N, d)
322
+ grad_train_T = np.transpose(grad_train, (1, 0, 2))
323
+ # K_star_EF = -∂k(s,x)/∂x. But note: ∂k(s,x)/∂x = -∇_{x} k(x,s), so:
324
+ K_star_EF = grad_train_T # shape (M, N, d)
325
+
326
+ # Compute Hessian cross covariance: ∂^2k(s, x)/(∂s ∂x), shape (M, N, d, d)
327
+ K_star_FF = rbf_kernel_hessian_chunked(X_star, X_train, sigma_f, length_scale, chunk_size=self.chunk_size)
328
+
329
+ # Reshape alpha into alpha_E and alpha_F
330
+ alpha_E = self.alpha[:N] # shape (N,)
331
+ alpha_F = self.alpha[N:].reshape(N, d) # shape (N, d)
332
+
333
+ # Predicted energy: E_pred = K_star_EE * alpha_E + sum_{j,l} K_star_EF[:, j, l] * alpha_F[j,l]
334
+ E_part1 = np.dot(K_star_EE, alpha_E) # shape (M,)
335
+ E_part2 = np.einsum('mjd,jd->m', K_star_EF, alpha_F) # shape (M,)
336
+ E_pred = E_part1 + E_part2
337
+
338
+ # Predicted force: F_pred = sum_j [K_star_FE[:,j,:]*alpha_E[j]] + sum_j [K_star_FF[:,j,:,:] dot alpha_F[j]]
339
+ F_part1 = np.einsum('mnd,n->md', K_star_FE, alpha_E) # shape (M, d)
340
+ F_part2 = np.einsum('mnij,nj->mi', K_star_FF, alpha_F) # shape (M, d)
341
+ F_pred = F_part1 + F_part2
342
+
343
+ return E_pred, F_pred
344
+
345
+
346
+ class CaluculationGPNEB:
347
+ def __init__(self, directory, APPLY_CI_NEB=99999):
348
+ self.APPLY_CI_NEB = APPLY_CI_NEB
349
+ self.base_dir = directory
350
+ self.init_param = None
351
+ self.spes_iter = 50
352
+ self.chunk_size = 64
353
+ return
354
+
355
+ def calc_quickmin_step(self, positions, velocities, forces, mass=1.0, dt=0.01, alpha=0.0):
356
+ dot_vf = np.sum(velocities * forces, axis=(1, 2), keepdims=True)
357
+ mask = dot_vf < 0
358
+ velocities[mask] = 0.0
359
+ velocities = (1 - alpha) * velocities + (dt / mass) * forces
360
+ positions = positions + dt * velocities
361
+ return positions, velocities
362
+
363
+ def judge_early_stopping(self, spes_energy_list, prev_spes_energy_list, spes_force_list, prev_spes_force_list):
364
+ boolean_list = []
365
+ nnode = len(spes_energy_list)
366
+ for i in range(nnode):
367
+ pass
368
+ ### implement early stopping conditions
369
+
370
+
371
+ return boolean_list
372
+
373
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
374
+ nnode = len(energy_list)
375
+ prev_geometry_num_list = copy.copy(geometry_num_list)
376
+ print("Start GPR fitting.")
377
+ if optimize_num == 0:
378
+ GPR = GaussianProcessRegressor()
379
+ init_param = {"sigma_f": 1.0, "length_scale": 1.0, "noise_e": 1e-3, "noise_f": 1e-3, "chunk_size": self.chunk_size}
380
+ train_geom_list = []
381
+ train_force_list = []
382
+ train_energy_list = []
383
+
384
+ for i in range(nnode):
385
+ train_geom_list.append(geometry_num_list[i].reshape(-1))
386
+ train_energy_list.append(energy_list[i])
387
+ train_force_list.append(gradient_list[i].reshape(-1))
388
+ train_geom_list = np.array(train_geom_list, dtype = "float64")
389
+ train_energy_list = np.array(train_energy_list, dtype = "float64")
390
+ train_force_list = np.array(train_force_list, dtype = "float64")
391
+ GPR.fit(train_geom_list, train_energy_list, train_force_list, init_param)
392
+
393
+ else:
394
+ GPR = GaussianProcessRegressor()
395
+ train_geom_list = np.load(self.base_dir + "/train_geometry_num_list.npy")
396
+ train_energy_list = np.load(self.base_dir + "/train_energy_list.npy")
397
+ train_force_list = np.load(self.base_dir + "/train_force_list.npy")
398
+ for i in range(nnode):
399
+ np.vstack(train_geom_list, geometry_num_list[i].reshape(-1))
400
+ np.hstack(train_energy_list, energy_list[i])
401
+ np.vstack(train_force_list, gradient_list[i].reshape(-1))
402
+
403
+ GPR.fit(train_geom_list, train_energy_list, train_force_list, self.init_param)
404
+
405
+ print("GPR fitting was done.")
406
+ print("Start optimization path on SPES (Surrogate Potential Energy Surface).")
407
+
408
+ velocities_list = np.zeros_like(gradient_list)
409
+ for l in range(self.spes_iter):
410
+ print("SPES Opt ITR.:", l)
411
+ input_pos = geometry_num_list
412
+ ### reshape positions (3N, nnode) input_pos
413
+ spes_energy_list, spes_force_list = GPR.predict_energy_and_forces(input_pos)
414
+ ### reshape positions (nnode, N, 3) input_pos
415
+ total_neb_spes_force_list = self.calc_force_for_gpr(input_pos, spes_energy_list, spes_force_list)
416
+ ### reshape total_neb_spes_force_list (nnode, N, 3)
417
+ for j in range(nnode):
418
+ input_pos[j], velocities_list[j] = self.calc_quickmin_step(input_pos[j], velocities_list[j], total_neb_spes_force_list[j], mass=1.0, dt=0.01, alpha=0.0)
419
+ if l > 0:
420
+ ### implement conditions of early stopping. is_early_stopping_list = self.judge_early_stopping(spes_energy_list, prev_spes_energy_list, spes_force_list, prev_spes_force_list)
421
+ pass
422
+ else:
423
+ pass
424
+
425
+ for j in range(nnode):
426
+ if is_early_stopping_list[j]:
427
+ print("Detect abnormal force and energy. Stop updating geometry.")
428
+
429
+ else:
430
+ geometry_num_list[j] = input_pos[j]
431
+ prev_spes_energy_list = spes_energy_list
432
+ prev_spes_force_list = spes_force_list
433
+
434
+ print("Optimization on SPES was done.")
435
+ np.save(self.base_dir + "/train_geometry_num_list.npy", train_geom_list)
436
+ np.save(self.base_dir + "/train_energy_list.npy", train_energy_list)
437
+ np.save(self.base_dir + "/train_force_list.npy", train_force_list)
438
+ self.init_param = {"sigma_f": GPR.sigma_f, "length_scale": GPR.length_scale, "noise_e": GPR.noise_e, "noise_f": GPR.noise_f, "chunk_size": self.chunk_size}
439
+ total_force_list = geometry_num_list - prev_geometry_num_list
440
+ return np.array(total_force_list, dtype = "float64")
441
+
442
+ def calc_force_for_gpr(self, geometry_num_list, energy_list, gradient_list):
443
+ print("GPNEBGPNEBGPNEBGPNEBGPNEBGPNEBGPNEBGPNEBGPNEBGPNEBGPNEB")
444
+ nnode = len(energy_list)
445
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
446
+ total_force_list = []
447
+ for i in range(nnode):
448
+ if i == 0:
449
+ total_force_list.append(-1*np.array(gradient_list[0], dtype = "float64"))
450
+ continue
451
+ elif i == nnode-1:
452
+ total_force_list.append(-1*np.array(gradient_list[nnode-1], dtype = "float64"))
453
+ continue
454
+ tmp_grad = copy.copy(gradient_list[i]).reshape(-1, 1)
455
+ force, tangent_grad = self.calc_project_out_grad(geometry_num_list[i-1], geometry_num_list[i], geometry_num_list[i+1], tmp_grad, energy_list[i-1:i+2])
456
+ total_force_list.append(-1*force.reshape(-1, 3))
457
+ return np.array(total_force_list, dtype = "float64")
458
+
459
+ def calc_project_out_grad(self, coord_1, coord_2, coord_3, grad_2, energy_list):# grad: (3N, 1), geom_num_list: (N, 3)
460
+ natom = len(coord_2)
461
+ tmp_grad = copy.copy(grad_2)
462
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
463
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
464
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
465
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
466
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
467
+ tangent_grad = projection_grad
468
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
469
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
470
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
471
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
472
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
473
+ tangent_grad = projection_grad
474
+ else:
475
+ B_mat_plus = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
476
+ B_mat_minus = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
477
+ int_grad_plus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_plus)
478
+ int_grad_minus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_minus)
479
+ max_ene = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
480
+ min_ene = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
481
+ a = (max_ene + 1e-15) / (max_ene + min_ene + 1e-15)
482
+ b = (min_ene + 1e-15) / (max_ene + min_ene + 1e-15)
483
+
484
+ if energy_list[0] < energy_list[2]:
485
+ projection_grad_plus = calc_cart_grad_from_pBmat(-a*int_grad_plus, B_mat_plus)
486
+ projection_grad_minus = calc_cart_grad_from_pBmat(-b*int_grad_minus, B_mat_minus)
487
+
488
+ else:
489
+ projection_grad_plus = calc_cart_grad_from_pBmat(-b*int_grad_plus, B_mat_plus)
490
+ projection_grad_minus = calc_cart_grad_from_pBmat(-a*int_grad_minus, B_mat_minus)
491
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad_plus + projection_grad_minus
492
+ tangent_grad = projection_grad_plus + projection_grad_minus
493
+ return proj_grad, tangent_grad
494
+
495
+
496
+ def calc_B_matrix_for_NEB_tangent(self, coord_1, coord_2):
497
+ natom = len(coord_2)
498
+ B_mat = np.zeros((natom, 3*natom))
499
+
500
+ for i in range(natom):
501
+ norm_12 = np.linalg.norm(coord_1[i] - coord_2[i]) + 1e-15
502
+ dr12_dx2 = (coord_2[i][0] - coord_1[i][0]) / norm_12
503
+ dr12_dy2 = (coord_2[i][1] - coord_1[i][1]) / norm_12
504
+ dr12_dz2 = (coord_2[i][2] - coord_1[i][2]) / norm_12
505
+ B_mat[i][3*i] = dr12_dx2
506
+ B_mat[i][3*i+1] = dr12_dy2
507
+ B_mat[i][3*i+2] = dr12_dz2
508
+
509
+ return B_mat
510
+
511
+
512
+
@@ -0,0 +1,113 @@
1
+ import numpy as np
2
+ from scipy.signal import argrelextrema
3
+
4
+ def extremum_list_index(energy_list):
5
+ local_max_energy_list_index = argrelextrema(energy_list, np.greater)
6
+ inverse_energy_list = (-1)*energy_list
7
+ local_min_energy_list_index = argrelextrema(inverse_energy_list, np.greater)
8
+
9
+ local_max_energy_list_index = local_max_energy_list_index[0].tolist()
10
+ local_min_energy_list_index = local_min_energy_list_index[0].tolist()
11
+ local_max_energy_list_index.append(0)
12
+ local_min_energy_list_index.append(0)
13
+ local_max_energy_list_index.append(0)
14
+ local_min_energy_list_index.append(0)
15
+ return local_max_energy_list_index, local_min_energy_list_index
16
+
17
+
18
+
19
+
20
+ class CaluculationLUP:
21
+ def __init__(self, APPLY_CI_NEB=99999):
22
+ self.spring_constant_k = 0.01
23
+ self.APPLY_CI_NEB = APPLY_CI_NEB
24
+ self.force_const_for_cineb = 0.01
25
+
26
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
27
+ print("LUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUPLUP")
28
+ #ref. Ulitsky, A., & Elber, R. (1990). A new technique to calculate steepest descent paths in flexible polyatomic systems. The Journal of Chemical Physics, 92(2), 1510.
29
+ #https://doi.org/10.1063/1.458112
30
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
31
+
32
+
33
+ total_force_list = [((-1)*np.array(gradient_list[0], dtype = "float64")).tolist()]
34
+ for i in range(1,len(energy_list)-1):
35
+ tau_plus, tau_minus, tau = [], [], []
36
+
37
+ delta_max_energy = np.array(max([(energy_list[i+1]-energy_list[i]),(energy_list[i-1]-energy_list[i])]), dtype = "float64")
38
+ delta_min_energy = np.array(min([(energy_list[i+1]-energy_list[i]),(energy_list[i-1]-energy_list[i])]), dtype = "float64")
39
+
40
+ if (energy_list[i-1] < energy_list[i]) and (energy_list[i] < energy_list[i+1]):
41
+ for t in range(len(geometry_num_list[i])):
42
+ tau_vector = geometry_num_list[i+1][t]-geometry_num_list[i][t]
43
+ tau_norm = np.linalg.norm(geometry_num_list[i+1][t]-geometry_num_list[i][t], ord=2)
44
+ tau.append(np.divide(tau_vector, tau_norm, out=np.zeros_like(geometry_num_list[i][t]) ,where=np.linalg.norm(geometry_num_list[i+1][t]-geometry_num_list[i][t], ord=2)!=0).tolist())
45
+
46
+
47
+ elif (energy_list[i-1] > energy_list[i]) and (energy_list[i] > energy_list[i+1]):
48
+ for t in range(len(geometry_num_list[i])):
49
+ tau_vector = geometry_num_list[i][t]-geometry_num_list[i-1][t]
50
+ tau_norm = np.linalg.norm(geometry_num_list[i][t]-geometry_num_list[i-1][t], ord=2)
51
+ tau.append(np.divide(tau_vector, tau_norm, out=np.zeros_like(geometry_num_list[i][t]), where=np.linalg.norm(geometry_num_list[i][t]-geometry_num_list[i-1][t], ord=2)!=0).tolist())
52
+
53
+
54
+
55
+ else: #((energy_list[i-1] >= energy_list[i]) and (energy_list[i] <= energy_list[i+1])) or ((energy_list[i-1] <= energy_list[i]) and (energy_list[i] >= energy_list[i+1])):
56
+ for t in range(len(geometry_num_list[i])):
57
+ tau_minus_vector = geometry_num_list[i][t]-geometry_num_list[i-1][t]
58
+ tau_minus_norm = np.linalg.norm(geometry_num_list[i][t]-geometry_num_list[i-1][t], ord=2)
59
+ tau_minus.append(np.divide(tau_minus_vector, tau_minus_norm
60
+ ,out=np.zeros_like(geometry_num_list[i][t]),
61
+ where=np.linalg.norm(geometry_num_list[i][t]-geometry_num_list[i-1][t], ord=2)!=0).tolist())
62
+
63
+ for t in range(len(geometry_num_list[i])):
64
+ tau_plus_vector = geometry_num_list[i+1][t]-geometry_num_list[i][t]
65
+ tau_plus_norm = np.linalg.norm(geometry_num_list[i+1][t]-geometry_num_list[i][t], ord=2)
66
+ tau_plus.append(np.divide(tau_plus_vector, tau_plus_norm, out=np.zeros_like(geometry_num_list[i][t]), where=np.linalg.norm(geometry_num_list[i+1][t]-geometry_num_list[i][t], ord=2)!=0).tolist())
67
+
68
+ if energy_list[i-1] > energy_list[i+1]:
69
+ for t in range(len(geometry_num_list[i])):
70
+ tau_vector = (tau_plus[t]*delta_min_energy+tau_minus[t]*delta_max_energy)
71
+ tau_norm = np.linalg.norm(tau_plus[t]*delta_min_energy+tau_minus[t]*delta_max_energy, ord=2)
72
+ tau.append(np.divide(tau_vector,tau_norm, out=np.zeros_like(tau_plus[0]) ,where=np.linalg.norm(tau_plus[t]*delta_min_energy+tau_minus[t]*delta_max_energy!=0)).tolist())
73
+ else:
74
+ for t in range(len(geometry_num_list[i])):
75
+ tau_vector = (tau_plus[t]*delta_max_energy+tau_minus[t]*delta_min_energy)
76
+ tau_norm = np.linalg.norm(tau_plus[t]*delta_min_energy+tau_minus[t]*delta_max_energy, ord=2)
77
+ tau.append(np.divide(tau_vector, tau_norm,out=np.zeros_like(tau_minus[0]) ,where=np.linalg.norm(tau_plus[t]*delta_min_energy+tau_minus[t]*delta_max_energy, ord=2)!=0 ).tolist())
78
+
79
+ tau_plus, tau_minus, tau = np.array(tau_plus, dtype = "float64"), np.array(tau_minus, dtype = "float64"), np.array(tau, dtype = "float64")
80
+ #print("tau_minus:\n",tau_minus)
81
+ #print("tau_plus:\n",tau_plus)
82
+ #print("tau:\n",str(tau))
83
+ force_perpendicularity = []
84
+
85
+
86
+ for f in range(len(geometry_num_list[i])):
87
+ grad = 0.0
88
+
89
+ for gg in range(len(gradient_list[i])):
90
+ grad += np.linalg.norm(gradient_list[i][gg], ord=2)
91
+
92
+ grad = grad/len(gradient_list[i])
93
+
94
+
95
+
96
+ force_perpendicularity.append(np.array(gradient_list[i][f]-(np.dot(gradient_list[i][f], tau[f]))*tau[f], dtype = "float64"))
97
+
98
+
99
+
100
+ force_perpendicularity = np.array(force_perpendicularity, dtype = "float64")
101
+ total_force = np.array((-1)*force_perpendicularity, dtype = "float64")
102
+
103
+ if np.nanmean(np.nanmean(total_force)) > 10:
104
+ total_force = total_force / np.nanmean(np.nanmean(total_force))
105
+
106
+ total_force_list.append(total_force.tolist())
107
+
108
+
109
+
110
+
111
+ total_force_list.append(((-1)*np.array(gradient_list[-1], dtype = "float64")).tolist())
112
+
113
+ return np.array(total_force_list, dtype = "float64")