mlmm-toolkit 0.2.2.dev0__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 (372) hide show
  1. hessian_ff/__init__.py +50 -0
  2. hessian_ff/analytical_hessian.py +609 -0
  3. hessian_ff/constants.py +46 -0
  4. hessian_ff/forcefield.py +339 -0
  5. hessian_ff/loaders.py +608 -0
  6. hessian_ff/native/Makefile +8 -0
  7. hessian_ff/native/__init__.py +28 -0
  8. hessian_ff/native/analytical_hessian.py +88 -0
  9. hessian_ff/native/analytical_hessian_ext.cpp +258 -0
  10. hessian_ff/native/bonded.py +82 -0
  11. hessian_ff/native/bonded_ext.cpp +640 -0
  12. hessian_ff/native/loader.py +349 -0
  13. hessian_ff/native/nonbonded.py +118 -0
  14. hessian_ff/native/nonbonded_ext.cpp +1150 -0
  15. hessian_ff/prmtop_parmed.py +23 -0
  16. hessian_ff/system.py +107 -0
  17. hessian_ff/terms/__init__.py +14 -0
  18. hessian_ff/terms/angle.py +73 -0
  19. hessian_ff/terms/bond.py +44 -0
  20. hessian_ff/terms/cmap.py +406 -0
  21. hessian_ff/terms/dihedral.py +141 -0
  22. hessian_ff/terms/nonbonded.py +209 -0
  23. hessian_ff/tests/__init__.py +0 -0
  24. hessian_ff/tests/conftest.py +75 -0
  25. hessian_ff/tests/data/small/complex.parm7 +1346 -0
  26. hessian_ff/tests/data/small/complex.pdb +125 -0
  27. hessian_ff/tests/data/small/complex.rst7 +63 -0
  28. hessian_ff/tests/test_coords_input.py +44 -0
  29. hessian_ff/tests/test_energy_force.py +49 -0
  30. hessian_ff/tests/test_hessian.py +137 -0
  31. hessian_ff/tests/test_smoke.py +18 -0
  32. hessian_ff/tests/test_validation.py +40 -0
  33. hessian_ff/workflows.py +889 -0
  34. mlmm/__init__.py +36 -0
  35. mlmm/__main__.py +7 -0
  36. mlmm/_version.py +34 -0
  37. mlmm/add_elem_info.py +374 -0
  38. mlmm/advanced_help.py +91 -0
  39. mlmm/align_freeze_atoms.py +601 -0
  40. mlmm/all.py +3535 -0
  41. mlmm/bond_changes.py +231 -0
  42. mlmm/bool_compat.py +223 -0
  43. mlmm/cli.py +574 -0
  44. mlmm/cli_utils.py +166 -0
  45. mlmm/default_group.py +337 -0
  46. mlmm/defaults.py +467 -0
  47. mlmm/define_layer.py +526 -0
  48. mlmm/dft.py +1041 -0
  49. mlmm/energy_diagram.py +253 -0
  50. mlmm/extract.py +2213 -0
  51. mlmm/fix_altloc.py +464 -0
  52. mlmm/freq.py +1406 -0
  53. mlmm/harmonic_constraints.py +140 -0
  54. mlmm/hessian_cache.py +44 -0
  55. mlmm/hessian_calc.py +174 -0
  56. mlmm/irc.py +638 -0
  57. mlmm/mlmm_calc.py +2262 -0
  58. mlmm/mm_parm.py +945 -0
  59. mlmm/oniom_export.py +1983 -0
  60. mlmm/oniom_import.py +457 -0
  61. mlmm/opt.py +1742 -0
  62. mlmm/path_opt.py +1353 -0
  63. mlmm/path_search.py +2299 -0
  64. mlmm/preflight.py +88 -0
  65. mlmm/py.typed +1 -0
  66. mlmm/pysis_runner.py +45 -0
  67. mlmm/scan.py +1047 -0
  68. mlmm/scan2d.py +1226 -0
  69. mlmm/scan3d.py +1265 -0
  70. mlmm/scan_common.py +184 -0
  71. mlmm/summary_log.py +736 -0
  72. mlmm/trj2fig.py +448 -0
  73. mlmm/tsopt.py +2871 -0
  74. mlmm/utils.py +2309 -0
  75. mlmm/xtb_embedcharge_correction.py +475 -0
  76. mlmm_toolkit-0.2.2.dev0.dist-info/METADATA +1159 -0
  77. mlmm_toolkit-0.2.2.dev0.dist-info/RECORD +372 -0
  78. mlmm_toolkit-0.2.2.dev0.dist-info/WHEEL +5 -0
  79. mlmm_toolkit-0.2.2.dev0.dist-info/entry_points.txt +2 -0
  80. mlmm_toolkit-0.2.2.dev0.dist-info/licenses/LICENSE +674 -0
  81. mlmm_toolkit-0.2.2.dev0.dist-info/top_level.txt +4 -0
  82. pysisyphus/Geometry.py +1667 -0
  83. pysisyphus/LICENSE +674 -0
  84. pysisyphus/TableFormatter.py +63 -0
  85. pysisyphus/TablePrinter.py +74 -0
  86. pysisyphus/__init__.py +12 -0
  87. pysisyphus/calculators/AFIR.py +452 -0
  88. pysisyphus/calculators/AnaPot.py +20 -0
  89. pysisyphus/calculators/AnaPot2.py +48 -0
  90. pysisyphus/calculators/AnaPot3.py +12 -0
  91. pysisyphus/calculators/AnaPot4.py +20 -0
  92. pysisyphus/calculators/AnaPotBase.py +337 -0
  93. pysisyphus/calculators/AnaPotCBM.py +25 -0
  94. pysisyphus/calculators/AtomAtomTransTorque.py +154 -0
  95. pysisyphus/calculators/CFOUR.py +250 -0
  96. pysisyphus/calculators/Calculator.py +844 -0
  97. pysisyphus/calculators/CerjanMiller.py +24 -0
  98. pysisyphus/calculators/Composite.py +123 -0
  99. pysisyphus/calculators/ConicalIntersection.py +171 -0
  100. pysisyphus/calculators/DFTBp.py +430 -0
  101. pysisyphus/calculators/DFTD3.py +66 -0
  102. pysisyphus/calculators/DFTD4.py +84 -0
  103. pysisyphus/calculators/Dalton.py +61 -0
  104. pysisyphus/calculators/Dimer.py +681 -0
  105. pysisyphus/calculators/Dummy.py +20 -0
  106. pysisyphus/calculators/EGO.py +76 -0
  107. pysisyphus/calculators/EnergyMin.py +224 -0
  108. pysisyphus/calculators/ExternalPotential.py +264 -0
  109. pysisyphus/calculators/FakeASE.py +35 -0
  110. pysisyphus/calculators/FourWellAnaPot.py +28 -0
  111. pysisyphus/calculators/FreeEndNEBPot.py +39 -0
  112. pysisyphus/calculators/Gaussian09.py +18 -0
  113. pysisyphus/calculators/Gaussian16.py +726 -0
  114. pysisyphus/calculators/HardSphere.py +159 -0
  115. pysisyphus/calculators/IDPPCalculator.py +49 -0
  116. pysisyphus/calculators/IPIClient.py +133 -0
  117. pysisyphus/calculators/IPIServer.py +234 -0
  118. pysisyphus/calculators/LEPSBase.py +24 -0
  119. pysisyphus/calculators/LEPSExpr.py +139 -0
  120. pysisyphus/calculators/LennardJones.py +80 -0
  121. pysisyphus/calculators/MOPAC.py +219 -0
  122. pysisyphus/calculators/MullerBrownSympyPot.py +51 -0
  123. pysisyphus/calculators/MultiCalc.py +85 -0
  124. pysisyphus/calculators/NFK.py +45 -0
  125. pysisyphus/calculators/OBabel.py +87 -0
  126. pysisyphus/calculators/ONIOMv2.py +1129 -0
  127. pysisyphus/calculators/ORCA.py +893 -0
  128. pysisyphus/calculators/ORCA5.py +6 -0
  129. pysisyphus/calculators/OpenMM.py +88 -0
  130. pysisyphus/calculators/OpenMolcas.py +281 -0
  131. pysisyphus/calculators/OverlapCalculator.py +908 -0
  132. pysisyphus/calculators/Psi4.py +218 -0
  133. pysisyphus/calculators/PyPsi4.py +37 -0
  134. pysisyphus/calculators/PySCF.py +341 -0
  135. pysisyphus/calculators/PyXTB.py +73 -0
  136. pysisyphus/calculators/QCEngine.py +106 -0
  137. pysisyphus/calculators/Rastrigin.py +22 -0
  138. pysisyphus/calculators/Remote.py +76 -0
  139. pysisyphus/calculators/Rosenbrock.py +15 -0
  140. pysisyphus/calculators/SocketCalc.py +97 -0
  141. pysisyphus/calculators/TIP3P.py +111 -0
  142. pysisyphus/calculators/TransTorque.py +161 -0
  143. pysisyphus/calculators/Turbomole.py +965 -0
  144. pysisyphus/calculators/VRIPot.py +37 -0
  145. pysisyphus/calculators/WFOWrapper.py +333 -0
  146. pysisyphus/calculators/WFOWrapper2.py +341 -0
  147. pysisyphus/calculators/XTB.py +418 -0
  148. pysisyphus/calculators/__init__.py +81 -0
  149. pysisyphus/calculators/cosmo_data.py +139 -0
  150. pysisyphus/calculators/parser.py +150 -0
  151. pysisyphus/color.py +19 -0
  152. pysisyphus/config.py +133 -0
  153. pysisyphus/constants.py +65 -0
  154. pysisyphus/cos/AdaptiveNEB.py +230 -0
  155. pysisyphus/cos/ChainOfStates.py +725 -0
  156. pysisyphus/cos/FreeEndNEB.py +25 -0
  157. pysisyphus/cos/FreezingString.py +103 -0
  158. pysisyphus/cos/GrowingChainOfStates.py +71 -0
  159. pysisyphus/cos/GrowingNT.py +309 -0
  160. pysisyphus/cos/GrowingString.py +508 -0
  161. pysisyphus/cos/NEB.py +189 -0
  162. pysisyphus/cos/SimpleZTS.py +64 -0
  163. pysisyphus/cos/__init__.py +22 -0
  164. pysisyphus/cos/stiffness.py +199 -0
  165. pysisyphus/drivers/__init__.py +17 -0
  166. pysisyphus/drivers/afir.py +855 -0
  167. pysisyphus/drivers/barriers.py +271 -0
  168. pysisyphus/drivers/birkholz.py +138 -0
  169. pysisyphus/drivers/cluster.py +318 -0
  170. pysisyphus/drivers/diabatization.py +133 -0
  171. pysisyphus/drivers/merge.py +368 -0
  172. pysisyphus/drivers/merge_mol2.py +322 -0
  173. pysisyphus/drivers/opt.py +375 -0
  174. pysisyphus/drivers/perf.py +91 -0
  175. pysisyphus/drivers/pka.py +52 -0
  176. pysisyphus/drivers/precon_pos_rot.py +669 -0
  177. pysisyphus/drivers/rates.py +480 -0
  178. pysisyphus/drivers/replace.py +219 -0
  179. pysisyphus/drivers/scan.py +212 -0
  180. pysisyphus/drivers/spectrum.py +166 -0
  181. pysisyphus/drivers/thermo.py +31 -0
  182. pysisyphus/dynamics/Gaussian.py +103 -0
  183. pysisyphus/dynamics/__init__.py +20 -0
  184. pysisyphus/dynamics/colvars.py +136 -0
  185. pysisyphus/dynamics/driver.py +297 -0
  186. pysisyphus/dynamics/helpers.py +256 -0
  187. pysisyphus/dynamics/lincs.py +105 -0
  188. pysisyphus/dynamics/mdp.py +364 -0
  189. pysisyphus/dynamics/rattle.py +121 -0
  190. pysisyphus/dynamics/thermostats.py +128 -0
  191. pysisyphus/dynamics/wigner.py +266 -0
  192. pysisyphus/elem_data.py +3473 -0
  193. pysisyphus/exceptions.py +2 -0
  194. pysisyphus/filtertrj.py +69 -0
  195. pysisyphus/helpers.py +623 -0
  196. pysisyphus/helpers_pure.py +649 -0
  197. pysisyphus/init_logging.py +50 -0
  198. pysisyphus/intcoords/Bend.py +69 -0
  199. pysisyphus/intcoords/Bend2.py +25 -0
  200. pysisyphus/intcoords/BondedFragment.py +32 -0
  201. pysisyphus/intcoords/Cartesian.py +41 -0
  202. pysisyphus/intcoords/CartesianCoords.py +140 -0
  203. pysisyphus/intcoords/Coords.py +56 -0
  204. pysisyphus/intcoords/DLC.py +197 -0
  205. pysisyphus/intcoords/DistanceFunction.py +34 -0
  206. pysisyphus/intcoords/DummyImproper.py +70 -0
  207. pysisyphus/intcoords/DummyTorsion.py +72 -0
  208. pysisyphus/intcoords/LinearBend.py +105 -0
  209. pysisyphus/intcoords/LinearDisplacement.py +80 -0
  210. pysisyphus/intcoords/OutOfPlane.py +59 -0
  211. pysisyphus/intcoords/PrimTypes.py +286 -0
  212. pysisyphus/intcoords/Primitive.py +137 -0
  213. pysisyphus/intcoords/RedundantCoords.py +659 -0
  214. pysisyphus/intcoords/RobustTorsion.py +59 -0
  215. pysisyphus/intcoords/Rotation.py +147 -0
  216. pysisyphus/intcoords/Stretch.py +31 -0
  217. pysisyphus/intcoords/Torsion.py +101 -0
  218. pysisyphus/intcoords/Torsion2.py +25 -0
  219. pysisyphus/intcoords/Translation.py +45 -0
  220. pysisyphus/intcoords/__init__.py +61 -0
  221. pysisyphus/intcoords/augment_bonds.py +126 -0
  222. pysisyphus/intcoords/derivatives.py +10512 -0
  223. pysisyphus/intcoords/eval.py +80 -0
  224. pysisyphus/intcoords/exceptions.py +37 -0
  225. pysisyphus/intcoords/findiffs.py +48 -0
  226. pysisyphus/intcoords/generate_derivatives.py +414 -0
  227. pysisyphus/intcoords/helpers.py +235 -0
  228. pysisyphus/intcoords/logging_conf.py +10 -0
  229. pysisyphus/intcoords/mp_derivatives.py +10836 -0
  230. pysisyphus/intcoords/setup.py +962 -0
  231. pysisyphus/intcoords/setup_fast.py +176 -0
  232. pysisyphus/intcoords/update.py +272 -0
  233. pysisyphus/intcoords/valid.py +89 -0
  234. pysisyphus/interpolate/Geodesic.py +93 -0
  235. pysisyphus/interpolate/IDPP.py +55 -0
  236. pysisyphus/interpolate/Interpolator.py +116 -0
  237. pysisyphus/interpolate/LST.py +70 -0
  238. pysisyphus/interpolate/Redund.py +152 -0
  239. pysisyphus/interpolate/__init__.py +9 -0
  240. pysisyphus/interpolate/helpers.py +34 -0
  241. pysisyphus/io/__init__.py +22 -0
  242. pysisyphus/io/aomix.py +178 -0
  243. pysisyphus/io/cjson.py +24 -0
  244. pysisyphus/io/crd.py +101 -0
  245. pysisyphus/io/cube.py +220 -0
  246. pysisyphus/io/fchk.py +184 -0
  247. pysisyphus/io/hdf5.py +49 -0
  248. pysisyphus/io/hessian.py +72 -0
  249. pysisyphus/io/mol2.py +146 -0
  250. pysisyphus/io/molden.py +293 -0
  251. pysisyphus/io/orca.py +189 -0
  252. pysisyphus/io/pdb.py +269 -0
  253. pysisyphus/io/psf.py +79 -0
  254. pysisyphus/io/pubchem.py +31 -0
  255. pysisyphus/io/qcschema.py +34 -0
  256. pysisyphus/io/sdf.py +29 -0
  257. pysisyphus/io/xyz.py +61 -0
  258. pysisyphus/io/zmat.py +175 -0
  259. pysisyphus/irc/DWI.py +108 -0
  260. pysisyphus/irc/DampedVelocityVerlet.py +134 -0
  261. pysisyphus/irc/Euler.py +22 -0
  262. pysisyphus/irc/EulerPC.py +345 -0
  263. pysisyphus/irc/GonzalezSchlegel.py +187 -0
  264. pysisyphus/irc/IMKMod.py +164 -0
  265. pysisyphus/irc/IRC.py +878 -0
  266. pysisyphus/irc/IRCDummy.py +10 -0
  267. pysisyphus/irc/Instanton.py +307 -0
  268. pysisyphus/irc/LQA.py +53 -0
  269. pysisyphus/irc/ModeKill.py +136 -0
  270. pysisyphus/irc/ParamPlot.py +53 -0
  271. pysisyphus/irc/RK4.py +36 -0
  272. pysisyphus/irc/__init__.py +31 -0
  273. pysisyphus/irc/initial_displ.py +219 -0
  274. pysisyphus/linalg.py +411 -0
  275. pysisyphus/line_searches/Backtracking.py +88 -0
  276. pysisyphus/line_searches/HagerZhang.py +184 -0
  277. pysisyphus/line_searches/LineSearch.py +232 -0
  278. pysisyphus/line_searches/StrongWolfe.py +108 -0
  279. pysisyphus/line_searches/__init__.py +9 -0
  280. pysisyphus/line_searches/interpol.py +15 -0
  281. pysisyphus/modefollow/NormalMode.py +40 -0
  282. pysisyphus/modefollow/__init__.py +10 -0
  283. pysisyphus/modefollow/davidson.py +199 -0
  284. pysisyphus/modefollow/lanczos.py +95 -0
  285. pysisyphus/optimizers/BFGS.py +99 -0
  286. pysisyphus/optimizers/BacktrackingOptimizer.py +113 -0
  287. pysisyphus/optimizers/ConjugateGradient.py +98 -0
  288. pysisyphus/optimizers/CubicNewton.py +75 -0
  289. pysisyphus/optimizers/FIRE.py +113 -0
  290. pysisyphus/optimizers/HessianOptimizer.py +1176 -0
  291. pysisyphus/optimizers/LBFGS.py +228 -0
  292. pysisyphus/optimizers/LayerOpt.py +411 -0
  293. pysisyphus/optimizers/MicroOptimizer.py +169 -0
  294. pysisyphus/optimizers/NCOptimizer.py +90 -0
  295. pysisyphus/optimizers/Optimizer.py +1084 -0
  296. pysisyphus/optimizers/PreconLBFGS.py +260 -0
  297. pysisyphus/optimizers/PreconSteepestDescent.py +7 -0
  298. pysisyphus/optimizers/QuickMin.py +74 -0
  299. pysisyphus/optimizers/RFOptimizer.py +181 -0
  300. pysisyphus/optimizers/RSA.py +99 -0
  301. pysisyphus/optimizers/StabilizedQNMethod.py +248 -0
  302. pysisyphus/optimizers/SteepestDescent.py +23 -0
  303. pysisyphus/optimizers/StringOptimizer.py +173 -0
  304. pysisyphus/optimizers/__init__.py +41 -0
  305. pysisyphus/optimizers/closures.py +301 -0
  306. pysisyphus/optimizers/cls_map.py +58 -0
  307. pysisyphus/optimizers/exceptions.py +6 -0
  308. pysisyphus/optimizers/gdiis.py +280 -0
  309. pysisyphus/optimizers/guess_hessians.py +311 -0
  310. pysisyphus/optimizers/hessian_updates.py +355 -0
  311. pysisyphus/optimizers/poly_fit.py +285 -0
  312. pysisyphus/optimizers/precon.py +153 -0
  313. pysisyphus/optimizers/restrict_step.py +24 -0
  314. pysisyphus/pack.py +172 -0
  315. pysisyphus/peakdetect.py +948 -0
  316. pysisyphus/plot.py +1031 -0
  317. pysisyphus/run.py +2106 -0
  318. pysisyphus/socket_helper.py +74 -0
  319. pysisyphus/stocastic/FragmentKick.py +132 -0
  320. pysisyphus/stocastic/Kick.py +81 -0
  321. pysisyphus/stocastic/Pipeline.py +303 -0
  322. pysisyphus/stocastic/__init__.py +21 -0
  323. pysisyphus/stocastic/align.py +127 -0
  324. pysisyphus/testing.py +96 -0
  325. pysisyphus/thermo.py +156 -0
  326. pysisyphus/trj.py +824 -0
  327. pysisyphus/tsoptimizers/RSIRFOptimizer.py +56 -0
  328. pysisyphus/tsoptimizers/RSPRFOptimizer.py +182 -0
  329. pysisyphus/tsoptimizers/TRIM.py +59 -0
  330. pysisyphus/tsoptimizers/TSHessianOptimizer.py +463 -0
  331. pysisyphus/tsoptimizers/__init__.py +23 -0
  332. pysisyphus/wavefunction/Basis.py +239 -0
  333. pysisyphus/wavefunction/DIIS.py +76 -0
  334. pysisyphus/wavefunction/__init__.py +25 -0
  335. pysisyphus/wavefunction/build_ext.py +42 -0
  336. pysisyphus/wavefunction/cart2sph.py +190 -0
  337. pysisyphus/wavefunction/diabatization.py +304 -0
  338. pysisyphus/wavefunction/excited_states.py +435 -0
  339. pysisyphus/wavefunction/gen_ints.py +1811 -0
  340. pysisyphus/wavefunction/helpers.py +104 -0
  341. pysisyphus/wavefunction/ints/__init__.py +0 -0
  342. pysisyphus/wavefunction/ints/boys.py +193 -0
  343. pysisyphus/wavefunction/ints/boys_table_N_64_xasym_27.1_step_0.01.npy +0 -0
  344. pysisyphus/wavefunction/ints/cart_gto3d.py +176 -0
  345. pysisyphus/wavefunction/ints/coulomb3d.py +25928 -0
  346. pysisyphus/wavefunction/ints/diag_quadrupole3d.py +10036 -0
  347. pysisyphus/wavefunction/ints/dipole3d.py +8762 -0
  348. pysisyphus/wavefunction/ints/int2c2e3d.py +7198 -0
  349. pysisyphus/wavefunction/ints/int3c2e3d_sph.py +65040 -0
  350. pysisyphus/wavefunction/ints/kinetic3d.py +8240 -0
  351. pysisyphus/wavefunction/ints/ovlp3d.py +3777 -0
  352. pysisyphus/wavefunction/ints/quadrupole3d.py +15054 -0
  353. pysisyphus/wavefunction/ints/self_ovlp3d.py +198 -0
  354. pysisyphus/wavefunction/localization.py +458 -0
  355. pysisyphus/wavefunction/multipole.py +159 -0
  356. pysisyphus/wavefunction/normalization.py +36 -0
  357. pysisyphus/wavefunction/pop_analysis.py +134 -0
  358. pysisyphus/wavefunction/shells.py +1171 -0
  359. pysisyphus/wavefunction/wavefunction.py +504 -0
  360. pysisyphus/wrapper/__init__.py +11 -0
  361. pysisyphus/wrapper/exceptions.py +2 -0
  362. pysisyphus/wrapper/jmol.py +120 -0
  363. pysisyphus/wrapper/mwfn.py +169 -0
  364. pysisyphus/wrapper/packmol.py +71 -0
  365. pysisyphus/xyzloader.py +168 -0
  366. pysisyphus/yaml_mods.py +45 -0
  367. thermoanalysis/LICENSE +674 -0
  368. thermoanalysis/QCData.py +244 -0
  369. thermoanalysis/__init__.py +0 -0
  370. thermoanalysis/config.py +3 -0
  371. thermoanalysis/constants.py +20 -0
  372. thermoanalysis/thermo.py +1011 -0
