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,185 @@
1
+ import numpy as np
2
+ import copy
3
+
4
+ from multioptpy.Parameters.parameter import UnitValueLib, atomic_mass
5
+
6
+
7
+ class Thermostat:
8
+ def __init__(self, momentum_list, temperature, pressure, element_list=[]):
9
+
10
+ self.momentum_list = momentum_list #list
11
+
12
+ self.temperature = temperature #K
13
+ self.initial_temperature = temperature #K
14
+ self.pressure = pressure * (3.39893 * 10 ** (-11)) #kPa -> a.u.
15
+ self.initial_pressure = pressure * (3.39893 * 10 ** (-11)) #kPa -> a.u.
16
+
17
+ self.Langevin_zeta = 0.01
18
+ self.zeta = 0.0
19
+ self.eta = 0.0
20
+ self.scaling = 1.0
21
+ self.Ps_momentum = 0.0
22
+
23
+ self.g_value = len(momentum_list) * 3
24
+ self.Q_value = 1e-1
25
+
26
+
27
+ self.M_value = 1e+12
28
+ self.Boltzmann_constant = 3.16681 * 10 ** (-6) # hartree/K
29
+ self.delta_timescale = 1e-1
30
+ self.volume = 1e-23 * (1/UnitValueLib().bohr2m) ** 3#m^3 -> Bohr^3
31
+
32
+ # Nose-Hoover-chain
33
+ self.Q_value_chain = [1.0, 2.0, 3.0, 6.0, 10.0, 20, 40, 50, 100, 200]#mass of thermostat
34
+ self.zeta_chain = [0.0 for i in range(len(self.Q_value_chain))]
35
+ self.timestep = None
36
+
37
+ self.Instantaneous_temperatures_list = []
38
+ self.Instantaneous_momentum_list = []
39
+
40
+ self.element_list = element_list
41
+ return
42
+
43
+
44
+ def calc_tot_kinetic_energy(self):
45
+ tot_kinetic_ene = 0.0
46
+
47
+ for i, elem in enumerate(self.element_list):
48
+ tot_kinetic_ene += (np.sum(self.momentum_list[i] ** 2) /(2 * atomic_mass(elem)))
49
+ self.tot_kinetic_ene = tot_kinetic_ene
50
+ return tot_kinetic_ene
51
+
52
+ def calc_inst_temperature(self):
53
+ #temperature
54
+ tot_kinetic_ene = self.calc_tot_kinetic_energy()
55
+ Instantaneous_temperature = 2 * tot_kinetic_ene / (self.g_value * self.Boltzmann_constant)
56
+ print("Instantaneous_temperature: ",Instantaneous_temperature ," K")
57
+
58
+ self.Instantaneous_temperature = Instantaneous_temperature
59
+ #-----------------
60
+ return Instantaneous_temperature
61
+
62
+ def add_inst_temperature_list(self):
63
+ #self.add_inst_temperature_list()
64
+ self.Instantaneous_temperatures_list.append(self.Instantaneous_temperature)
65
+
66
+
67
+ def Nose_Hoover_thermostat(self, geom_num_list, new_g):#fixed volume #NVT ensemble
68
+ new_g *= -1
69
+ self.momentum_list = self.momentum_list * np.exp(-self.delta_timescale * self.zeta * 0.5)
70
+
71
+ self.momentum_list += new_g * self.delta_timescale * 0.5
72
+ print("NVT ensemble (Nose_Hoover) : Sum of momenta (absolute value):", np.sum(np.abs(self.momentum_list)))
73
+ tmp_list = []
74
+ for i, elem in enumerate(self.element_list):
75
+ tmp_list.append(self.delta_timescale * self.momentum_list[i] / atomic_mass(elem))
76
+
77
+ new_geometry = geom_num_list + tmp_list
78
+ #------------
79
+ self.calc_inst_temperature()
80
+ self.add_inst_temperature_list()
81
+ #----------
82
+ self.zeta += self.delta_timescale * (2 * self.tot_kinetic_ene - self.g_value * self.Boltzmann_constant * self.initial_temperature) / self.Q_value
83
+
84
+ #print(tmp_value, self.g_value * self.Boltzmann_constant * self.temperature)
85
+
86
+
87
+ self.momentum_list += new_g * self.delta_timescale * 0.5
88
+ self.momentum_list = self.momentum_list * np.exp(-self.delta_timescale * self.zeta * 0.5)
89
+
90
+
91
+ return new_geometry
92
+
93
+ def Nose_Hoover_chain_thermostat(self, geom_num_list, new_g):#fixed volume #NVT ensemble
94
+ #ref. J. Chem. Phys. 97, 2635-2643 (1992)
95
+ new_g *= -1
96
+ self.momentum_list = self.momentum_list * np.exp(-self.delta_timescale * self.zeta_chain[0] * 0.5)
97
+
98
+ self.momentum_list += new_g * self.delta_timescale * 0.5
99
+ print("NVT ensemble (Nose_Hoover chain) : Sum of momenta (absolute value):", np.sum(np.abs(self.momentum_list)))
100
+
101
+ tmp_list = []
102
+ for i, elem in enumerate(self.element_list):
103
+ tmp_list.append(self.delta_timescale * self.momentum_list[i] / atomic_mass(elem))
104
+
105
+ new_geometry = geom_num_list + tmp_list
106
+ #------------
107
+ self.calc_inst_temperature()
108
+ self.add_inst_temperature_list()
109
+ #----------
110
+ self.zeta_chain[0] += self.delta_timescale * (2 * self.tot_kinetic_ene - self.g_value * self.Boltzmann_constant * self.initial_temperature) / self.Q_value_chain[0] -1* self.delta_timescale * (self.zeta_chain[0] * self.zeta_chain[1])
111
+
112
+ for j in range(1, len(self.zeta_chain)-1):
113
+ self.zeta_chain[j] += self.delta_timescale * (self.Q_value_chain[j-1]*self.zeta_chain[j-1]**2 - self.Boltzmann_constant * self.initial_temperature) / self.Q_value_chain[j] -1* self.delta_timescale * (self.zeta_chain[j] * self.zeta_chain[j+1])
114
+
115
+ self.zeta_chain[-1] += self.delta_timescale * (self.Q_value_chain[-2]*self.zeta_chain[-2]**2 -1*self.Boltzmann_constant * self.initial_temperature) / self.Q_value_chain[-1]
116
+
117
+ #print(tmp_value, self.g_value * self.Boltzmann_constant * self.temperature)
118
+
119
+
120
+ self.momentum_list += new_g * self.delta_timescale * 0.5
121
+ self.momentum_list = self.momentum_list * np.exp(-self.delta_timescale * self.zeta_chain[0] * 0.5)
122
+ print("zeta_list (Coefficient of friction): ", self.zeta_chain)
123
+ return new_geometry
124
+
125
+ def Velocity_Verlet(self, geom_num_list, new_g, prev_g, iter):#NVE ensemble
126
+ tmp_new_g = copy.copy(-1*new_g)
127
+ tmp_prev_g = copy.copy(-1*prev_g)
128
+ #print("NVE ensemble (Velocity_Verlet)")
129
+ self.momentum_list += ( tmp_new_g + tmp_prev_g ) * (self.delta_timescale) * 0.5 #+ third_term + fourth_term
130
+ #-----------
131
+ tmp_list = []
132
+ for i, elem in enumerate(self.element_list):
133
+ tmp_list.append(self.delta_timescale * self.momentum_list[i] / atomic_mass(elem) + self.delta_timescale ** 2 * tmp_new_g[i] / (2.0 * atomic_mass(elem)))
134
+ new_geometry = geom_num_list + tmp_list
135
+ #------------
136
+ self.calc_inst_temperature()
137
+ self.add_inst_temperature_list()
138
+ #-------------
139
+
140
+ return new_geometry
141
+
142
+
143
+
144
+ def generate_normal_random_variables(self, n_variables):
145
+ random_variables = []
146
+ for _ in range(n_variables // 2):
147
+ u1, u2 = np.random.rand(2)
148
+ #Box-Muller method
149
+ z1 = np.sqrt(-2 * np.log(u1)) * np.cos(2 * np.pi * u2)
150
+ z2 = np.sqrt(-2 * np.log(u1)) * np.sin(2 * np.pi * u2)
151
+ random_variables.extend([z1, z2])
152
+
153
+ if n_variables % 2 == 1:
154
+ u1, u2 = np.random.rand(2)
155
+ z1 = np.sqrt(-2 * np.log(u1)) * np.cos(2 * np.pi * u2)
156
+ random_variables.append(z1)
157
+
158
+ return np.array([random_variables], dtype="float64")
159
+
160
+ def calc_rand_moment_based_on_boltzman_const(self, random_variables):
161
+ rand_moment = random_variables
162
+
163
+ for i in range(len(self.element_list)):
164
+ random_variables[i] *= np.sqrt(self.Boltzmann_constant * self.temperature / atomic_mass(self.element_list[i]))
165
+
166
+
167
+ return rand_moment
168
+
169
+
170
+ def init_purtubation(self, geometry, B_e, B_g):
171
+ random_variables = self.generate_normal_random_variables(len(self.element_list)*3).reshape(len(self.element_list), 3)
172
+
173
+ addtional_velocity = self.calc_rand_moment_based_on_boltzman_const(random_variables) # velocity
174
+ init_momentum = addtional_velocity * 0.0
175
+
176
+ for i in range(len(self.element_list)):
177
+ init_momentum[i] += addtional_velocity[i] * atomic_mass(self.element_list[i])
178
+
179
+
180
+ self.momentum_list += init_momentum
181
+ self.init_energy = B_e
182
+ #self.init_hamiltonian = B_e
183
+ #for i, elem in enumerate(element_list):
184
+ # self.init_hamiltonian += (np.sum(self.momentum_list[i]) ** 2 / (2 * atomic_mass(elem)))
185
+ return
File without changes
@@ -0,0 +1,443 @@
1
+ import numpy as np
2
+ import copy
3
+ from multioptpy.Coordinate.redundant_coordinate import calc_int_grad_from_pBmat, calc_cart_grad_from_pBmat
4
+ from scipy.signal import argrelextrema
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
+
20
+
21
+ class CaluculationBNEB():# Wilson's B-matrix-constrained NEB
22
+ def __init__(self, APPLY_CI_NEB=99999):
23
+ self.APPLY_CI_NEB = APPLY_CI_NEB
24
+ return
25
+
26
+ def calc_ci_neb_force(self, grad, tangent_grad):
27
+ #ref.: J. Chem. Phys. 113, 9901–9904 (2000)
28
+ #ref.: J. Chem. Phys. 142, 024106 (2015)
29
+ #available for optimizer using only first order differential
30
+ ci_force = -2.0 * tangent_grad
31
+ return ci_force
32
+
33
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
34
+ print("BNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEB")
35
+ nnode = len(energy_list)
36
+ self.tau_list = []
37
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
38
+ total_force_list = []
39
+ for i in range(nnode):
40
+ if i == 0:
41
+ total_force_list.append(-1*np.array(gradient_list[0], dtype = "float64"))
42
+ self.tau_list.append(np.zeros_like(gradient_list[0]).reshape(-1, 3))
43
+ continue
44
+ elif i == nnode-1:
45
+ total_force_list.append(-1*np.array(gradient_list[nnode-1], dtype = "float64"))
46
+ self.tau_list.append(np.zeros_like(gradient_list[nnode-1]).reshape(-1, 3))
47
+ continue
48
+ tmp_grad = copy.copy(gradient_list[i]).reshape(-1, 1)
49
+ 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])
50
+ 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):
51
+ force *= 0.001
52
+ print("Restrect step of # NODE", i, " for CI-NEB")
53
+ elif optimize_num > self.APPLY_CI_NEB and (i in local_max_energy_list_index) and (i != 1 or i != nnode-2):
54
+ force = self.calc_ci_neb_force(tmp_grad, tangent_grad)
55
+ print("CI-NEB was applied to # NODE", i)
56
+ else:
57
+ pass
58
+
59
+ total_force_list.append(-1*force.reshape(-1, 3))
60
+ self.tau_list.append(tangent_grad.reshape(-1, 3))
61
+
62
+ total_force_list = np.array(total_force_list, dtype = "float64")
63
+
64
+
65
+ return total_force_list
66
+
67
+ def calc_project_out_grad(self, coord_1, coord_2, coord_3, grad_2, energy_list):# grad: (3N, 1), geom_num_list: (N, 3)
68
+ natom = len(coord_2)
69
+ tmp_grad = copy.copy(grad_2)
70
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
71
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
72
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
73
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
74
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
75
+ tangent_grad = projection_grad
76
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
77
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
78
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
79
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
80
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
81
+ tangent_grad = projection_grad
82
+ else:
83
+ B_mat_plus = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
84
+ B_mat_minus = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
85
+ int_grad_plus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_plus)
86
+ int_grad_minus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_minus)
87
+ max_ene = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
88
+ min_ene = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
89
+ a = (max_ene) / (max_ene + min_ene + 1e-8)
90
+ b = (min_ene) / (max_ene + min_ene + 1e-8)
91
+
92
+ if energy_list[0] < energy_list[2]:
93
+ projection_grad_plus = calc_cart_grad_from_pBmat(-a*int_grad_plus, B_mat_plus)
94
+ projection_grad_minus = calc_cart_grad_from_pBmat(-b*int_grad_minus, B_mat_minus)
95
+
96
+ else:
97
+ projection_grad_plus = calc_cart_grad_from_pBmat(-b*int_grad_plus, B_mat_plus)
98
+ projection_grad_minus = calc_cart_grad_from_pBmat(-a*int_grad_minus, B_mat_minus)
99
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad_plus + projection_grad_minus
100
+ tangent_grad = projection_grad_plus + projection_grad_minus
101
+ return proj_grad, tangent_grad
102
+
103
+
104
+ def calc_B_matrix_for_NEB_tangent(self, coord_1, coord_2):
105
+ natom = len(coord_2)
106
+ B_mat = np.zeros((natom, 3*natom))
107
+
108
+ for i in range(natom):
109
+ norm_12 = np.linalg.norm(coord_1[i] - coord_2[i]) + 1e-15
110
+ dr12_dx2 = (coord_2[i][0] - coord_1[i][0]) / norm_12
111
+ dr12_dy2 = (coord_2[i][1] - coord_1[i][1]) / norm_12
112
+ dr12_dz2 = (coord_2[i][2] - coord_1[i][2]) / norm_12
113
+ B_mat[i][3*i] = dr12_dx2
114
+ B_mat[i][3*i+1] = dr12_dy2
115
+ B_mat[i][3*i+2] = dr12_dz2
116
+
117
+ return B_mat
118
+
119
+ def projection_hessian(self, coord_1, coord_2, coord_3, gradient_list, hessian_2, energy_list):
120
+ #ref.: J. Chem. Theory. Comput. 2013, 9, 3498−3504
121
+ natom = len(coord_2)
122
+ gradient_2 = gradient_list[1].reshape(-1, 1)
123
+ gradient_1 = gradient_list[0].reshape(-1, 1)
124
+ gradient_3 = gradient_list[2].reshape(-1, 1)
125
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
126
+ tangent = coord_3.reshape(-1, 1) - coord_2.reshape(-1, 1)
127
+ grad_tangent = np.dot(np.eye(3*natom, k=1) - np.eye(3*natom, k=0), np.ones((3*natom, 3*natom)))
128
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
129
+ tangent = coord_2.reshape(-1, 1) - coord_1.reshape(-1, 1)
130
+
131
+ grad_tangent = np.dot(np.eye(3*natom, k=0) - np.eye(3*natom, k=-1), np.ones((3*natom, 3*natom)))
132
+ else:
133
+ ene_max = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
134
+ ene_min = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
135
+ tangent_plus = coord_3.reshape(-1, 1) - coord_2.reshape(-1, 1)
136
+ tangent_minus = coord_2.reshape(-1, 1) - coord_1.reshape(-1, 1)
137
+ if energy_list[0] < energy_list[2]:
138
+ tangent = tangent_plus * ene_max + tangent_minus * ene_min
139
+ else:
140
+ tangent = tangent_plus * ene_min + tangent_minus * ene_max
141
+
142
+ a = np.linalg.norm(coord_3 - coord_2)
143
+ b = np.linalg.norm(coord_2 - coord_1)
144
+ grad_a = np.sign(energy_list[2] - energy_list[1]) * (np.dot(np.eye(3*natom, k=1), gradient_3) - np.dot(np.eye(3*natom, k=0), gradient_2))
145
+ grad_b = np.sign(energy_list[0] - energy_list[1]) * (np.dot(np.eye(3*natom, k=-1), gradient_1) - np.dot(np.eye(3*natom, k=0), gradient_2))
146
+ grad_tangent = np.dot((a * np.eye(3*natom, k=1) + (b - a) * np.eye(3*natom, k=0) - b * np.eye(3*natom, k=-1)), np.ones((3*natom, 3*natom))) + np.dot(tangent_plus, grad_a.T) + np.dot(tangent_minus, grad_b.T)
147
+
148
+
149
+ unit_tangent = tangent / (np.linalg.norm(tangent) + 1e-15)
150
+ A = np.sum(gradient_2 * unit_tangent) * np.ones((3*natom, 3*natom)) + np.dot(unit_tangent, gradient_2.T) * (np.ones((3*natom, 3*natom)) - np.dot(unit_tangent, unit_tangent.T)) / (np.linalg.norm(tangent) + 1e-15)
151
+ hessian_2 = hessian_2 -1 * np.dot(unit_tangent, np.dot(hessian_2, unit_tangent).T) + np.dot(A, grad_tangent)
152
+ return hessian_2
153
+
154
+
155
+ def get_tau(self, node_num):
156
+ """Returns the flattened tangent vector at the specified node."""
157
+ if len(self.tau_list) == 0:
158
+ raise ValueError("Tangent list is empty. Calculate forces first.")
159
+ return self.tau_list[node_num]
160
+
161
+ def calculate_gamma(self, q_triplet, E_triplet, g_triplet, tangent):
162
+ """
163
+ Calculates the curvature gamma along the path using quintic polynomial fitting.
164
+
165
+ Args:
166
+ q_triplet: List of [q_prev, q_curr, q_next] coordinates
167
+ E_triplet: List of [E_prev, E_curr, E_next] energies
168
+ g_triplet: List of [g_prev, g_curr, g_next] gradients
169
+ tangent: Normalized tangent vector at the current node
170
+
171
+ Returns:
172
+ gamma: Curvature (2nd derivative) along the path at the current node
173
+ """
174
+ q_prev, q_curr, q_next = q_triplet
175
+ E_prev, E_curr, E_next = E_triplet
176
+ g_prev, g_curr, g_next = g_triplet
177
+
178
+ # 1. Distances along the path
179
+ dist_prev = np.linalg.norm(q_curr - q_prev)
180
+ dist_next = np.linalg.norm(q_next - q_curr)
181
+
182
+ if dist_prev < 1e-6 or dist_next < 1e-6:
183
+ return 0.0
184
+
185
+ # s coordinates: prev at -dist_prev, curr at 0, next at +dist_next
186
+ s_p = -dist_prev
187
+ s_c = 0.0
188
+ s_n = dist_next
189
+
190
+ # 2. Project gradients onto path
191
+ # Tangent at i-1: Approximated by direction from i-1 to i
192
+ t_prev = (q_curr - q_prev) / dist_prev
193
+ gp_proj = np.dot(g_prev.flatten(), t_prev.flatten())
194
+
195
+ # Tangent at i: Given tangent
196
+ gc_proj = np.dot(g_curr.flatten(), tangent.flatten())
197
+
198
+ # Tangent at i+1: Approximated by direction from i to i+1
199
+ t_next = (q_next - q_curr) / dist_next
200
+ gn_proj = np.dot(g_next.flatten(), t_next.flatten())
201
+
202
+ # 3. Solve Quintic Polynomial Coefficients
203
+ # E(s) = c0 + c1*s + c2*s^2 + c3*s^3 + c4*s^4 + c5*s^5
204
+ A = np.array([
205
+ [1, s_p, s_p**2, s_p**3, s_p**4, s_p**5],
206
+ [1, s_c, s_c**2, s_c**3, s_c**4, s_c**5],
207
+ [1, s_n, s_n**2, s_n**3, s_n**4, s_n**5],
208
+ [0, 1, 2*s_p, 3*s_p**2, 4*s_p**3, 5*s_p**4],
209
+ [0, 1, 2*s_c, 3*s_c**2, 4*s_c**3, 5*s_c**4],
210
+ [0, 1, 2*s_n, 3*s_n**2, 4*s_n**3, 5*s_n**4]
211
+ ])
212
+
213
+ b = np.array([E_prev, E_curr, E_next, gp_proj, gc_proj, gn_proj])
214
+
215
+ try:
216
+ coeffs = np.linalg.solve(A, b)
217
+ # Curvature gamma = E''(0) = 2 * c2
218
+ gamma = 2.0 * coeffs[2]
219
+ return gamma
220
+ except np.linalg.LinAlgError:
221
+ # Fallback for singular matrix
222
+ return 0.0
223
+
224
+
225
+
226
+ class CaluculationBNEB2():# Wilson's B-matrix-constrained NEB
227
+ def __init__(self, APPLY_CI_NEB=99999):
228
+ return
229
+
230
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
231
+ print("BNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEB")
232
+ nnode = len(energy_list)
233
+ total_force_list = []
234
+ for i in range(nnode):
235
+ if i == 0:
236
+ total_force_list.append(-1*np.array(gradient_list[0], dtype = "float64"))
237
+ continue
238
+ elif i == nnode-1:
239
+ total_force_list.append(-1*np.array(gradient_list[nnode-1], dtype = "float64"))
240
+ continue
241
+ tmp_grad = copy.copy(gradient_list[i]).reshape(-1, 1)
242
+ force = self.calc_project_out_grad(geometry_num_list[i-1], geometry_num_list[i], geometry_num_list[i+1], tmp_grad)
243
+ total_force_list.append(-1*force)
244
+ return np.array(total_force_list, dtype = "float64")
245
+
246
+ def calc_project_out_grad(self, coord_1, coord_2, coord_3, grad_2):# grad: (3N, 1), geom_num_list: (N, 3)
247
+ natom = len(coord_2)
248
+ tmp_grad = copy.copy(grad_2)
249
+
250
+ B_mat = self.calc_B_matrix_for_NEB_1st_stage(coord_1, coord_2, coord_3)
251
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
252
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
253
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
254
+
255
+ B_mat = self.calc_B_matrix_for_NEB_2nd_stage(coord_1, coord_3)
256
+ int_grad = calc_int_grad_from_pBmat(proj_grad, B_mat)
257
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
258
+ proj_grad = proj_grad + projection_grad
259
+ proj_grad = proj_grad.reshape(natom, 3)
260
+
261
+ return proj_grad
262
+
263
+
264
+ def calc_B_matrix_for_NEB_1st_stage(self, coord_1, coord_2, coord_3):
265
+ natom = len(coord_2)
266
+ B_mat = np.zeros((2*natom, 3*natom))
267
+
268
+ for i in range(natom):
269
+ norm_12 = np.linalg.norm(coord_1[i] - coord_2[i]) + 1e-15
270
+ dr12_dx2 = (coord_1[i][0] - coord_2[i][0]) / norm_12
271
+ dr12_dy2 = (coord_1[i][1] - coord_2[i][1]) / norm_12
272
+ dr12_dz2 = (coord_1[i][2] - coord_2[i][2]) / norm_12
273
+ B_mat[i][3*i] = dr12_dx2
274
+ B_mat[i][3*i+1] = dr12_dy2
275
+ B_mat[i][3*i+2] = dr12_dz2
276
+
277
+ for i in range(natom):
278
+ norm_23 = np.linalg.norm(coord_2[i] - coord_3[i]) + 1e-15
279
+ dr32_dx2 = (coord_3[i][0] - coord_2[i][0]) / norm_23
280
+ dr32_dy2 = (coord_3[i][1] - coord_2[i][1]) / norm_23
281
+ dr32_dz2 = (coord_3[i][2] - coord_2[i][2]) / norm_23
282
+ B_mat[natom+i][3*i] = dr32_dx2
283
+ B_mat[natom+i][3*i+1] = dr32_dy2
284
+ B_mat[natom+i][3*i+2] = dr32_dz2
285
+
286
+
287
+ return B_mat
288
+
289
+
290
+ def calc_B_matrix_for_NEB_2nd_stage(self, coord_1, coord_3):
291
+ natom = len(coord_1)
292
+ B_mat = np.zeros((natom, 3*natom))
293
+
294
+ for i in range(natom):
295
+ norm_13 = np.linalg.norm(coord_3[i] - coord_1[i]) + 1e-15
296
+ dr13_dx2 = (coord_3[i][0] - coord_1[i][0]) / norm_13
297
+ dr13_dy2 = (coord_3[i][1] - coord_1[i][1]) / norm_13
298
+ dr13_dz2 = (coord_3[i][2] - coord_1[i][2]) / norm_13
299
+ B_mat[i][3*i] = dr13_dx2
300
+ B_mat[i][3*i+1] = dr13_dy2
301
+ B_mat[i][3*i+2] = dr13_dz2
302
+
303
+ return B_mat
304
+
305
+ class CaluculationBNEB3():# Wilson's B-matrix-constrained NEB
306
+ def __init__(self, APPLY_CI_NEB=99999):
307
+ self.APPLY_CI_NEB = APPLY_CI_NEB
308
+ self.spring_force_const = 0.05
309
+ return
310
+
311
+ def calc_ci_neb_force(self, grad, tangent_grad):
312
+ #ref.: J. Chem. Phys. 113, 9901–9904 (2000)
313
+ #ref.: J. Chem. Phys. 142, 024106 (2015)
314
+ #available for optimizer using only first order differential
315
+ ci_force = -2.0 * tangent_grad
316
+ return ci_force
317
+
318
+ def calc_force(self, geometry_num_list, energy_list, gradient_list, optimize_num, element_list):
319
+ print("BNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEBBNEB")
320
+ nnode = len(energy_list)
321
+ local_max_energy_list_index, local_min_energy_list_index = extremum_list_index(energy_list)
322
+ total_force_list = []
323
+ for i in range(nnode):
324
+ if i == 0:
325
+ total_force_list.append(-1*np.array(gradient_list[0], dtype = "float64"))
326
+ continue
327
+ elif i == nnode-1:
328
+ total_force_list.append(-1*np.array(gradient_list[nnode-1], dtype = "float64"))
329
+ continue
330
+ tmp_grad = copy.copy(gradient_list[i]).reshape(-1, 1)
331
+ force, _ = 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])
332
+ if i > 1 and i < nnode - 2:
333
+ spring_force = self.calc_spring_force(geometry_num_list[i-2], geometry_num_list[i-1], geometry_num_list[i], geometry_num_list[i+1], geometry_num_list[i+2], i, nnode)
334
+ else:
335
+ spring_force = 0.0 * force
336
+
337
+ total_force_list.append(-1*force.reshape(-1, 3) -1* spring_force.reshape(-1, 3))
338
+
339
+ total_force_list = np.array(total_force_list, dtype = "float64")
340
+
341
+
342
+ return total_force_list
343
+
344
+ def calc_spring_force(self, coord_0, coord_1, coord_2, coord_3, coord_4, node_num, max_node_num):
345
+ if 1 < node_num and max_node_num - 2 > node_num:
346
+ # coord_0, coord_1, coord_2
347
+ force_1 = self.spring_force_const * (np.linalg.norm(coord_1 - coord_2) - np.linalg.norm(coord_0 - coord_1)) * (coord_1 - coord_2) / (np.linalg.norm(coord_1 - coord_2) + 1e-15)
348
+
349
+ # coord_1, coord_2, coord_3
350
+ force_2 = self.spring_force_const * (np.linalg.norm(coord_2 - coord_3) - np.linalg.norm(coord_1 - coord_2)) * (-1 * (coord_1 - coord_2) / (np.linalg.norm(coord_1 - coord_2) + 1e-15) - (coord_2 - coord_3) / (np.linalg.norm(coord_2 - coord_3) + 1e-15))
351
+
352
+ # coord_2, coord_3, coord_4
353
+ force_3 = self.spring_force_const * (np.linalg.norm(coord_3 - coord_4) - np.linalg.norm(coord_2 - coord_3)) * (coord_3 - coord_4) / (np.linalg.norm(coord_3 - coord_4) + 1e-15)
354
+
355
+ force = force_1 + force_2 + force_3
356
+ return force
357
+
358
+ def calc_project_out_grad(self, coord_1, coord_2, coord_3, grad_2, energy_list):# grad: (3N, 1), geom_num_list: (N, 3)
359
+ natom = len(coord_2)
360
+ tmp_grad = copy.copy(grad_2)
361
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
362
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
363
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
364
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
365
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
366
+ tangent_grad = projection_grad
367
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
368
+ B_mat = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
369
+ int_grad = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat)
370
+ projection_grad = calc_cart_grad_from_pBmat(-1*int_grad, B_mat)
371
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad
372
+ tangent_grad = projection_grad
373
+ else:
374
+ B_mat_plus = self.calc_B_matrix_for_NEB_tangent(coord_2, coord_3)
375
+ B_mat_minus = self.calc_B_matrix_for_NEB_tangent(coord_1, coord_2)
376
+ int_grad_plus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_plus)
377
+ int_grad_minus = calc_int_grad_from_pBmat(tmp_grad.reshape(3*natom, 1), B_mat_minus)
378
+ max_ene = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
379
+ min_ene = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
380
+ a = (max_ene) / (max_ene + min_ene + 1e-8)
381
+ b = (min_ene) / (max_ene + min_ene + 1e-8)
382
+
383
+ if energy_list[0] < energy_list[2]:
384
+ projection_grad_plus = calc_cart_grad_from_pBmat(-a*int_grad_plus, B_mat_plus)
385
+ projection_grad_minus = calc_cart_grad_from_pBmat(-b*int_grad_minus, B_mat_minus)
386
+
387
+ else:
388
+ projection_grad_plus = calc_cart_grad_from_pBmat(-b*int_grad_plus, B_mat_plus)
389
+ projection_grad_minus = calc_cart_grad_from_pBmat(-a*int_grad_minus, B_mat_minus)
390
+ proj_grad = tmp_grad.reshape(3*natom, 1) + projection_grad_plus + projection_grad_minus
391
+ tangent_grad = projection_grad_plus + projection_grad_minus
392
+ return proj_grad, tangent_grad
393
+
394
+
395
+ def calc_B_matrix_for_NEB_tangent(self, coord_1, coord_2):
396
+ natom = len(coord_2)
397
+ B_mat = np.zeros((natom, 3*natom))
398
+
399
+ for i in range(natom):
400
+ norm_12 = np.linalg.norm(coord_1[i] - coord_2[i]) + 1e-15
401
+ dr12_dx2 = (coord_2[i][0] - coord_1[i][0]) / norm_12
402
+ dr12_dy2 = (coord_2[i][1] - coord_1[i][1]) / norm_12
403
+ dr12_dz2 = (coord_2[i][2] - coord_1[i][2]) / norm_12
404
+ B_mat[i][3*i] = dr12_dx2
405
+ B_mat[i][3*i+1] = dr12_dy2
406
+ B_mat[i][3*i+2] = dr12_dz2
407
+
408
+ return B_mat
409
+
410
+ def projection_hessian(self, coord_1, coord_2, coord_3, gradient_list, hessian_2, energy_list):
411
+ #ref.: J. Chem. Theory. Comput. 2013, 9, 3498−3504
412
+ natom = len(coord_2)
413
+ gradient_2 = gradient_list[1].reshape(-1, 1)
414
+ gradient_1 = gradient_list[0].reshape(-1, 1)
415
+ gradient_3 = gradient_list[2].reshape(-1, 1)
416
+ if energy_list[0] < energy_list[1] and energy_list[1] < energy_list[2]:
417
+ tangent = coord_3.reshape(-1, 1) - coord_2.reshape(-1, 1)
418
+ grad_tangent = np.dot(np.eye(3*natom, k=1) - np.eye(3*natom, k=0), np.ones((3*natom, 3*natom)))
419
+ elif energy_list[0] > energy_list[1] and energy_list[1] > energy_list[2]:
420
+ tangent = coord_2.reshape(-1, 1) - coord_1.reshape(-1, 1)
421
+
422
+ grad_tangent = np.dot(np.eye(3*natom, k=0) - np.eye(3*natom, k=-1), np.ones((3*natom, 3*natom)))
423
+ else:
424
+ ene_max = max(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
425
+ ene_min = min(abs(energy_list[2] - energy_list[1]), abs(energy_list[1] - energy_list[0]))
426
+ tangent_plus = coord_3.reshape(-1, 1) - coord_2.reshape(-1, 1)
427
+ tangent_minus = coord_2.reshape(-1, 1) - coord_1.reshape(-1, 1)
428
+ if energy_list[0] < energy_list[2]:
429
+ tangent = tangent_plus * ene_max + tangent_minus * ene_min
430
+ else:
431
+ tangent = tangent_plus * ene_min + tangent_minus * ene_max
432
+
433
+ a = np.linalg.norm(coord_3 - coord_2)
434
+ b = np.linalg.norm(coord_2 - coord_1)
435
+ grad_a = np.sign(energy_list[2] - energy_list[1]) * (np.dot(np.eye(3*natom, k=1), gradient_3) - np.dot(np.eye(3*natom, k=0), gradient_2))
436
+ grad_b = np.sign(energy_list[0] - energy_list[1]) * (np.dot(np.eye(3*natom, k=-1), gradient_1) - np.dot(np.eye(3*natom, k=0), gradient_2))
437
+ grad_tangent = np.dot((a * np.eye(3*natom, k=1) + (b - a) * np.eye(3*natom, k=0) - b * np.eye(3*natom, k=-1)), np.ones((3*natom, 3*natom))) + np.dot(tangent_plus, grad_a.T) + np.dot(tangent_minus, grad_b.T)
438
+
439
+
440
+ unit_tangent = tangent / (np.linalg.norm(tangent) + 1e-15)
441
+ A = np.sum(gradient_2 * unit_tangent) * np.ones((3*natom, 3*natom)) + np.dot(unit_tangent, gradient_2.T) * (np.ones((3*natom, 3*natom)) - np.dot(unit_tangent, unit_tangent.T)) / (np.linalg.norm(tangent) + 1e-15)
442
+ hessian_2 = hessian_2 -1 * np.dot(unit_tangent, np.dot(hessian_2, unit_tangent).T) + np.dot(A, grad_tangent)
443
+ return hessian_2