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,417 @@
1
+ import numpy as np
2
+
3
+
4
+ class EDIIS:
5
+ def __init__(self):
6
+ """
7
+ ref.: The Journal of Chemical Physics, 2002, 116(19), 8255-8261.
8
+ International Journal of Quantum Chemistry, 2000, 79(2), 82-90.
9
+ The Journal of Chemical Physics, 2010, 132(5), 054109.
10
+ """
11
+
12
+ # EDIIS parameters with robust defaults
13
+ self.ediis_history_size = 5 # Moderate history size
14
+ self.ediis_min_points = 2 # Minimum points needed (just 2 for EDIIS)
15
+ self.ediis_weight_initial = 0.3 # Start with moderate EDIIS contribution
16
+ self.ediis_weight_max = 0.8 # Maximum EDIIS weight
17
+
18
+ # Error handling parameters
19
+ self.ediis_failure_count = 0 # Counter for consecutive EDIIS failures
20
+ self.ediis_max_failures = 2 # Reset history after these many failures
21
+ self.ediis_recovery_steps = 2 # Steps in recovery mode after failure
22
+ self.ediis_current_recovery = 0 # Current recovery step counter
23
+
24
+ # Adaptive weighting
25
+ self.ediis_weight_current = self.ediis_weight_initial # Current weight
26
+ self.ediis_weight_increment = 0.05 # Increment for successful iterations
27
+ self.ediis_weight_decrement = 0.15 # Decrement for failures
28
+
29
+ # Robust optimization parameters
30
+ self.ediis_regularization = 1e-8 # Regularization for numerical stability
31
+ self.ediis_step_ratio_max = 2.5 # Maximum allowed ratio between EDIIS and Original steps
32
+
33
+ # EDIIS history storage
34
+ self.geom_history = []
35
+ self.energy_history = []
36
+ self.grad_history = [] # Store gradients too for energy extrapolation
37
+ self.quality_history = []
38
+
39
+ # Energy tracking for improvement monitoring
40
+ self.prev_energy = float('inf')
41
+ self.non_improving_count = 0
42
+ self.iter = 0
43
+ return
44
+
45
+ def _update_ediis_history(self, geometry, energy, gradient, step_quality=1.0):
46
+ """
47
+ Update the EDIIS history with quality-based filtering
48
+
49
+ Parameters:
50
+ -----------
51
+ geometry : numpy.ndarray
52
+ Current geometry
53
+ energy : float
54
+ Current energy value
55
+ gradient : numpy.ndarray
56
+ Current gradient (used for energy extrapolation)
57
+ step_quality : float
58
+ Quality metric for this point (1.0 = good, <1.0 = lower quality)
59
+ """
60
+ # Add current point to history with quality metric
61
+ self.geom_history.append(geometry.copy())
62
+ self.energy_history.append(energy)
63
+ self.grad_history.append(gradient.copy())
64
+ self.quality_history.append(step_quality)
65
+
66
+ # If in recovery mode, only keep the most recent points
67
+ if self.ediis_current_recovery > 0:
68
+ self.ediis_current_recovery -= 1
69
+ if len(self.geom_history) > 2:
70
+ self.geom_history = self.geom_history[-2:]
71
+ self.energy_history = self.energy_history[-2:]
72
+ self.grad_history = self.grad_history[-2:]
73
+ self.quality_history = self.quality_history[-2:]
74
+ return
75
+
76
+ # Limit history size
77
+ if len(self.geom_history) > self.ediis_history_size:
78
+ # For EDIIS, prioritize keeping points with lower energies
79
+ if len(self.geom_history) > 2:
80
+ # Don't consider the most recent point for removal
81
+ # Combine energy values and quality for decision
82
+ metrics = []
83
+ for i in range(len(self.energy_history)-1):
84
+ # Lower energy and higher quality are better
85
+ normalized_energy = (self.energy_history[i] - min(self.energy_history)) / \
86
+ (max(self.energy_history) - min(self.energy_history) + 1e-10)
87
+ metrics.append(normalized_energy - 0.5 * self.quality_history[i])
88
+
89
+ worst_idx = np.argmax(metrics)
90
+
91
+ # Remove the worst point
92
+ self.geom_history.pop(worst_idx)
93
+ self.energy_history.pop(worst_idx)
94
+ self.grad_history.pop(worst_idx)
95
+ self.quality_history.pop(worst_idx)
96
+ else:
97
+ # Default to removing oldest point if we only have 2 points
98
+ self.geom_history.pop(0)
99
+ self.energy_history.pop(0)
100
+ self.grad_history.pop(0)
101
+ self.quality_history.pop(0)
102
+
103
+ def _solve_ediis_equations(self):
104
+ """
105
+ Solve EDIIS equations with non-negative coefficients constraint
106
+
107
+ Returns:
108
+ --------
109
+ numpy.ndarray
110
+ EDIIS coefficients that minimize energy in the subspace
111
+ """
112
+ n_points = len(self.geom_history)
113
+
114
+ if n_points < 2:
115
+ return np.array([1.0])
116
+
117
+ # Construct the energy difference matrix
118
+ E_diff = np.zeros((n_points, n_points))
119
+
120
+ # Calculate energy differences using energies and gradients
121
+ for i in range(n_points):
122
+ for j in range(n_points):
123
+ if i == j:
124
+ E_diff[i, j] = 0.0
125
+ else:
126
+ # Energy difference from i to j:
127
+ # E_j ≈ E_i + g_i·(x_j-x_i) + 0.5·(x_j-x_i)·H·(x_j-x_i)
128
+ # We approximate the Hessian term as zero for simplicity
129
+ dx = self.geom_history[j] - self.geom_history[i]
130
+ E_diff[i, j] = self.energy_history[j] - self.energy_history[i] - \
131
+ np.dot(self.grad_history[i].flatten(), dx.flatten())
132
+
133
+ try:
134
+ # Formulate the quadratic programming problem:
135
+ # minimize 0.5*x^T*A*x + b^T*x subject to sum(x) = 1, x >= 0
136
+ # where A is the energy difference matrix and b is zero
137
+
138
+ # We'll use a simpler constrained minimization approach
139
+ from scipy.optimize import minimize
140
+
141
+ def objective(x):
142
+ return 0.5 * np.sum(np.outer(x, x) * E_diff)
143
+
144
+ def constraint(x):
145
+ return np.sum(x) - 1.0
146
+
147
+ bounds = [(0, 1) for _ in range(n_points)]
148
+ constraints = {'type': 'eq', 'fun': constraint}
149
+
150
+ # Initial guess: equal weights
151
+ x0 = np.ones(n_points) / n_points
152
+
153
+ # Solve the constrained minimization problem
154
+ result = minimize(objective, x0, method='SLSQP', bounds=bounds,
155
+ constraints=constraints, options={'ftol': 1e-6})
156
+
157
+ if result.success:
158
+ return result.x
159
+ else:
160
+ print("EDIIS solver failed, using uniform coefficients")
161
+ return np.ones(n_points) / n_points
162
+
163
+ except Exception as e:
164
+ print(f"EDIIS equation solver failed: {str(e)}")
165
+ # Fallback: use most recent point
166
+ coeffs = np.zeros(n_points)
167
+ coeffs[-1] = 1.0
168
+ return coeffs
169
+
170
+ def _calculate_ediis_geometry(self):
171
+ """
172
+ Calculate a new geometry using EDIIS with robust error handling
173
+
174
+ Returns:
175
+ --------
176
+ tuple
177
+ (extrapolated_geometry, coefficients, success, quality)
178
+ """
179
+ n_points = len(self.geom_history)
180
+
181
+ if n_points < self.ediis_min_points:
182
+ return None, None, False, 0.0
183
+
184
+ # Reset history if we've had too many failures
185
+ if self.ediis_failure_count >= self.ediis_max_failures:
186
+ print(f"Warning: {self.ediis_failure_count} consecutive EDIIS failures, resetting history")
187
+ # Keep only the most recent point
188
+ if len(self.geom_history) > 0:
189
+ self.geom_history = [self.geom_history[-1]]
190
+ self.energy_history = [self.energy_history[-1]]
191
+ self.grad_history = [self.grad_history[-1]]
192
+ self.quality_history = [1.0]
193
+
194
+ self.ediis_failure_count = 0
195
+ self.ediis_current_recovery = self.ediis_recovery_steps
196
+ self.ediis_weight_current = max(0.2, self.ediis_weight_current / 2)
197
+
198
+ return None, None, False, 0.0
199
+
200
+ try:
201
+ # Calculate EDIIS coefficients
202
+ coeffs = self._solve_ediis_equations()
203
+
204
+ # Check coefficient validity
205
+ if np.any(np.isnan(coeffs)) or abs(np.sum(coeffs) - 1.0) > 1e-4:
206
+ print("Warning: Invalid EDIIS coefficients, using most recent point")
207
+ coeffs = np.zeros(n_points)
208
+ coeffs[-1] = 1.0
209
+ quality = 0.5
210
+ else:
211
+ # Calculate quality metric based on coefficient distribution
212
+ # We prefer solutions with fewer dominant points (unlike GDIIS)
213
+ nonzero_count = np.sum(coeffs > 0.01)
214
+ total_count = len(coeffs)
215
+ # Quality is higher when we have fewer nonzero coefficients
216
+ quality = 0.5 + 0.5 * (1.0 - nonzero_count / total_count)
217
+
218
+ # Calculate the new geometry as a linear combination
219
+ extrapolated_geometry = np.zeros_like(self.geom_history[0])
220
+ for i in range(n_points):
221
+ extrapolated_geometry += coeffs[i] * self.geom_history[i]
222
+
223
+ # Check for NaN values in the result
224
+ if np.any(np.isnan(extrapolated_geometry)):
225
+ print("Warning: NaN values in extrapolated geometry, EDIIS calculation failed")
226
+ self.ediis_failure_count += 1
227
+ return None, None, False, 0.0
228
+
229
+ # Print coefficients
230
+ print("EDIIS coefficients:", ", ".join(f"{c:.4f}" for c in coeffs))
231
+ print(f"EDIIS quality metric: {quality:.4f}")
232
+
233
+ return extrapolated_geometry, coeffs, True, quality
234
+
235
+ except Exception as e:
236
+ print(f"EDIIS extrapolation failed: {str(e)}")
237
+ self.ediis_failure_count += 1
238
+ return None, None, False, 0.0
239
+
240
+ def _validate_ediis_step(self, original_step, ediis_step, B_g):
241
+ """
242
+ Validate the EDIIS step to ensure it's reasonable
243
+
244
+ Parameters:
245
+ -----------
246
+ original_step : numpy.ndarray
247
+ Step calculated by the original method
248
+ ediis_step : numpy.ndarray
249
+ Step calculated by the EDIIS method
250
+ B_g : numpy.ndarray
251
+ Current gradient
252
+
253
+ Returns:
254
+ --------
255
+ tuple
256
+ (is_valid, validation_quality)
257
+ """
258
+ # 1. Check step size ratio
259
+ original_norm = np.linalg.norm(original_step)
260
+ ediis_norm = np.linalg.norm(ediis_step)
261
+
262
+ if original_norm > 1e-10:
263
+ step_ratio = ediis_norm / original_norm
264
+ if step_ratio > self.ediis_step_ratio_max:
265
+ print(f"EDIIS step too large: {step_ratio:.2f} times Original step")
266
+ return False, 0.0
267
+
268
+ # Calculate quality based on step ratio
269
+ ratio_quality = 1.0 - min(1.0, abs(np.log10(step_ratio)))
270
+ else:
271
+ ratio_quality = 0.5
272
+
273
+ # 2. Check gradient alignment
274
+ grad_norm = np.linalg.norm(B_g)
275
+ if grad_norm > 1e-10:
276
+ # For EDIIS, we don't require strict downhill movement,
277
+ # but extreme disagreement with gradient direction is suspicious
278
+ neg_grad = -B_g / grad_norm
279
+ original_alignment = np.dot(original_step.flatten(), neg_grad.flatten()) / np.linalg.norm(original_step)
280
+ ediis_alignment = np.dot(ediis_step.flatten(), neg_grad.flatten()) / np.linalg.norm(ediis_step)
281
+
282
+ # Only reject if EDIIS step is strongly opposing gradient while original step is downhill
283
+ if original_alignment > 0.5 and ediis_alignment < -0.7:
284
+ print(f"EDIIS step rejected: strongly opposing gradient direction")
285
+ return False, 0.0
286
+
287
+ # Calculate gradient alignment quality
288
+ alignment_quality = 0.5 + 0.5 * max(-1.0, min(1.0, ediis_alignment))
289
+ else:
290
+ alignment_quality = 0.5
291
+
292
+ # 3. Overall validation quality
293
+ validation_quality = 0.4 * ratio_quality + 0.6 * alignment_quality
294
+
295
+ return True, validation_quality
296
+
297
+ def run(self, geom_num_list, energy, B_g, original_move_vector):
298
+ """
299
+ Run EDIIS optimization step
300
+
301
+ Parameters:
302
+ -----------
303
+ geom_num_list : numpy.ndarray
304
+ Current geometry
305
+ energy : float
306
+ Current energy value
307
+ B_g : numpy.ndarray
308
+ Current gradient
309
+ original_move_vector : numpy.ndarray
310
+ Step calculated by the original method
311
+
312
+ Returns:
313
+ --------
314
+ numpy.ndarray
315
+ Optimized step vector
316
+ """
317
+ print("EDIIS method")
318
+ n_coords = len(geom_num_list)
319
+
320
+ # Track energy improvements
321
+ improving = energy < self.prev_energy
322
+ if improving:
323
+ self.non_improving_count = 0
324
+ else:
325
+ self.non_improving_count += 1
326
+ if self.non_improving_count > 2:
327
+ # Reduce EDIIS weight if optimization is stalling
328
+ self.ediis_weight_current = max(0.1, self.ediis_weight_current - 0.1)
329
+ print(f"Energy not improving, reducing EDIIS weight to {self.ediis_weight_current:.2f}")
330
+ self.non_improving_count = 0
331
+
332
+ self.prev_energy = energy
333
+
334
+ # Update EDIIS history with quality information
335
+ step_quality = 1.0
336
+ if self.iter > 0 and len(self.energy_history) > 0:
337
+ # Calculate quality based on energy change
338
+ if energy < min(self.energy_history):
339
+ # New lowest energy, excellent quality
340
+ step_quality = 1.0
341
+ elif energy > max(self.energy_history):
342
+ # Energy increased, poor quality
343
+ step_quality = 0.5
344
+ else:
345
+ # In between, scale quality
346
+ energy_range = max(self.energy_history) - min(self.energy_history)
347
+ if energy_range > 1e-10:
348
+ normalized_energy = (energy - min(self.energy_history)) / energy_range
349
+ step_quality = 1.0 - 0.5 * normalized_energy
350
+ else:
351
+ step_quality = 0.8
352
+
353
+ self._update_ediis_history(geom_num_list, energy, B_g, step_quality)
354
+
355
+ # Skip EDIIS if in recovery mode
356
+ if self.ediis_current_recovery > 0:
357
+ self.ediis_current_recovery -= 1
358
+ print(f"In EDIIS recovery mode ({self.ediis_current_recovery} steps remaining), skipping EDIIS")
359
+ move_vector = original_move_vector
360
+ # Apply EDIIS if enough history has been accumulated
361
+ elif len(self.geom_history) >= self.ediis_min_points:
362
+ # Calculate EDIIS geometry
363
+ ediis_geom, ediis_coeffs, success, quality = self._calculate_ediis_geometry()
364
+
365
+ if success and ediis_geom is not None:
366
+ # Calculate EDIIS step
367
+ ediis_step = (ediis_geom - geom_num_list).reshape(n_coords, 1)
368
+
369
+ # Validate EDIIS step
370
+ is_valid, validation_quality = self._validate_ediis_step(original_move_vector, ediis_step, B_g)
371
+
372
+ if is_valid:
373
+ # Calculate adaptive weight
374
+ if self.ediis_failure_count > 0:
375
+ # Reduce weight if we've had failures
376
+ ediis_weight = max(0.1, self.ediis_weight_current - self.ediis_failure_count * self.ediis_weight_decrement)
377
+ else:
378
+ # Otherwise use current weight, possibly increasing it
379
+ ediis_weight = min(self.ediis_weight_max, self.ediis_weight_current + self.ediis_weight_increment)
380
+
381
+ # Scale weight by validation quality
382
+ ediis_weight *= validation_quality
383
+
384
+ original_weight = 1.0 - ediis_weight
385
+
386
+ # Calculate blended step
387
+ move_vector = original_weight * original_move_vector + ediis_weight * ediis_step
388
+ print(f"Using blended step: {original_weight:.4f}*Original + {ediis_weight:.4f}*EDIIS")
389
+
390
+ # Update current weight for next iteration
391
+ self.ediis_weight_current = 0.7 * self.ediis_weight_current + 0.3 * ediis_weight
392
+ else:
393
+ print("EDIIS step validation failed, using Original step only")
394
+ move_vector = original_move_vector
395
+ self.ediis_failure_count += 1
396
+ else:
397
+ move_vector = original_move_vector
398
+ if not success:
399
+ self.ediis_failure_count += 1
400
+ else:
401
+ print(f"Building EDIIS history ({len(self.geom_history)}/{self.ediis_min_points} points)")
402
+ move_vector = original_move_vector
403
+
404
+ # Final safety checks
405
+ move_norm = np.linalg.norm(move_vector)
406
+ if move_norm < 1e-10 or np.any(np.isnan(move_vector)) or np.any(np.isinf(move_vector)):
407
+ print("Warning: Step issue detected, using scaled gradient instead")
408
+ move_vector = -0.1 * B_g.reshape(n_coords, 1)
409
+ # Reset history on numerical failure
410
+ if np.any(np.isnan(move_vector)):
411
+ self.geom_history = []
412
+ self.energy_history = []
413
+ self.grad_history = []
414
+ self.quality_history = []
415
+
416
+ self.iter += 1
417
+ return move_vector
@@ -0,0 +1,76 @@
1
+ import numpy as np
2
+ import copy
3
+
4
+
5
+
6
+
7
+ class EVE:
8
+ def __init__(self, **config):
9
+ #EVE
10
+ #ref.arXiv:1611.01505v3
11
+ self.adam_count = 1
12
+ self.beta_m = 0.9
13
+ self.beta_v = 0.999
14
+ self.beta_d = 0.999
15
+ self.DELTA = 0.03
16
+ self.c = 10
17
+ self.eve_d_tilde = 1.0
18
+ self.Epsilon = 1e-12
19
+ self.Initialization = True
20
+ self.config = config
21
+ self.hessian = None
22
+ self.bias_hessian = None
23
+
24
+ def run(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector, initial_geom_num_list, g, pre_g):
25
+ print("EVE")
26
+ if self.Initialization:
27
+ self.adam_m = geom_num_list * 0.0
28
+ self.adam_v = geom_num_list * 0.0
29
+
30
+ self.Initialization = False
31
+
32
+ new_adam_m = self.adam_m*0.0
33
+ new_adam_v = self.adam_v*0.0
34
+
35
+ new_adam_m_hat = self.adam_m*0.0
36
+ new_adam_v_hat = self.adam_v*0.0
37
+ for i in range(len(geom_num_list)):
38
+ new_adam_m[i] = copy.copy(self.beta_m*self.adam_m[i] + (1.0-self.beta_m)*(B_g[i]))
39
+ new_adam_v[i] = copy.copy(self.beta_v*self.adam_v[i] + (1.0-self.beta_v)*(B_g[i])**2)
40
+
41
+
42
+ move_vector = []
43
+ for i in range(len(geom_num_list)):
44
+ new_adam_m_hat[i] = copy.copy(new_adam_m[i]/(1 - self.beta_m**self.adam_count))
45
+ new_adam_v_hat[i] = copy.copy((new_adam_v[i])/(1 - self.beta_v**self.adam_count))
46
+
47
+ if self.adam_count > 1:
48
+ eve_d = abs(B_e - pre_B_e)/ min(B_e, pre_B_e)
49
+ eve_d_hat = np.clip(eve_d, 1/self.c , self.c)
50
+ self.eve_d_tilde = self.beta_d*self.eve_d_tilde + (1.0 - self.beta_d)*eve_d_hat
51
+
52
+ else:
53
+ pass
54
+
55
+ for i in range(len(geom_num_list)):
56
+ move_vector.append((self.DELTA/self.eve_d_tilde)*new_adam_m_hat[i]/(np.sqrt(new_adam_v_hat[i])+self.Epsilon))
57
+ self.adam_m = new_adam_m
58
+ self.adam_v = new_adam_v
59
+
60
+ self.adam_count += 1
61
+ return move_vector#Bohr.
62
+
63
+ def set_hessian(self, hessian):
64
+ self.hessian = hessian
65
+ return
66
+
67
+ def set_bias_hessian(self, bias_hessian):
68
+ self.bias_hessian = bias_hessian
69
+ return
70
+
71
+
72
+ def get_hessian(self):
73
+ return self.hessian
74
+
75
+ def get_bias_hessian(self):
76
+ return self.bias_hessian
@@ -0,0 +1,61 @@
1
+ import numpy as np
2
+ import copy
3
+
4
+
5
+ class FastAdabelief:
6
+ def __init__(self, **config):
7
+ #FastAdaBelief
8
+ #ref: arXiv:2104.13790 https://doi.org/10.48550/arXiv.2104.13790
9
+ self.adam_count = 1
10
+ self.DELTA = 0.03
11
+ self.beta_m = 0.9
12
+ self.beta_v = 0.999
13
+ self.Epsilon = 1e-12
14
+ self.Initialization = True
15
+ self.config = config
16
+ self.delta_for_v = 0.01
17
+ self.hessian = None
18
+ self.bias_hessian = None
19
+ return
20
+
21
+ def run(self, geom_num_list, B_g, pre_B_g=[], pre_geom=[], B_e=0.0, pre_B_e=0.0, pre_move_vector=[], initial_geom_num_list=[], g=[], pre_g=[]):
22
+ print("FastAdaBelief")
23
+ if self.Initialization:
24
+ self.adam_m = geom_num_list * 0.0
25
+ self.adam_v = geom_num_list * 0.0
26
+ self.Initialization = False
27
+
28
+ adam_count = self.adam_count
29
+ adam_m = self.adam_m
30
+ adam_v = self.adam_v
31
+ new_adam_m = adam_m*0.0
32
+ new_adam_v = adam_v*0.0
33
+
34
+ for i in range(len(geom_num_list)):
35
+ new_adam_m[i] = copy.copy(self.beta_m*adam_m[i] + (1.0-self.beta_m)*(B_g[i]))
36
+ new_adam_v[i] = copy.copy(self.beta_v*adam_v[i] + (1.0-self.beta_v)*(B_g[i]-new_adam_m[i])**2)
37
+
38
+ move_vector = []
39
+
40
+ for i in range(len(geom_num_list)):
41
+ move_vector.append(self.DELTA*new_adam_m[i]/(new_adam_v[i] + self.Epsilon + self.delta_for_v))
42
+
43
+ self.adam_m = new_adam_m
44
+ self.adam_v = new_adam_v
45
+ self.adam_count += 1
46
+
47
+ return move_vector#Bohr
48
+ def set_hessian(self, hessian):
49
+ self.hessian = hessian
50
+ return
51
+
52
+ def set_bias_hessian(self, bias_hessian):
53
+ self.bias_hessian = bias_hessian
54
+ return
55
+
56
+
57
+ def get_hessian(self):
58
+ return self.hessian
59
+
60
+ def get_bias_hessian(self):
61
+ return self.bias_hessian
@@ -0,0 +1,77 @@
1
+ import numpy as np
2
+ import copy
3
+
4
+
5
+
6
+ class FIRE:
7
+ def __init__(self, **config):#MD-like optimization method.
8
+ #FIRE
9
+ #Physical Review Letters, Vol. 97, 170201 (2006)
10
+ self.adam_count = 1
11
+ self.N_acc = 5
12
+ self.f_inc = 1.10
13
+ self.f_acc = 0.99
14
+ self.f_dec = 0.50
15
+ self.dt_max = 0.8
16
+ self.alpha_start = 0.1
17
+
18
+ self.display_flag = True
19
+ self.config = config
20
+ self.Initialization = True
21
+ self.hessian = None
22
+ self.bias_hessian = None
23
+
24
+ return
25
+
26
+ def run(self, geom_num_list, B_g, pre_B_g=[], pre_geom=[], B_e=0.0, pre_B_e=0.0, pre_move_vector=[], initial_geom_num_list=[], g=[], pre_g=[]):
27
+
28
+ adam_count = self.adam_count
29
+
30
+ if self.Initialization:
31
+ self.dt = 0.1
32
+ self.alpha = self.alpha_start
33
+ self.n_reset = 0
34
+ self.pre_velocity = geom_num_list * 0.0
35
+ self.Initialization = False
36
+
37
+
38
+
39
+ velocity = (1.0 - self.alpha) * self.pre_velocity + self.alpha * (np.linalg.norm(self.pre_velocity, ord=2)/np.linalg.norm(B_g, ord=2)) * B_g
40
+
41
+ if adam_count > 0 and np.dot(self.pre_velocity.reshape(1, len(geom_num_list)), B_g.reshape(len(geom_num_list), 1)) > 0:
42
+ if self.n_reset > self.N_acc:
43
+ self.dt = min(self.dt * self.f_inc, self.dt_max)
44
+ self.alpha = self.alpha * self.f_acc
45
+ self.n_reset += 1
46
+ else:
47
+ velocity *= 0.0
48
+ self.alpha = self.alpha_start
49
+ self.dt *= self.f_dec
50
+ self.n_reset = 0
51
+
52
+ velocity += self.dt*B_g
53
+
54
+ move_vector = copy.copy(self.dt * velocity)
55
+
56
+ if self.display_flag:
57
+ print("FIRE")
58
+ print("dt, alpha, n_reset :", self.dt, self.alpha, self.n_reset)
59
+
60
+ self.pre_velocity = velocity
61
+ adam_count += 1
62
+ return move_vector#Bohr.
63
+
64
+ def set_hessian(self, hessian):
65
+ self.hessian = hessian
66
+ return
67
+
68
+ def set_bias_hessian(self, bias_hessian):
69
+ self.bias_hessian = bias_hessian
70
+ return
71
+
72
+
73
+ def get_hessian(self):
74
+ return self.hessian
75
+
76
+ def get_bias_hessian(self):
77
+ return self.bias_hessian