@@ -0,0 +1,260 @@
1
+ from collections import deque
2
+ from functools import partial
3
+ from typing import Literal, Optional
4
+
5
+ import numpy as np
6
+ from scipy.sparse.linalg import spsolve
7
+
8
+ from pysisyphus.calculators import Dimer
9
+ from pysisyphus.cos.GrowingNT import GrowingNT
10
+ from pysisyphus.Geometry import Geometry
11
+ from pysisyphus.line_searches import *
12
+ from pysisyphus.optimizers.closures import bfgs_multiply
13
+ from pysisyphus.optimizers.Optimizer import Optimizer
14
+ from pysisyphus.optimizers.precon import precon_getter, PreconKind
15
+
16
+
17
+ LineSearch = Literal["armijo", "armijo_fg", "strong_wolfe", "hz", None, False]
18
+
19
+
20
+ class PreconLBFGS(Optimizer):
21
+ def __init__(
22
+ self,
23
+ geometry: Geometry,
24
+ alpha_init: float = 1.0,
25
+ history: int = 7,
26
+ precon: bool = True,
27
+ precon_update: int = 1,
28
+ precon_getter_update: Optional[int] = None,
29
+ precon_kind: PreconKind = "full",
30
+ max_step_element: Optional[float] = None,
31
+ line_search: LineSearch = "armijo",
32
+ c_stab: Optional[float] = None,
33
+ **kwargs,
34
+ ) -> None:
35
+ """Preconditioned limited-memory BFGS optimizer.
36
+
37
+ See pysisyphus.optimizers.precon for related references.
38
+
39
+ Parameters
40
+ ----------
41
+ geometry
42
+ Geometry to be optimized.
43
+ alpha_init
44
+ Initial scaling factor for the first trial step in the excplicit line search.
45
+ history
46
+ History size. Keep last 'history' steps and gradient differences.
47
+ precon
48
+ Wheter to use preconditioning or not.
49
+ precon_update
50
+ Recalculate preconditioner P in every n-th cycle with the same topology.
51
+ precon_getter_update
52
+ Recalculate topology for preconditioner P in every n-th cycle. It is usually
53
+ sufficient to only determine the topology once at the beginning.
54
+ precon_kind
55
+ What types of primitive internal coordinates to consider in the preconditioner.
56
+ max_step_element
57
+ Maximum component of the absolute step vector when no line search is carried out.
58
+ line_search
59
+ Whether to use explicit line searches and if so, which kind of line search.
60
+ c_stab
61
+ Regularization constant c in (H + cI)⁻¹ in atomic units.
62
+
63
+ Other Parameters
64
+ ----------------
65
+ **kwargs
66
+ Keyword arguments passed to the Optimizer baseclass.
67
+ """
68
+ if precon:
69
+ assert geometry.coord_type in (
70
+ "cart",
71
+ "cartesian",
72
+ ), "Preconditioning makes only sense with 'coord_type: cart|cartesian'"
73
+ # Set before calling the superclass constructor so we can use the value
74
+ # in _set_opt_restart_info.
75
+ self.history = history
76
+
77
+ super().__init__(geometry, **kwargs)
78
+
79
+ self.alpha_init = alpha_init
80
+ self.precon = precon
81
+ # Disable preconditioning for 1 atom species, e.g., analytical potentials
82
+ if self.precon and (self.geometry.cart_coords.size == 3):
83
+ self.precon = None
84
+ self.precon_update = precon_update
85
+ self.precon_getter_update = precon_getter_update
86
+ self.precon_kind = precon_kind
87
+
88
+ self.P = None
89
+ try:
90
+ is_dimer = isinstance(self.geometry.calculator, Dimer)
91
+ # COS objectes may not have a calculator
92
+ except AttributeError:
93
+ is_dimer = False
94
+ go_uphill = is_dimer or isinstance(self.geometry, GrowingNT)
95
+
96
+ if c_stab is None:
97
+ self.log("No c_stab specified.")
98
+ if go_uphill:
99
+ c_stab = 0.103 # 1 eV/Ų
100
+ self.log(
101
+ "Found climbing calculation. Using higher regularization "
102
+ f"c_stab={c_stab:.4f} au/bohr**2."
103
+ )
104
+ else:
105
+ c_stab = 0.0103 # 0.1 eV/Ų
106
+
107
+ self.c_stab = float(c_stab)
108
+ self.log(f"Using c_stab={self.c_stab:.6f}")
109
+
110
+ if max_step_element is None and go_uphill:
111
+ max_step_element = 0.25
112
+ self.log(
113
+ f"Found climbing calculation. Using max_step_element={max_step_element:.2f}"
114
+ )
115
+ elif max_step_element is None and line_search in (None, False):
116
+ max_step_element = 0.2
117
+ self.max_step_element = max_step_element
118
+
119
+ # Disable linesearch if max_step_element is set
120
+ if self.max_step_element is not None:
121
+ self.log(
122
+ f"max_step_element={max_step_element:.6f} given. Setting "
123
+ "line_search to 'None'."
124
+ )
125
+ line_search = None
126
+
127
+ self.line_search = line_search
128
+ ls_cls = {
129
+ "armijo": Backtracking,
130
+ "armijo_fg": partial(Backtracking, use_grad=True),
131
+ "strong_wolfe": StrongWolfe,
132
+ "hz": HagerZhang,
133
+ None: None,
134
+ False: None,
135
+ }
136
+ self.line_search_cls = ls_cls[self.line_search]
137
+
138
+ if not self.restarted:
139
+ self.grad_diffs = deque(maxlen=self.history)
140
+ self.steps_ = deque(maxlen=self.history)
141
+ self.f_evals = 0
142
+ self.df_evals = 0
143
+
144
+ def get_precon_getter(self):
145
+ return precon_getter(
146
+ self.geometry, c_stab=self.c_stab, kind=self.precon_kind, logger=self.logger
147
+ )
148
+
149
+ def prepare_opt(self):
150
+ if self.precon:
151
+ self.precon_getter = self.get_precon_getter()
152
+
153
+ def _get_opt_restart_info(self):
154
+ opt_restart_info = {
155
+ "c_stab": self.c_stab,
156
+ "grad_diffs": np.array(self.grad_diffs).tolist(),
157
+ "steps_": np.array(self.steps_).tolist(),
158
+ "precon_kind": self.precon_kind,
159
+ "f_evals": self.f_evals,
160
+ "df_evals": self.df_evals,
161
+ }
162
+ return opt_restart_info
163
+
164
+ def _set_opt_restart_info(self, opt_restart_info):
165
+ self.grad_diffs = deque(
166
+ [np.array(gd) for gd in opt_restart_info["grad_diffs"]], maxlen=self.history
167
+ )
168
+ self.steps_ = deque(
169
+ [np.array(cd) for cd in opt_restart_info["steps_"]], maxlen=self.history
170
+ )
171
+
172
+ self.c_stab = opt_restart_info["c_stab"]
173
+ self.precon_kind = opt_restart_info["precon_kind"]
174
+ self.precon_getter = self.get_precon_getter()
175
+ self.f_evals = opt_restart_info["f_evals"]
176
+ self.df_evals = opt_restart_info["df_evals"]
177
+
178
+ def scale_max_element(self, step, max_step_element):
179
+ max_element = np.abs(step).max()
180
+ if max_element > max_step_element:
181
+ step *= max_step_element / max_element
182
+ return step
183
+
184
+ def optimize(self):
185
+ forces = self.geometry.forces
186
+ energy = self.geometry.energy
187
+
188
+ self.forces.append(forces)
189
+ self.energies.append(energy)
190
+
191
+ norm = np.linalg.norm(forces)
192
+ if not self.is_cos:
193
+ fmt = " >12.6f"
194
+ self.log(f" Current energy={energy:{fmt}} au")
195
+ if self.cur_cycle > 0:
196
+ prev_energy = self.energies[-2]
197
+ self.log(f"Previous energy={prev_energy:{fmt}} au")
198
+ self.log(f" ΔE={energy-prev_energy:{fmt}} au")
199
+ self.log(f"norm(forces)={norm:.6f}")
200
+
201
+ # Check for preconditioner getter update
202
+ if (
203
+ self.precon_getter_update
204
+ and self.cur_cycle > 0
205
+ and self.cur_cycle % self.precon_getter_update == 0
206
+ ):
207
+ self.precon_getter = self.get_precon_getter()
208
+ self.log("Calculated new preconditioner getter")
209
+
210
+ # If requested, construct preconditioner
211
+ if self.precon and (self.cur_cycle % self.precon_update == 0):
212
+ self.P = self.precon_getter(self.geometry.coords)
213
+ self.log("Calculated new preconditioner P")
214
+
215
+ # Determine step direction
216
+
217
+ # Preconditioned LBFGS in later cycles
218
+ if self.cur_cycle > 0:
219
+ self.grad_diffs.append(-forces - -self.forces[-2])
220
+ self.steps_.append(self.steps[-1])
221
+ step = bfgs_multiply(self.steps_, self.grad_diffs, forces, P=self.P)
222
+ # Preconditioned steepest descent in cycle 0
223
+ elif self.precon:
224
+ step = spsolve(self.P, forces)
225
+ # Steepest descent w/o preconditioner in cycle 0
226
+ else:
227
+ step = forces
228
+
229
+ step_norm = np.linalg.norm(step)
230
+ self.log(f"norm(unscaled step)={step_norm:.6f} au")
231
+
232
+ # Determine step length
233
+ if self.line_search_cls is not None:
234
+ kwargs = {
235
+ "geometry": self.geometry,
236
+ "p": step,
237
+ "f0": energy,
238
+ "g0": -forces,
239
+ "alpha_init": self.alpha_init,
240
+ }
241
+ line_search = self.line_search_cls(**kwargs)
242
+ line_search_result = line_search.run()
243
+ try:
244
+ alpha = line_search_result.alpha
245
+ step *= alpha
246
+ f_evals = line_search_result.f_evals
247
+ df_evals = line_search_result.df_evals
248
+ self.log(
249
+ f"Evaluated {f_evals} energies and {df_evals} gradients in line search."
250
+ )
251
+ self.f_evals += f_evals
252
+ self.df_evals += df_evals
253
+ except TypeError:
254
+ self.log("Line search did not converge!")
255
+ step = self.scale_max_element(step, self.max_step_element)
256
+ else:
257
+ step = self.scale_max_element(step, self.max_step_element)
258
+ step_norm = np.linalg.norm(step)
259
+ self.log(f"norm(step)={step_norm:.6f} au")
260
+ return step
@@ -0,0 +1,7 @@
1
+ from pysisyphus.optimizers.PreconLBFGS import PreconLBFGS
2
+
3
+
4
+ class PreconSteepestDescent(PreconLBFGS):
5
+
6
+ def __init__(self, geometry, alpha_init=0.5, **kwargs):
7
+ super().__init__(geometry, alpha_init=alpha_init, history=0, **kwargs)
@@ -0,0 +1,74 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.optimizers.Optimizer import Optimizer
4
+
5
+
6
+ class QuickMin(Optimizer):
7
+ def __init__(self, geometry, dt=0.35, **kwargs):
8
+ super(QuickMin, self).__init__(geometry, **kwargs)
9
+
10
+ self.dt = dt
11
+
12
+ def _get_opt_restart_info(self):
13
+ opt_restart_info = {
14
+ "velocity": self.velocities[-1].tolist(),
15
+ }
16
+ return opt_restart_info
17
+
18
+ def _set_opt_restart_info(self, opt_restart_info):
19
+ velocity = np.array(opt_restart_info["velocity"], dtype=float)
20
+ self.velocities = [
21
+ velocity,
22
+ ]
23
+
24
+ def prepare_opt(self):
25
+ self.velocities = [
26
+ np.zeros_like(self.geometry.coords),
27
+ ]
28
+
29
+ def reset(self):
30
+ if self.coords[-1].size != self.coords[-2].size:
31
+ self.log(
32
+ "Number of coordinates changed. Adapting velocity vector "
33
+ "to new coordinate number."
34
+ )
35
+ self.prepare_opt()
36
+ self.log("Resetted optimizer")
37
+
38
+ def optimize(self):
39
+ if self.align and self.is_cos:
40
+ (self.velocities[-1],), _, _ = self.fit_rigid(
41
+ vectors=(self.velocities[-1],)
42
+ )
43
+
44
+ prev_velocities = self.velocities[-1]
45
+ cur_forces = self.geometry.forces
46
+ self.forces.append(cur_forces)
47
+ self.energies.append(self.geometry.energy)
48
+
49
+ norm = np.linalg.norm(cur_forces)
50
+ if not self.is_cos:
51
+ self.log(f"Current energy={self.energies[-1]:.6f}")
52
+ self.log(f"norm(forces)={norm:.6f}")
53
+
54
+ if self.cur_cycle == 0:
55
+ tmp_velocities = np.zeros_like(prev_velocities)
56
+ else:
57
+ overlap = prev_velocities.dot(cur_forces)
58
+ self.log(f"Overlap of previous and current forces: {overlap:.6f}")
59
+ if overlap > 0:
60
+ tmp_velocities = overlap * cur_forces / cur_forces.dot(cur_forces)
61
+ else:
62
+ tmp_velocities = np.zeros_like(prev_velocities)
63
+ self.log("Zeroed velocities")
64
+
65
+ accelerations = cur_forces / self.geometry.masses_rep
66
+ cur_velocities = tmp_velocities + self.dt * accelerations
67
+ steps = cur_velocities * self.dt + 1 / 2 * accelerations * self.dt**2
68
+ steps = self.scale_by_max_step(steps)
69
+ self.velocities.append(cur_velocities)
70
+ velo_norm = np.linalg.norm(cur_velocities)
71
+ acc_norm = np.linalg.norm(accelerations)
72
+ self.log(f"norm(v) = {velo_norm:.4f}, norm(a) = {acc_norm:.4f}")
73
+
74
+ return steps
@@ -0,0 +1,181 @@
1
+ # [1] http://aip.scitation.org/doi/10.1063/1.1515483 Optimization review
2
+ # [2] https://doi.org/10.1063/1.450914 Trust region method
3
+ # [3] 10.1007/978-0-387-40065-5 Numerical optimization
4
+ # [4] 10.1007/s00214-016-1847-3 Explorations of some refinements
5
+
6
+
7
+ import numpy as np
8
+
9
+ from pysisyphus.Geometry import Geometry
10
+ from pysisyphus.helpers_pure import rms
11
+ from pysisyphus.optimizers.HessianOptimizer import HessianOptimizer
12
+ from pysisyphus.optimizers.poly_fit import poly_line_search
13
+ from pysisyphus.optimizers.gdiis import gdiis, gediis
14
+
15
+ import torch
16
+
17
+ class RFOptimizer(HessianOptimizer):
18
+ def __init__(
19
+ self,
20
+ geometry: Geometry,
21
+ line_search: bool = True,
22
+ gediis: bool = False,
23
+ gdiis: bool = True,
24
+ gdiis_thresh: float = 2.5e-3,
25
+ gediis_thresh: float = 1e-2,
26
+ gdiis_test_direction: bool = True,
27
+ max_micro_cycles: int = 25,
28
+ adapt_step_func: bool = False,
29
+ **kwargs,
30
+ ) -> None:
31
+ """
32
+ Rational function Optimizer.
33
+
34
+ Parameters
35
+ ----------
36
+ geometry
37
+ Geometry to be optimized.
38
+ line_search
39
+ Whether to carry out implicit line searches.
40
+ gediis
41
+ Whether to enable GEDIIS.
42
+ gdiis
43
+ Whether to enable GDIIS.
44
+ gdiis_thresh
45
+ Threshold for rms(forces) to enable GDIIS.
46
+ gediis_thresh
47
+ Threshold for rms(step) to enable GEDIIS.
48
+ gdiis_test_direction
49
+ Whether to the overlap of the RFO step and the GDIIS step.
50
+ max_micro_cycles
51
+ Number of restricted-step microcycles. Disabled by default.
52
+ adapt_step_func
53
+ Whether to switch between shifted Newton and RFO-steps.
54
+
55
+ Other Parameters
56
+ ----------------
57
+ **kwargs
58
+ Keyword arguments passed to the Optimizer/HessianOptimizer baseclass.
59
+ """
60
+ super().__init__(geometry, max_micro_cycles=max_micro_cycles, **kwargs)
61
+
62
+ self.line_search = line_search
63
+ self.gediis = gediis
64
+ self.gdiis = gdiis
65
+ self.gdiis_thresh = gdiis_thresh # Will be compared to rms(step)
66
+ self.gediis_thresh = gediis_thresh # Will be compared to rms(forces)
67
+ self.gdiis_test_direction = gdiis_test_direction
68
+ self.adapt_step_func = adapt_step_func
69
+
70
+ self.successful_gediis = 0
71
+ self.successful_gdiis = 0
72
+ self.successful_line_search = 0
73
+
74
+ def optimize(self):
75
+ energy, gradient, H, big_eigvals, big_eigvecs, resetted = self.housekeeping()
76
+ step_func, pred_func = self.get_step_func(big_eigvals, gradient)
77
+
78
+ forces_act = self.active_list(self.forces)
79
+ coords_act = self.active_list(self.coords)
80
+ steps_act = self.active_list(self.steps)
81
+
82
+ ref_gradient = gradient.copy() if isinstance(gradient, np.ndarray) else gradient.clone()
83
+ # Reference step, used for judging the proposed GDIIS step
84
+ ref_step = step_func(big_eigvals, big_eigvecs, gradient) # heavy-compute
85
+
86
+ # Right everything is in place to check for convergence. If all values are below
87
+ # the thresholds, there is no need to do additional inter/extrapolations.
88
+ if self.check_convergence(ref_step)[0]: # Drop conv_info
89
+ self.log("Convergence achieved! Skipping inter/extrapolation.")
90
+ return ref_step
91
+
92
+ # Try to interpolate an intermediate geometry, either from GDIIS or line search.
93
+ #
94
+ # Set some defaults
95
+ ip_gradient = None
96
+ ip_step = None
97
+ diis_result = None
98
+
99
+ # Check if we can do GDIIS or GEDIIS. If we (can) do a line search is decided
100
+ # after trying GDIIS.
101
+ rms_forces = rms(gradient)
102
+ rms_step = rms(ref_step)
103
+ can_diis = (rms_step <= self.gdiis_thresh) and (not resetted)
104
+ can_gediis = (rms_forces <= self.gediis_thresh) and (not resetted)
105
+
106
+ # GDIIS / GEDIIS, prefer GDIIS over GEDIIS
107
+ if self.gdiis and can_diis:
108
+ # Gradients as error vectors
109
+ if isinstance(ref_step, torch.Tensor):
110
+ err_vecs = -torch.from_numpy(np.array(forces_act)).to(ref_step.dtype).to(ref_step.device)
111
+ else:
112
+ err_vecs = -np.array(forces_act)
113
+ diis_result = gdiis(
114
+ err_vecs,
115
+ coords_act,
116
+ forces_act,
117
+ ref_step,
118
+ test_direction=self.gdiis_test_direction,
119
+ )
120
+ self.successful_gdiis += 1 if diis_result else 0
121
+ # Don't try GEDIIS if GDIIS failed. If GEDIIS should be tried after GDIIS failed
122
+ # comment the line below and uncomment the line following it.
123
+ elif self.gediis and can_gediis:
124
+ # if self.gediis and can_gediis and (diis_result == None):
125
+ diis_result = gediis(coords_act, self.energies, forces_act, hessian=H)
126
+ self.successful_gediis += 1 if diis_result else 0
127
+
128
+ try:
129
+ ip_coords = diis_result.coords
130
+ if isinstance(ip_coords, torch.Tensor):
131
+ ip_step = ip_coords - torch.from_numpy(coords_act[-1]).to(ip_coords.device, ip_coords.dtype)
132
+ else:
133
+ ip_step = ip_coords - coords_act[-1]
134
+ ip_gradient = -diis_result.forces
135
+ # When diis_result is None
136
+ except AttributeError:
137
+ self.log("GDIIS didn't succeed.")
138
+
139
+ # Try line search if GDIIS failed or not requested
140
+ if self.line_search and (diis_result is None) and (not resetted):
141
+ ip_energy, ip_gradient, ip_step = poly_line_search(
142
+ energy,
143
+ self.energies[-2],
144
+ gradient,
145
+ -forces_act[-2],
146
+ steps_act[-1],
147
+ cubic_max_x=-1,
148
+ quartic_max_x=2,
149
+ logger=self.logger,
150
+ )
151
+ self.successful_line_search += 1 if ip_gradient is not None else 0
152
+
153
+ # Use the interpolated gradient for the RFO step if interpolation succeeded
154
+ if (ip_gradient is not None) and (ip_step is not None):
155
+ gradient = ip_gradient
156
+ step = step_func(big_eigvals, big_eigvecs, gradient) # heavy-compute
157
+ # Form full step with interpolation offset.
158
+ if isinstance(ip_step, torch.Tensor):
159
+ ip_step = ip_step.detach().cpu().numpy()
160
+ step = step + ip_step
161
+ # Keep the original gradient when the interpolation failed; reuse ref_step.
162
+ else:
163
+ step = ref_step
164
+
165
+ # Use the original, actually calculated, gradient
166
+ prediction = pred_func(ref_gradient, H, step)
167
+ self.predicted_energy_changes.append(prediction)
168
+
169
+ step = self.full_from_active(step)
170
+ if isinstance(step, torch.Tensor):
171
+ step = step.cpu().numpy()
172
+ return step
173
+
174
+ def postprocess_opt(self):
175
+ msg = (
176
+ f"Successful invocations:\n"
177
+ f"\t GEDIIS: {self.successful_gediis}\n"
178
+ f"\t GDIIS: {self.successful_gdiis}\n"
179
+ f"\tLine Search: {self.successful_line_search}\n"
180
+ )
181
+ self.log(msg)
@@ -0,0 +1,99 @@
1
+ from math import sqrt
2
+
3
+ import numpy as np
4
+ from scipy.optimize import root_scalar
5
+
6
+ from pysisyphus.optimizers.HessianOptimizer import HessianOptimizer
7
+
8
+
9
+ class RSA(HessianOptimizer):
10
+ """The Importance of Step Control in Optimization Methods, del Campo, 2009."""
11
+
12
+ def optimize(self):
13
+ energy, gradient, H, big_eigvals, big_eigvecs, resetted = self.housekeeping()
14
+
15
+ assert big_eigvals.argmin() == 0
16
+ min_eigval = big_eigvals[0]
17
+ pos_definite = min_eigval > 0.0
18
+ gradient_trans = big_eigvecs.T.dot(gradient)
19
+ # This will be also be True when we come close to a minimizer,
20
+ # but then the Hessian will also be positive definite and a
21
+ # simple Newton step will be used.
22
+ hard_case = abs(gradient_trans[0]) <= 1e-6
23
+ self.log(f"Smallest eigenvalue: {min_eigval:.6f}")
24
+ self.log(f"Positive definite Hessian: {pos_definite}")
25
+ self.log(f"Hard case: {hard_case}")
26
+
27
+ def get_step(lambda_):
28
+ return -gradient_trans / (big_eigvals + lambda_)
29
+
30
+ # Unshifted Newton step
31
+ newton_step = get_step(0.0)
32
+ newton_norm = np.linalg.norm(newton_step)
33
+
34
+ # def on_trust_radius(step, thresh=1e-3):
35
+ # return abs(self.trust_radius - np.linalg.norm(step)) <= thresh
36
+
37
+ def on_trust_radius_lin(step):
38
+ return 1 / self.trust_radius - 1 / np.linalg.norm(step)
39
+
40
+ def finalize_step(lambda_):
41
+ step = get_step(lambda_)
42
+ step = big_eigvecs.dot(step)
43
+ predicted_change = step.dot(gradient) + 0.5 * step.dot(H).dot(step)
44
+ self.predicted_energy_changes.append(predicted_change)
45
+ return step
46
+
47
+ # Simplest case. Positive definite Hessian and predicted step is
48
+ # already in trust radius.
49
+ if pos_definite and newton_norm <= self.trust_radius:
50
+ lambda_ = 0.0
51
+ self.log("Using unshifted Newton step.")
52
+ return finalize_step(lambda_)
53
+
54
+ # If the Hessian is not positive definite or if the step is too
55
+ # long we have to determine the shift parameter lambda.
56
+ rs_kwargs = {
57
+ "f": lambda lambda_: on_trust_radius_lin(get_step(lambda_)),
58
+ "xtol": 1e-3,
59
+ # Would otherwise be chosen automatically, but we set it
60
+ # here explicitly for verbosity.
61
+ "method": "brentq",
62
+ }
63
+
64
+ def root_search(bracket):
65
+ rs_kwargs.update(
66
+ {
67
+ "bracket": bracket,
68
+ "x0": bracket[0] + 1e-3,
69
+ }
70
+ )
71
+ res = root_scalar(**rs_kwargs)
72
+ return res
73
+
74
+ BRACKET_END = 1e10
75
+ if not hard_case:
76
+ bracket_start = 0.0 if pos_definite else -min_eigval - 1e-3
77
+ bracket = (bracket_start, BRACKET_END)
78
+ res = root_search(bracket)
79
+ assert res.converged
80
+ return finalize_step(res.root)
81
+
82
+ # Hard case.
83
+ # First we try the bracket (-b1, ∞)
84
+ bracket = (-min_eigval, BRACKET_END)
85
+ res = root_search(bracket)
86
+ if res.converged:
87
+ return finalize_step(res.root)
88
+
89
+ # Now we would try the bracket (-b2, -b1). The resulting step should have
90
+ # a suitable length, but the (shifted) Hessian would have an incorrect
91
+ # eigenvalue spectrum (not positive definite). To solve this we use a
92
+ # different formula to calculate the step.
93
+ without_first = gradient_trans[1:] / (big_eigvals[1:] - min_eigval)
94
+ tau = sqrt(self.trust_radius ** 2 - (without_first ** 2).sum())
95
+ step_trans = [tau] + -without_first.tolist()
96
+ step = big_eigvecs.dot(step_trans)
97
+ predicted_change = step.dot(gradient) + 0.5 * step.dot(H).dot(step)
98
+ self.predicted_energy_changes.append(predicted_change)
99
+ return step