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,174 @@
1
+ import numpy as np
2
+ import copy
3
+ from scipy.signal import argrelextrema
4
+ from multioptpy.Coordinate.redundant_coordinate import calc_int_grad_from_pBmat, calc_cart_grad_from_pBmat
5
+
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
+
22
+
23
+ class CaluculationQSM:
24
+ def __init__(self, APPLY_CI_NEB=99999):
25
+ self.spring_constant_k = 0.01
26
+ self.APPLY_CI_NEB = APPLY_CI_NEB
27
+ self.force_const_for_cineb = 0.01
28
+
29
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
30
+ print("QSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSMQSM")
31
+ #ref. J. Chem. Phys. 124, 054109 (2006)
32
+ nnode = len(energy_list)
33
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
34
+ total_force_list = []
35
+ self.tau_list = []
36
+ for i in range(nnode):
37
+ if i == 0:
38
+ total_force_list.append(-1*np.array(gradient_list[0], dtype = "float64"))
39
+ self.tau_list.append(np.zeros_like(geometry_num_list[0], dtype = "float64"))
40
+ continue
41
+ elif i == nnode-1:
42
+ total_force_list.append(-1*np.array(gradient_list[nnode-1], dtype = "float64"))
43
+ self.tau_list.append(np.zeros_like(geometry_num_list[nnode-1], dtype = "float64"))
44
+ continue
45
+ tmp_grad = copy.copy(gradient_list[i]).reshape(-1, 1)
46
+ 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])
47
+ if optimize_num > self.APPLY_CI_NEB and (i + 1 in local_max_energy_list_index or i - 1 in local_max_energy_list_index) and (i != 1 and i != nnode-2):
48
+ force *= 0.001
49
+ print("Restrect step of # NODE", i, " for CI-NEB")
50
+ elif optimize_num > self.APPLY_CI_NEB and (i in local_max_energy_list_index) and (i != 1 or i != nnode-2):
51
+ force = self.calc_ci_neb_force(tmp_grad, tangent_grad)
52
+ print("CI-NEB was applied to # NODE", i)
53
+ else:
54
+ pass
55
+
56
+
57
+
58
+ total_force_list.append(-1*force.reshape(-1, 3))
59
+ self.tau_list.append(tangent_grad.reshape(-1, 3) / (np.linalg.norm(tangent_grad) + 1e-15))
60
+
61
+ total_force_list = np.array(total_force_list, dtype = "float64")
62
+ total_force_list = projection(total_force_list, geometry_num_list)
63
+
64
+ return total_force_list
65
+
66
+ def calc_project_out_grad(self, coord_1, coord_2, coord_3, grad_2, energy_list):# grad: (3N, 1), geom_num_list: (N, 3)
67
+ natom = len(coord_2)
68
+ tmp_grad = copy.copy(grad_2)
69
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
70
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
71
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
72
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
73
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
74
+ tangent_grad = projection_grad
75
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
76
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
77
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
78
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
79
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
80
+ tangent_grad = projection_grad
81
+ else:
82
+ B_mat_plus = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
83
+ B_mat_minus = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
84
+ int_grad_plus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_plus)
85
+ int_grad_minus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_minus)
86
+ max_ene = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
87
+ min_ene = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
88
+ a = (max_ene) / (max_ene + min_ene + 1e-8)
89
+ b = (min_ene) / (max_ene + min_ene + 1e-8)
90
+
91
+ if energy_list[0] < energy_list[2]:
92
+ projection_grad_plus = calc_cart_grad_from_pBmat(-a*int_grad_plus, B_mat_plus)
93
+ projection_grad_minus = calc_cart_grad_from_pBmat(-b*int_grad_minus, B_mat_minus)
94
+
95
+ else:
96
+ projection_grad_plus = calc_cart_grad_from_pBmat(-b*int_grad_plus, B_mat_plus)
97
+ projection_grad_minus = calc_cart_grad_from_pBmat(-a*int_grad_minus, B_mat_minus)
98
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad_plus + projection_grad_minus
99
+ tangent_grad = projection_grad_plus + projection_grad_minus
100
+ return proj_grad, tangent_grad
101
+
102
+
103
+ def calc_B_matrix_for_NEB_tangent(self, coord_1, coord_2):
104
+ natom = len(coord_2)
105
+ B_mat = np.zeros((natom, 3*natom))
106
+
107
+ for i in range(natom):
108
+ norm_12 = np.linalg.norm(coord_1[i] - coord_2[i]) + 1e-15
109
+ dr12_dx2 = (coord_2[i][0] - coord_1[i][0]) / norm_12
110
+ dr12_dy2 = (coord_2[i][1] - coord_1[i][1]) / norm_12
111
+ dr12_dz2 = (coord_2[i][2] - coord_1[i][2]) / norm_12
112
+ B_mat[i][3*i] = dr12_dx2
113
+ B_mat[i][3*i+1] = dr12_dy2
114
+ B_mat[i][3*i+2] = dr12_dz2
115
+
116
+ return B_mat
117
+
118
+ def calc_proj_hess(self, hess, node_num, geometry_num_list):
119
+ if node_num == 0 or node_num == len(geometry_num_list)-1:
120
+ return hess
121
+ proj_hess = projection_hess(hess, geometry_num_list, node_num)
122
+ # Make sure the Hessian is symmetric
123
+ proj_hess = 0.5 * (proj_hess + proj_hess.T)
124
+ return proj_hess
125
+
126
+
127
+
128
+ def projection(move_vector_list, geometry_list):
129
+ print("Applying projection to move vectors")
130
+ for i in range(1, len(geometry_list)-1):
131
+ vec_1 = geometry_list[i] - geometry_list[i-1]
132
+ vec_2 = geometry_list[i+1] - geometry_list[i]
133
+ vec_1_norm = np.linalg.norm(vec_1)
134
+ vec_2_norm = np.linalg.norm(vec_2)
135
+ if vec_1_norm < 1e-8 or vec_2_norm < 1e-8:
136
+ continue
137
+ vec_1 = vec_1 / vec_1_norm
138
+ vec_2 = vec_2 / vec_2_norm
139
+ vec_1 = vec_1.reshape(-1, 1)
140
+ vec_2 = vec_2.reshape(-1, 1)
141
+ # Gram-Schmidt process
142
+ vec_2 -= np.dot(vec_2.T, vec_1) * vec_1
143
+ if np.linalg.norm(vec_2) < 1e-8:
144
+ continue
145
+ vec_2 /= np.linalg.norm(vec_2)
146
+
147
+ P = np.eye(len(vec_1)) - np.outer(vec_1, vec_1) - np.outer(vec_2, vec_2)
148
+ tmp_proj_move_vec = np.dot(P, move_vector_list[i].reshape(-1, 1))
149
+ move_vector_list[i] = tmp_proj_move_vec.reshape(-1, 3)
150
+ return move_vector_list
151
+
152
+
153
+ def projection_hess(hessian, geometry_list, node_num):
154
+ print("Applying projection to Hessian")
155
+
156
+ vec_1 = geometry_list[node_num] - geometry_list[node_num-1]
157
+ vec_2 = geometry_list[node_num+1] - geometry_list[node_num]
158
+ vec_1_norm = np.linalg.norm(vec_1)
159
+ vec_2_norm = np.linalg.norm(vec_2)
160
+ if vec_1_norm < 1e-8 or vec_2_norm < 1e-8:
161
+ return hessian
162
+ vec_1 = vec_1 / vec_1_norm
163
+ vec_2 = vec_2 / vec_2_norm
164
+ vec_1 = vec_1.reshape(-1, 1)
165
+ vec_2 = vec_2.reshape(-1, 1)
166
+ # Gram-Schmidt process
167
+ vec_2 -= np.dot(vec_2.T, vec_1) * vec_1
168
+ if np.linalg.norm(vec_2) < 1e-8:
169
+ return hessian
170
+ vec_2 /= np.linalg.norm(vec_2)
171
+
172
+ P = np.eye(len(vec_1)) - np.outer(vec_1, vec_1) - np.outer(vec_2, vec_2)
173
+ tmp_proj_hess = np.dot(np.dot(P, hessian), P.T)
174
+ return tmp_proj_hess
@@ -0,0 +1,304 @@
1
+ import numpy as np
2
+ import copy
3
+ from scipy.signal import argrelextrema
4
+
5
+
6
+ def extremum_list_index(energy_list):
7
+ local_max_energy_list_index = argrelextrema(energy_list, np.greater)
8
+ inverse_energy_list = (-1)*energy_list
9
+ local_min_energy_list_index = argrelextrema(inverse_energy_list, np.greater)
10
+
11
+ local_max_energy_list_index = local_max_energy_list_index[0].tolist()
12
+ local_min_energy_list_index = local_min_energy_list_index[0].tolist()
13
+ local_max_energy_list_index.append(0)
14
+ local_min_energy_list_index.append(0)
15
+ local_max_energy_list_index.append(0)
16
+ local_min_energy_list_index.append(0)
17
+ return local_max_energy_list_index, local_min_energy_list_index
18
+
19
+ class CaluculationQSMv2:
20
+ """
21
+ Implementation of Tangent-based Projection using Ayala & Schlegel (1997) method.
22
+ Replaces the B-matrix logic of QSM with geometric tangent propagation from the TS.
23
+ """
24
+ def __init__(self, APPLY_CI_NEB=99999):
25
+ self.spring_constant_k = 0.01
26
+ self.APPLY_CI_NEB = APPLY_CI_NEB
27
+ self.force_const_for_cineb = 0.01
28
+ self.tau_list = [] # Cache tangents for Hessian projection
29
+
30
+ def _normalize(self, v):
31
+ """Helper function to normalize a vector."""
32
+ norm = np.linalg.norm(v)
33
+ return v / norm if norm > 1e-10 else v
34
+
35
+ def _calc_arc_tangent(self, q_cur, q_uphill, t_uphill):
36
+ """Ayala & Schlegel Eq. 3c: Arc approximation"""
37
+ chord = q_cur - q_uphill
38
+ diff_norm_sq = np.dot(chord, chord)
39
+ denom = 2 * np.dot(t_uphill, chord)
40
+
41
+ if abs(denom) < 1e-10:
42
+ return self._normalize(chord)
43
+
44
+ r = diff_norm_sq / denom
45
+ t_new = (chord - r * t_uphill) / r
46
+ return self._normalize(t_new)
47
+
48
+ def _calc_parabola_tangent(self, q_cur, q_uphill, t_uphill):
49
+ """Ayala & Schlegel Eq. 3d: Parabola approximation"""
50
+ chord = q_cur - q_uphill
51
+ chord_len = np.linalg.norm(chord)
52
+ if chord_len < 1e-10:
53
+ return t_uphill
54
+
55
+ cos_theta = np.dot(chord, t_uphill) / chord_len
56
+ theta = np.arccos(np.clip(cos_theta, -1.0, 1.0))
57
+
58
+ proj = np.dot(chord, t_uphill)
59
+ n_vec = chord - proj * t_uphill
60
+ n_vec = self._normalize(n_vec)
61
+
62
+ tan_val = np.tan(theta - (np.pi / 4.0))
63
+ t_new = n_vec - tan_val * (t_uphill - n_vec)
64
+ return self._normalize(t_new)
65
+
66
+ def _calculate_all_tangents(self, geometry_num_list, energy_list):
67
+ """
68
+ Calculate tangents for all nodes using Ayala & Schlegel logic.
69
+ Propagates from the highest energy point (TS) downwards.
70
+ """
71
+ geoms = np.array(geometry_num_list, dtype=np.float64)
72
+ energies = np.array(energy_list, dtype=np.float64)
73
+ n_images = len(geoms)
74
+
75
+ # Flatten geometries to treat system as a single vector (3N dim)
76
+ flat_geoms = geoms.reshape(n_images, -1)
77
+ tangents = np.zeros_like(flat_geoms)
78
+
79
+ # 1. Find TS (Highest Energy)
80
+ # Exclude fixed endpoints (0 and -1) from being the TS source if possible
81
+ search_energies = energies.copy()
82
+
83
+ ts_idx = np.argmax(search_energies)
84
+
85
+ # Safety for edge cases
86
+ if ts_idx == 0:
87
+ ts_idx = 1
88
+ if ts_idx == n_images - 1:
89
+ ts_idx = n_images - 2
90
+
91
+ # 2. Tangent at TS (Eq. 3a)
92
+ q_ts = flat_geoms[ts_idx]
93
+ q_prev = flat_geoms[ts_idx - 1]
94
+ q_next = flat_geoms[ts_idx + 1]
95
+
96
+ v_prev = q_prev - q_ts
97
+ v_next = q_next - q_ts
98
+
99
+ dist_prev_sq = max(np.dot(v_prev, v_prev), 1e-10)
100
+ dist_next_sq = max(np.dot(v_next, v_next), 1e-10)
101
+
102
+ ts_tangent = (v_next / dist_next_sq) - (v_prev / dist_prev_sq)
103
+ tangents[ts_idx] = self._normalize(ts_tangent)
104
+
105
+ # 3. Propagate Downhill (Reactant side: ts-1 -> 1)
106
+ for i in range(ts_idx - 1, 0, -1):
107
+ q_cur = flat_geoms[i]
108
+ q_uphill = flat_geoms[i+1]
109
+ t_uphill = tangents[i+1]
110
+
111
+ chord = q_cur - q_uphill
112
+ chord_u = self._normalize(chord)
113
+ angle = np.arccos(np.clip(np.dot(chord_u, t_uphill), -1.0, 1.0))
114
+
115
+ if angle <= (np.pi / 4.0):
116
+ tangents[i] = self._calc_arc_tangent(q_cur, q_uphill, t_uphill)
117
+ else:
118
+ tangents[i] = self._calc_parabola_tangent(q_cur, q_uphill, t_uphill)
119
+
120
+ # 4. Propagate Downhill (Product side: ts+1 -> N-2)
121
+ for i in range(ts_idx + 1, n_images - 1):
122
+ q_cur = flat_geoms[i]
123
+ q_uphill = flat_geoms[i-1]
124
+ t_uphill = tangents[i-1]
125
+
126
+ chord = q_cur - q_uphill
127
+ chord_u = self._normalize(chord)
128
+ angle = np.arccos(np.clip(np.dot(chord_u, t_uphill), -1.0, 1.0))
129
+
130
+ if angle <= (np.pi / 4.0):
131
+ tangents[i] = self._calc_arc_tangent(q_cur, q_uphill, t_uphill)
132
+ else:
133
+ tangents[i] = self._calc_parabola_tangent(q_cur, q_uphill, t_uphill)
134
+
135
+ # Reshape tangents back to (N, Atoms, 3)
136
+ return -1*tangents.reshape(geoms.shape)
137
+
138
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
139
+ print("AyalaMethodV2_AyalaMethodV2_AyalaMethodV2_AyalaMethodV2")
140
+
141
+ nnode = len(energy_list)
142
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
143
+
144
+ # Calculate Ayala Tangents for all nodes
145
+ ayala_tangents = self._calculate_all_tangents(geometry_num_list, energy_list)
146
+
147
+ # Store for calc_proj_hess use
148
+ self.tau_list = ayala_tangents
149
+
150
+ total_force_list = []
151
+
152
+ for i in range(nnode):
153
+ # Fixed Endpoints
154
+ if i == 0 or i == nnode - 1:
155
+ total_force_list.append(-1 * np.array(gradient_list[i], dtype="float64"))
156
+ continue
157
+
158
+ # Current Gradient and Tangent
159
+ grad = np.array(gradient_list[i], dtype="float64").flatten()
160
+ tangent = ayala_tangents[i].flatten()
161
+
162
+ # Project Gradient
163
+ # g_parallel = (g . tau) * tau
164
+ g_parallel = np.dot(grad, tangent) * tangent
165
+ g_perp = grad - g_parallel
166
+
167
+ # Force Calculation
168
+ # Basic NEB Force (Projected Gradient): F = -g_perp
169
+ force = -1.0 * g_perp
170
+
171
+ # CI-NEB Logic
172
+ # If CI-NEB is active and this node is a local max (TS candidate)
173
+ if optimize_num > self.APPLY_CI_NEB and (i in local_max_energy_list_index) and (i != 1 and i != nnode-2):
174
+ print(f"CI-NEB was applied to # NODE {i} (Ayala Tangent)")
175
+ # Invert the parallel component to climb up: F_ci = -g_perp + g_parallel
176
+ # (Usually F = -Grad_perp - Grad_parallel_spring + ..., here we simulate climbing)
177
+ # Removing spring force along path and adding potential force UP the path.
178
+ # Since standard force here is just -g_perp, adding climbing force means adding component along gradient?
179
+ # Standard CI-NEB: F = -Gradient + 2*(Gradient.Tangent)*Tangent
180
+ # F = - (g_perp + g_para) + 2 * g_para = -g_perp + g_para
181
+ force = -1.0 * g_perp + g_parallel
182
+
183
+ elif optimize_num > self.APPLY_CI_NEB and (i + 1 in local_max_energy_list_index or i - 1 in local_max_energy_list_index) and (i != 1 and i != nnode-2):
184
+ # Restrict step for neighbors of TS (as in original code)
185
+ print(f"Restrict step of # NODE {i} for CI-NEB")
186
+ force *= 0.001
187
+
188
+ total_force_list.append(force.reshape(geometry_num_list[i].shape))
189
+
190
+ total_force_list = np.array(total_force_list, dtype="float64")
191
+
192
+ # Note: Original code applied a global 'projection' here.
193
+ # Since we explicitly projected using Ayala tangents inside the loop,
194
+ # applying another Gram-Schmidt based on simple neighbor differences might be redundant or conflicting.
195
+ # However, if the original 'projection' function handles constraints other than the path tangent
196
+ # (like removing rotation/translation), it might still be needed.
197
+ # Assuming 'projection' in the original snippet was purely for path orthogonality:
198
+ # We DO NOT call the global 'projection' function here to strictly follow the Ayala tangent method.
199
+
200
+ return total_force_list
201
+
202
+ def calc_proj_hess(self, hess, node_num, geometry_num_list):
203
+ """
204
+ Project the Hessian using the cached Ayala tangent.
205
+ P = I - |tau><tau|
206
+ H_proj = P * H * P
207
+ """
208
+ # Ensure tangents are available (calc_force should be called before this)
209
+ if len(self.tau_list) == 0:
210
+ # Fallback or error handling if calc_force wasn't called.
211
+ # For safety, we return original hess, or one needs to calculate tangents here using stored energies.
212
+ # Assuming usage pattern: calc_force -> opt step -> (optional) calc_hess
213
+ print("Warning: Tangent list empty in calc_proj_hess. Returning original Hessian.")
214
+ return hess
215
+
216
+ if node_num == 0 or node_num == len(geometry_num_list)-1:
217
+ return hess
218
+
219
+ print(f"Applying Ayala tangent projection to Hessian at node {node_num}")
220
+
221
+ tangent = self.tau_list[node_num].flatten()
222
+
223
+ # Make Projector P = I - t * t.T
224
+ dim = len(tangent)
225
+ identity = np.eye(dim)
226
+ projector = identity - np.outer(tangent, tangent)
227
+
228
+ # H_proj = P . H . P
229
+ # Note: hess is likely (3N, 3N)
230
+ tmp_proj_hess = np.dot(np.dot(projector, hess), projector.T)
231
+
232
+ # Ensure symmetry
233
+ tmp_proj_hess = 0.5 * (tmp_proj_hess + tmp_proj_hess.T)
234
+
235
+ return tmp_proj_hess
236
+
237
+ def get_tau(self, node_num):
238
+ """Returns the flattened tangent vector at the specified node."""
239
+ if len(self.tau_list) == 0:
240
+ raise ValueError("Tangent list is empty. Calculate forces first.")
241
+ return self.tau_list[node_num]
242
+
243
+ def calculate_gamma(self, q_triplet, E_triplet, g_triplet, tangent):
244
+ """
245
+ Calculates the curvature gamma along the path using quintic polynomial fitting.
246
+
247
+ Args:
248
+ q_triplet: List of [q_prev, q_curr, q_next] coordinates
249
+ E_triplet: List of [E_prev, E_curr, E_next] energies
250
+ g_triplet: List of [g_prev, g_curr, g_next] gradients
251
+ tangent: Normalized tangent vector at the current node
252
+
253
+ Returns:
254
+ gamma: Curvature (2nd derivative) along the path at the current node
255
+ """
256
+ q_prev, q_curr, q_next = q_triplet
257
+ E_prev, E_curr, E_next = E_triplet
258
+ g_prev, g_curr, g_next = g_triplet
259
+
260
+ # 1. Distances along the path
261
+ dist_prev = np.linalg.norm(q_curr - q_prev)
262
+ dist_next = np.linalg.norm(q_next - q_curr)
263
+
264
+ if dist_prev < 1e-6 or dist_next < 1e-6:
265
+ return 0.0
266
+
267
+ # s coordinates: prev at -dist_prev, curr at 0, next at +dist_next
268
+ s_p = -dist_prev
269
+ s_c = 0.0
270
+ s_n = dist_next
271
+
272
+ # 2. Project gradients onto path
273
+ # Tangent at i-1: Approximated by direction from i-1 to i
274
+ t_prev = (q_curr - q_prev) / dist_prev
275
+ gp_proj = np.dot(g_prev.flatten(), t_prev.flatten())
276
+
277
+ # Tangent at i: Given tangent
278
+ gc_proj = np.dot(g_curr.flatten(), tangent.flatten())
279
+
280
+ # Tangent at i+1: Approximated by direction from i to i+1
281
+ t_next = (q_next - q_curr) / dist_next
282
+ gn_proj = np.dot(g_next.flatten(), t_next.flatten())
283
+
284
+ # 3. Solve Quintic Polynomial Coefficients
285
+ # E(s) = c0 + c1*s + c2*s^2 + c3*s^3 + c4*s^4 + c5*s^5
286
+ A = np.array([
287
+ [1, s_p, s_p**2, s_p**3, s_p**4, s_p**5],
288
+ [1, s_c, s_c**2, s_c**3, s_c**4, s_c**5],
289
+ [1, s_n, s_n**2, s_n**3, s_n**4, s_n**5],
290
+ [0, 1, 2*s_p, 3*s_p**2, 4*s_p**3, 5*s_p**4],
291
+ [0, 1, 2*s_c, 3*s_c**2, 4*s_c**3, 5*s_c**4],
292
+ [0, 1, 2*s_n, 3*s_n**2, 4*s_n**3, 5*s_n**4]
293
+ ])
294
+
295
+ b = np.array([E_prev, E_curr, E_next, gp_proj, gc_proj, gn_proj])
296
+
297
+ try:
298
+ coeffs = np.linalg.solve(A, b)
299
+ # Curvature gamma = E''(0) = 2 * c2
300
+ gamma = 2.0 * coeffs[2]
301
+ return gamma
302
+ except np.linalg.LinAlgError:
303
+ # Fallback for singular matrix
304
+ return 0.0
@@ -0,0 +1,7 @@
1
+ from .seam_model_function import SeamModelFunction
2
+ from .avoiding_model_function import AvoidingModelFunction
3
+ from .binary_image_ts_search_model_function import BITSSModelFunction
4
+ from .conical_model_function import ConicalModelFunction
5
+ from .opt_mesx import OptMESX
6
+ from .opt_mesx_2 import OptMESX2
7
+ from .opt_meci import OptMECI
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+
3
+ class AvoidingModelFunction:
4
+ def __init__(self):
5
+ #ref.: Advances in Physical Chemistry 2012, 2012, 1-13.
6
+ self.alpha = 0.01
7
+ return
8
+
9
+ def calc_energy(self, energy_1, energy_2):
10
+ U = self.alpha / 2.0 * np.exp(-1 * (energy_1 - energy_2) ** 2 / self.alpha)
11
+ tot_energy = 0.5 * (energy_1 + energy_2) + 0.5 * np.sqrt((energy_1 - energy_2) ** 2 + 4.0 * U)
12
+ return tot_energy
13
+
14
+ def calc_grad(self, energy_1, energy_2, grad_1, grad_2):
15
+ b = np.exp(-1 * (energy_1 - energy_2) ** 2 / self.alpha)
16
+ U = self.alpha / 2.0 * b
17
+ a = np.sqrt((energy_1 - energy_2) ** 2 + 4.0 * U)
18
+ dU_dq1 = -1 * (energy_1 - energy_2) * grad_1 * b
19
+ dU_dq2 = (energy_1 - energy_2) * grad_2 * b
20
+
21
+ smf_grad_1 = 0.5 * (grad_1 + grad_2) + 0.5 * (1.0 /a) * ( 2.0 * (energy_1 - energy_2) * (grad_1) + 8.0 * U * dU_dq1) + 0.5 * (1.0 /a) * (-2.0 * (energy_1 - energy_2) * (grad_2) + 8.0 * U * dU_dq2)
22
+ smf_grad_2 = 0.5 * (grad_1 + grad_2) + 0.5 * (1.0 /a) * ( 2.0 * (energy_1 - energy_2) * (grad_1) + 8.0 * U * dU_dq1) + 0.5 * (1.0 /a) * (-2.0 * (energy_1 - energy_2) * (grad_2) + 8.0 * U * dU_dq2)
23
+
24
+ return smf_grad_1, smf_grad_2
25
+
26
+ def calc_hess(self, energy_1, energy_2, grad_1, grad_2, hess_1, hess_2):
27
+
28
+
29
+ return
@@ -0,0 +1,47 @@
1
+ import numpy as np
2
+
3
+ #J. Chem. Phys. 157, 124107 (2022)
4
+ #https://doi.org/10.1063/5.0102145
5
+
6
+ class BITSSModelFunction:
7
+ def __init__(self, geom_num_list_1, geom_num_list_2):
8
+ self.f = 0.5
9
+ self.alpha = 10.0
10
+ self.beta = 0.1
11
+ self.d = np.linalg.norm(geom_num_list_1 - geom_num_list_2)
12
+
13
+ return
14
+
15
+ def calc_energy(self, energy_1, energy_2, geom_num_list_1, geom_num_list_2, gradient_1, gradient_2, iter):
16
+ current_distance = np.linalg.norm(geom_num_list_1 - geom_num_list_2)
17
+ if iter % 500 == 0:
18
+
19
+ self.E_B = abs(energy_1 - energy_2)
20
+ self.kappa_e = self.alpha / (2.0 * self.E_B + 1e-10)
21
+
22
+ unit_vec = (geom_num_list_1 - geom_num_list_2) / current_distance
23
+
24
+
25
+
26
+ proj_grad_1 = gradient_1 * unit_vec * (-1)
27
+ proj_grad_2 = gradient_2 * unit_vec
28
+
29
+ a = np.sqrt(np.linalg.norm(proj_grad_1) + np.linalg.norm(proj_grad_2)) / (2 ** 1.5 * self.beta * self.d + 1e-10)
30
+ b = self.E_B / (self.beta * self.d ** 2 + 1e-10)
31
+ self.kappa_d = max(a, b)
32
+ self.d = np.linalg.norm(geom_num_list_1 - geom_num_list_2)
33
+
34
+ self.d = max((1.0 - self.f) * self.d, 1e-10)
35
+ energy = energy_1 + energy_2 + self.kappa_e * (energy_1 + energy_2) ** 2 + self.kappa_d * (current_distance - self.d) ** 2
36
+
37
+ return energy
38
+
39
+ def calc_grad(self, energy_1, energy_2, geom_num_list_1, geom_num_list_2, gradient_1, gradient_2):
40
+ current_vec = geom_num_list_1 - geom_num_list_2
41
+ current_dist = np.linalg.norm(current_vec) + 1e-10
42
+
43
+ bitss_grad_1 = gradient_1 + gradient_2 + 2.0 * self.kappa_e * (energy_1 - energy_2) * (gradient_1 - gradient_2) + current_vec * 2.0 * self.kappa_d * (current_dist - self.d) / current_dist
44
+
45
+ bitss_grad_2 = gradient_1 + gradient_2 + 2.0 * self.kappa_e * (energy_1 - energy_2) * (gradient_1 - gradient_2) - current_vec * 2.0 * self.kappa_d * (current_dist - self.d) / current_dist
46
+
47
+ return bitss_grad_1, bitss_grad_2
@@ -0,0 +1,26 @@
1
+ import numpy as np
2
+
3
+
4
+ class ConicalModelFunction:
5
+ def __init__(self):
6
+ #ref.: J. Phys. Chem. B 2008, 112, 2, 405–413
7
+ self.alpha = 0.025
8
+ self.sigma = 3.5
9
+ return
10
+
11
+ def calc_energy(self, energy_1, energy_2):
12
+ delta_ene = energy_1 - energy_2
13
+
14
+ tot_energy = 0.5 * (energy_1 + energy_2) + self.sigma * delta_ene ** 2 / (delta_ene + self.alpha)
15
+ return tot_energy
16
+
17
+ def calc_grad(self, energy_1, energy_2, grad_1, grad_2):
18
+ delta_ene = energy_1 - energy_2
19
+ mf_grad_1 = 0.5 * (grad_1) + 0.5 * (grad_2) + self.sigma * (delta_ene ** 2.0 + 2.0 * self.alpha * delta_ene) / (delta_ene + self.alpha) ** 2.0 * (grad_1 - grad_2)
20
+ mf_grad_2 = 0.5 * (grad_1) + 0.5 * (grad_2) + self.sigma * (delta_ene ** 2.0 + 2.0 * self.alpha * delta_ene) / (delta_ene + self.alpha) ** 2.0 * (grad_1 - grad_2)
21
+ return mf_grad_1, mf_grad_2
22
+
23
+ def calc_hess(self, energy_1, energy_2, grad_1, grad_2, hess_1, hess_2):
24
+
25
+
26
+ return
@@ -0,0 +1,50 @@
1
+ import numpy as np
2
+
3
+ class OptMECI:
4
+ def __init__(self):
5
+ # ref.:https://doi.org/10.1021/ct1000268
6
+
7
+ self.switch_threshold = 5e-4
8
+ self.alpha = 1e-3
9
+ self.approx_cdv_vec = None
10
+ self.prev_dgv_vec = None
11
+ self.dgv_vec = None
12
+
13
+ return
14
+
15
+ def calc_energy(self, energy_1, energy_2):
16
+ tot_energy = (energy_1 + energy_2) / 2.0
17
+ print("energy_1:", energy_1, "hartree")
18
+ print("energy_2:", energy_2, "hartree")
19
+ print("energy_1 - energy_2:", abs(energy_1 - energy_2), "hartree")
20
+ return tot_energy
21
+
22
+ def calc_grad(self, energy_1, energy_2, grad_1, grad_2):
23
+ if self.approx_cdv_vec is None:
24
+ self.approx_cdv_vec = np.ones((len(grad_1)*3, 1))
25
+
26
+ delta_grad = grad_1 - grad_2
27
+ dgv_vec = delta_grad / np.linalg.norm(delta_grad)
28
+ dgv_vec = dgv_vec.reshape(-1, 1)
29
+
30
+ if self.prev_dgv_vec is None:
31
+ self.prev_dgv_vec = dgv_vec
32
+
33
+ self.approx_cdv_vec = (np.dot(self.approx_cdv_vec.T, dgv_vec) * self.prev_dgv_vec -1 * np.dot(self.prev_dgv_vec.T, dgv_vec) * self.approx_cdv_vec) / np.sqrt(np.dot(self.approx_cdv_vec.T, dgv_vec) ** 2 + np.dot(self.prev_dgv_vec.T, dgv_vec) ** 2)
34
+
35
+ P_matrix = np.eye((len(dgv_vec))) -1 * np.dot(dgv_vec, dgv_vec.T) -1 * np.dot(self.approx_cdv_vec, self.approx_cdv_vec.T)
36
+ P_matrix = 0.5 * (P_matrix + P_matrix.T)
37
+ gp_grad = 2 * (energy_1 - energy_2) * dgv_vec + np.dot(P_matrix, 0.5 * (grad_1.reshape(-1, 1) + grad_2.reshape(-1, 1)))
38
+
39
+ self.prev_dgv_vec = dgv_vec
40
+ gp_grad = gp_grad.reshape(len(grad_1), 3)
41
+ return gp_grad
42
+
43
+
44
+ def calc_hess(self, hess_1, hess_2):
45
+ mean_hess = 0.5 * (hess_1 + hess_2)
46
+ P_matrix = np.eye((len(self.prev_dgv_vec))) -1 * np.dot(self.prev_dgv_vec, self.prev_dgv_vec.T) -1 * np.dot(self.approx_cdv_vec, self.approx_cdv_vec.T)
47
+ P_matrix = 0.5 * (P_matrix + P_matrix.T)
48
+
49
+ gp_hess = np.dot(P_matrix, np.dot(mean_hess, P_matrix))
50
+ return gp_hess