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,463 @@
1
+ from typing import List, Optional
2
+
3
+ import h5py
4
+ import numpy as np
5
+
6
+ from pysisyphus.Geometry import Geometry
7
+ from pysisyphus.helpers_pure import log
8
+ from pysisyphus.intcoords.augment_bonds import augment_bonds
9
+ from pysisyphus.intcoords.PrimTypes import normalize_prim_input, normalize_prim_inputs
10
+ from pysisyphus.optimizers import poly_fit
11
+ from pysisyphus.optimizers.guess_hessians import ts_hessian, HessInit
12
+ from pysisyphus.optimizers.HessianOptimizer import HessianOptimizer, HessUpdate
13
+ from pysisyphus.optimizers.Optimizer import get_data_model, get_h5_group
14
+
15
+ from pysisyphus.helpers import array2string
16
+ import torch
17
+
18
+ class TSHessianOptimizer(HessianOptimizer):
19
+ """Optimizer to find first-order saddle points."""
20
+
21
+ valid_updates = ("bofill", "ts_bfgs", "ts_bfgs_org", "ts_bfgs_rev")
22
+
23
+ def __init__(
24
+ self,
25
+ geometry: Geometry,
26
+ roots: Optional[List[int]] = None,
27
+ root: int = 0,
28
+ hessian_ref: Optional[str] = None,
29
+ rx_modes=None,
30
+ prim_coord=None,
31
+ rx_coords=None,
32
+ hessian_init: HessInit = "calc",
33
+ hessian_update: HessUpdate = "bofill",
34
+ hessian_recalc_reset: bool = True,
35
+ max_micro_cycles: int = 50,
36
+ trust_radius: float = 0.3,
37
+ trust_max: float = 0.5,
38
+ augment_bonds: bool = False,
39
+ min_line_search: bool = False,
40
+ max_line_search: bool = False,
41
+ assert_neg_eigval: bool = False,
42
+ **kwargs,
43
+ ) -> None:
44
+ """Baseclass for transition state optimizers utilizing Hessian information.
45
+
46
+ Several arguments expect a typed primitive or an iterable of typed primitives.
47
+ A typed primitive is specified as (PrimType, int, int, ...), e.g., for a bond
48
+ between atoms 0 and 1: (BOND, 0, 1) or for a bend between the atom triple 0, 1, 2
49
+ as (BEND, 0, 1, 2).
50
+
51
+ Parameters
52
+ ----------
53
+ geometry
54
+ Geometry to be optimized.
55
+ roots
56
+ Indices of modes to maximize along, e.g., to optimize saddle points of 2nd order.
57
+ Overrides 'root'.
58
+ root
59
+ Index of imaginary mode to maximize along. Shortcut for 'roots' with only one root.
60
+ hessian_ref
61
+ Filename pointing to a pysisyphus HDF5 Hessian.
62
+ rx_modes : iterable of (iterable of (typed_prim, phase_factor))
63
+ Select initial root(s) by overlap with a modes constructed from the given
64
+ typed primitives with respective phase factors.
65
+ prim_coord : typed_prim
66
+ Select initial root/imaginary mode by overlap with this internal coordinate.
67
+ Shortcut for 'rx_modes' with only one internal coordinate.
68
+ rx_coords : iterable of (typed_prim)
69
+ Construct imaginary mode comprising the given typed prims by modifying
70
+ a model Hessian.
71
+ hessian_init
72
+ Type of initial model Hessian.
73
+ hessian_update
74
+ Type of Hessian update. Defaults to BFGS for minimizations and Bofill
75
+ for saddle point searches.
76
+ hessian_recalc_reset
77
+ Whether to skip Hessian recalculation after reset. Undocumented.
78
+ max_micro_cycles
79
+ Maximum number of RS iterations.
80
+ trust_radius
81
+ Initial trust radius in whatever unit the optimization is carried out.
82
+ trust_max
83
+ Maximum trust radius.
84
+ augment_bonds
85
+ Try to derive additional streching coordinates from the imaginary mode.
86
+ min_line_search
87
+ Carry out line search along the imaginary mode.
88
+ max_line_search
89
+ Carry out line search in the subspace that is minimized.
90
+ assert_neg_eigval
91
+ Check for the existences for at least one significant negative eigenvalue.
92
+ If enabled and no negative eigenvalue is present the optimization will be
93
+ aborted.
94
+
95
+ Other Parameters
96
+ ----------------
97
+ **kwargs
98
+ Keyword arguments passed to the HessianOptimizer/Optimizer baseclass.
99
+ """
100
+
101
+ assert (
102
+ hessian_update in self.valid_updates
103
+ ), f"Invalid Hessian update. Please chose from: {self.valid_updates}!"
104
+
105
+ super().__init__(
106
+ geometry,
107
+ hessian_init=hessian_init,
108
+ hessian_update=hessian_update,
109
+ trust_radius=trust_radius,
110
+ trust_max=trust_max,
111
+ hessian_recalc_reset=hessian_recalc_reset,
112
+ **kwargs,
113
+ )
114
+
115
+ if (root is not None) and (roots is None):
116
+ roots = [
117
+ root,
118
+ ]
119
+ elif roots is None:
120
+ roots = list()
121
+ self.roots = roots
122
+ self.log(f"{self.roots=}")
123
+ self.hessian_ref = hessian_ref
124
+ try:
125
+ with h5py.File(self.hessian_ref, "r") as handle:
126
+ self.hessian_ref = handle["hessian"][:]
127
+ _ = self.geometry.coords.size
128
+ expected_shape = (_, _)
129
+ shape = self.hessian_ref.shape
130
+ # Hessian is not yet converted to the correct coordinate system if
131
+ # coord_type != cart.
132
+ assert (
133
+ self.geometry.coord_type == "cart"
134
+ ), "hessian_ref with internal coordinates are not yet supported."
135
+ assert shape == expected_shape, (
136
+ f"Shape of reference Hessian {shape} doesn't match the expected "
137
+ f"shape {expected_shape} of the Hessian for the current coordinates!"
138
+ )
139
+ except OSError as err:
140
+ self.log(
141
+ f"Tried to load reference Hessian from '{self.hessian_ref}' "
142
+ "but the file could not be found."
143
+ )
144
+ self.hessian_ref = None
145
+ except (ValueError, TypeError) as err:
146
+ self.log(f"No reference Hessian provided.")
147
+
148
+ # Select initial root according to highest contribution of 'prim_coord'
149
+ if prim_coord is not None:
150
+ self.log("'prim_coord' given. Overwriting/setting 'rx_modes'.")
151
+ rx_modes = [[[prim_coord, 1.0]]]
152
+ self.prim_coord = prim_coord
153
+
154
+ # Construct initial imaginary mode from the given inputs while respecting
155
+ # the given weight/phase factors.
156
+ self.rx_modes = rx_modes
157
+
158
+ # Construct initial imaginary mode according the primitive internals in
159
+ # 'rx_coords' by modifying a model Hessian.
160
+ if rx_coords is not None:
161
+ rx_coords = normalize_prim_inputs(rx_coords)
162
+ self.rx_coords = rx_coords
163
+
164
+ # Bond augmentation is only useful with calculated hessians
165
+ self.augment_bonds = augment_bonds and (self.hessian_init == "calc")
166
+ self.min_line_search = min_line_search
167
+ self.max_line_search = max_line_search
168
+ self.assert_neg_eigval = assert_neg_eigval
169
+
170
+ self.ts_modes = list()
171
+ self.max_micro_cycles = max_micro_cycles
172
+ self.prim_contrib_thresh = 0.05
173
+
174
+ self.alpha0 = 1
175
+
176
+ @property
177
+ def root(self):
178
+ return self.roots[0]
179
+
180
+ @root.setter
181
+ def root(self, root):
182
+ raise Exception("Setting 'self.root' is deprecated. Set 'self.roots' instead.")
183
+
184
+ @property
185
+ def roots(self):
186
+ return self._roots
187
+
188
+ @roots.setter
189
+ def roots(self, roots):
190
+ self._roots = np.array(roots, dtype=int)
191
+
192
+ def prepare_opt(self, *args, **kwargs):
193
+ if self.augment_bonds:
194
+ self.geometry = augment_bonds(self.geometry, root=self.root)
195
+ # Update data model and HD5 shapes, as the number of coordinates
196
+ # may have changed.
197
+ if self.dump:
198
+ self.data_model = get_data_model(
199
+ self.geometry, self.is_cos, self.max_cycles
200
+ )
201
+ # self.h5_group = get_h5_group(
202
+ # self.h5_fn, self.h5_group_name, self.data_model
203
+ # )
204
+
205
+ # Calculate/set initial hessian
206
+ super().prepare_opt(*args, **kwargs)
207
+
208
+ # Assume a guess hessian when not calculated. This hessian has to be
209
+ # modified according to the assumed reaction coordinates.
210
+ if self.hessian_init != "calc" and (self.rx_coords is not None):
211
+ assert self.geometry.coord_type != "cart", (
212
+ "Using a modified guess Hessian for TS-optimizations is "
213
+ "only supported in redundand internal coordinates "
214
+ "(coord_type=redund)"
215
+ )
216
+ prim_inds = [
217
+ self.geometry.internal.get_index_of_typed_prim(rxc)
218
+ for rxc in self.rx_coords
219
+ ]
220
+ missing_prim_inds = [
221
+ self.rx_coords[i] for i, _ in enumerate(prim_inds) if _ is None
222
+ ]
223
+ assert len(missing_prim_inds) == 0, (
224
+ "Some of the requested reaction coordinates are not defined: "
225
+ f"{missing_prim_inds}"
226
+ )
227
+ self.H = ts_hessian(self.H, coord_inds=prim_inds)
228
+
229
+ # Determiniation of initial mode either by using a provided
230
+ # reference hessian, or by using a supplied root.
231
+
232
+ if isinstance(self.H, torch.Tensor):
233
+ eigvals, eigvecs = torch.linalg.eigh(self.H)
234
+ eigvals = eigvals.cpu().numpy()
235
+ else:
236
+ eigvals, eigvecs = np.linalg.eigh(self.H)
237
+ neg_inds = eigvals < -self.small_eigval_thresh
238
+ self.log_negative_eigenvalues(eigvals, "Initial ")
239
+
240
+ self.log("Determining initial TS mode to follow uphill.")
241
+ # Select an initial TS-mode by highest overlap with eigenvectors from
242
+ # reference Hessian.
243
+ if self.hessian_ref is not None:
244
+ eigvals_ref, eigvecs_ref = np.linalg.eigh(self.hessian_ref)
245
+ self.log_negative_eigenvalues(eigvals_ref, "Reference ")
246
+ assert eigvals_ref[0] < -self.small_eigval_thresh
247
+ ref_mode = eigvecs_ref[:, 0]
248
+ overlaps = np.einsum("ij,j->i", eigvecs.T, ref_mode)
249
+ ovlp_str = array2string(overlaps, precision=4)
250
+ self.log(
251
+ "Overlaps between eigenvectors of current Hessian "
252
+ f"TS mode from reference Hessian:"
253
+ )
254
+ self.log(f"\t{ovlp_str}")
255
+
256
+ root = np.abs(overlaps).argmax()
257
+ self.roots = [
258
+ root,
259
+ ]
260
+ print(
261
+ "Highest overlap between reference TS mode and "
262
+ f"eigenvector {self.root:02d}."
263
+ )
264
+ used_str = "overlap with reference TS mode"
265
+ # Construct an approximate initial mode according to user input
266
+ # and calculate overlaps with the current eigenvectors.
267
+ elif self.rx_modes is not None:
268
+ self.log(f"Constructing reference mode, according to user input")
269
+ assert self.geometry.coord_type != "cart"
270
+ int_ = self.geometry.internal
271
+ modes = list()
272
+ for i, rx_mode in enumerate(self.rx_modes):
273
+ mode = np.zeros_like(self.geometry.coords)
274
+ for typed_prim, val in rx_mode:
275
+ typed_prim = normalize_prim_input(typed_prim)[0]
276
+ ind = int_.get_index_of_typed_prim(typed_prim)
277
+ mode[ind] = val
278
+ self.log(
279
+ f"\tIndex {ind} (coordinate {typed_prim}) set to {val:.4f}"
280
+ )
281
+ mode /= np.linalg.norm(mode)
282
+ modes.append(mode)
283
+ mode_str = array2string(mode, precision=2)
284
+ self.log(f"Normalized reference mode {i:02d}: {mode_str}")
285
+
286
+ # Calculate overlaps in non-redundant subspace by zeroing overlaps
287
+ # in the redundant subspace.
288
+ small_inds = np.abs(eigvals) < self.small_eigval_thresh
289
+ # Take absolute value, because sign of eigenvectors is ambiguous.
290
+ ovlps = np.abs(np.einsum("ij,ki->kj", eigvecs, modes))
291
+ ovlps[:, small_inds] = 0.0
292
+ self.roots = ovlps.argmax(axis=1)
293
+ used_str = "overlap with user-generated mode"
294
+ else:
295
+ used_str = f"root(s)={self.roots}"
296
+ self.log(f"Used {used_str} to select inital TS mode.")
297
+
298
+ # Below, some code is found, that checks if the chosen root(s) are a
299
+ # sensible choice, i.e., if they are negative. Currently, it is commented out,
300
+ # as we can also start from the convex region of the PES.
301
+ #
302
+ # Check if the selected mode (root) is a sensible choice.
303
+ #
304
+ # small_eigval_thresh is positive and we dont take the absolute value
305
+ # of the eigenvalues. So we multiply small_eigval_thresh to get a
306
+ # negative number.
307
+ # assert (eigvals[self.roots] < -self.small_eigval_thresh).all(), (
308
+ # "Expected negative eigenvalue(s)! Eigenvalues of selected TS-modes "
309
+ # f"are above the the threshold of self.small_eigval_thresh:.6e}!"
310
+ # )
311
+
312
+ # Select an initial TS-mode by root index. self.root may have been
313
+ # modified by using a reference hessian.
314
+ self.ts_modes = eigvecs[:, self.roots].T
315
+ self.ts_mode_eigvals = eigvals[self.roots]
316
+ self.log(
317
+ f"Using root(s) {self.roots} with eigenvalues "
318
+ f"{array2string(self.ts_mode_eigvals, precision=6)} as TS mode.\n"
319
+ )
320
+
321
+ def update_ts_mode(self, eigvals, eigvecs):
322
+ neg_eigval_inds = eigvals < -self.small_eigval_thresh
323
+ neg_num = neg_eigval_inds.sum()
324
+ self.log_negative_eigenvalues(eigvals)
325
+
326
+ # When we left the convex region of the PES we only compare to other
327
+ # imaginary modes ... is this a bad idea? Maybe we should use all modes
328
+ # for the overlaps?!
329
+ if (self.ts_mode_eigvals < 0).all() and neg_num > 0:
330
+ infix = "imaginary "
331
+ ovlp_eigvecs = eigvecs[:, :neg_num]
332
+ eigvals = eigvals[:neg_num]
333
+ # When the eigenvalue corresponding to the TS mode has been negative once,
334
+ # we should not lose all negative eigenvalues. If this happens something went
335
+ # wrong and we crash :)
336
+ elif self.assert_neg_eigval and neg_num == 0:
337
+ raise AssertionError(
338
+ "Need at least 1 negative eigenvalue for TS optimization."
339
+ )
340
+ # Use all eigenvectors for overlaps when the eigenvalue corresponding to the TS
341
+ # mode is still positive.
342
+ else:
343
+ infix = ""
344
+ ovlp_eigvecs = eigvecs
345
+
346
+ if (
347
+ self.using_active_dofs
348
+ and self.ts_modes is not None
349
+ and self.ts_modes.shape[1] != ovlp_eigvecs.shape[0]
350
+ ):
351
+ self.log("Projecting previous TS mode(s) onto active DOFs.")
352
+ if isinstance(self.ts_modes, torch.Tensor):
353
+ self.ts_modes = torch.stack(
354
+ [self.active_from_full(mode) for mode in self.ts_modes]
355
+ )
356
+ else:
357
+ self.ts_modes = np.stack(
358
+ [self.active_from_full(mode) for mode in self.ts_modes]
359
+ )
360
+
361
+ # Select new TS mode according to biggest overlap with previous TS mode.
362
+ self.log(f"Overlaps of previous TS mode with current {infix}mode(s):")
363
+ if isinstance(eigvecs, torch.Tensor):
364
+ ovlps = torch.abs(torch.einsum("ij,ki->kj", ovlp_eigvecs, self.ts_modes))
365
+ ovlps = ovlps.cpu().numpy()
366
+ else:
367
+ ovlps = np.abs(np.einsum("ij,ki->kj", ovlp_eigvecs, self.ts_modes))
368
+ for i, ovlp in enumerate(ovlps):
369
+ self.log(f"\tTS mode {i:02d}: {array2string(ovlp, precision=3)}")
370
+ max_ovlp_inds = np.argmax(ovlps, axis=1)
371
+ for i, _ in enumerate(self.ts_modes):
372
+ max_ovlp_ind = max_ovlp_inds[i].argmax()
373
+ self.log(
374
+ f"Mode {i}: highest overlap: {ovlps[i, max_ovlp_ind]:.6f} with mode "
375
+ f"{max_ovlp_ind}"
376
+ )
377
+ self.roots = max_ovlp_inds
378
+ self.ts_modes = ovlp_eigvecs.T[self.roots]
379
+ self.ts_mode_eigvals = eigvals[self.roots]
380
+
381
+ @staticmethod
382
+ def do_line_search(e0, e1, g0, g1, prev_step, maximize, logger=None):
383
+ poly_fit_kwargs = {
384
+ "e0": e0,
385
+ "e1": e1,
386
+ "g0": g0,
387
+ "g1": g1,
388
+ "maximize": maximize,
389
+ }
390
+ if not maximize:
391
+ poly_fit_kwargs.update(
392
+ {
393
+ "g0": prev_step.dot(g0),
394
+ "g1": prev_step.dot(g1),
395
+ }
396
+ )
397
+ prefix = "Max" if maximize else "Min"
398
+
399
+ fit_result = poly_fit.quartic_fit(**poly_fit_kwargs)
400
+ fit_energy = None
401
+ fit_grad = None
402
+ fit_step = None
403
+ if fit_result and (0.0 < fit_result.x <= 2.0):
404
+ x = fit_result.x
405
+ log(logger, f"{prefix}-subpsace interpolation succeeded: x={x:.6f}")
406
+ fit_energy = fit_result.y
407
+ fit_step = (1 - x) * -prev_step
408
+ fit_grad = (1 - x) * g0 + x * g1
409
+ return fit_energy, fit_grad, fit_step
410
+
411
+ def step_and_grad_from_line_search(
412
+ self,
413
+ energy,
414
+ gradient_trans,
415
+ eigvecs,
416
+ min_indices,
417
+ max_indices,
418
+ ):
419
+ ip_step = np.zeros_like(gradient_trans)
420
+ ip_gradient_trans = gradient_trans.copy()
421
+
422
+ if self.max_line_search and self.cur_cycle > 0:
423
+ prev_energy = self.energies[-2]
424
+ prev_gradient = -self.forces[-2]
425
+ try:
426
+ prev_gradient_trans = eigvecs.T.dot(prev_gradient)
427
+ prev_step = self.steps[-1]
428
+ prev_step_trans = eigvecs.T.dot(prev_step)
429
+ # Will be raised when coordinates were rebuilt and the array shapes differe.
430
+ except ValueError:
431
+ return ip_step, ip_gradient_trans
432
+
433
+ # Max subspace
434
+ # max_energy, max_gradient, max_step = self.do_max_line_search(
435
+ max_energy, max_gradient, max_step = self.do_line_search(
436
+ prev_energy,
437
+ energy,
438
+ prev_gradient_trans[max_indices],
439
+ gradient_trans[max_indices],
440
+ prev_step=prev_step_trans[max_indices],
441
+ maximize=True,
442
+ logger=self.logger,
443
+ )
444
+ if max_gradient is not None:
445
+ ip_gradient_trans[max_indices] = max_gradient
446
+ ip_step[max_indices] = max_step
447
+
448
+ if self.min_line_search and self.cur_cycle > 0:
449
+ # Min subspace
450
+ # min_energy, min_gradient, min_step = self.do_min_line_search(
451
+ min_energy, min_gradient, min_step = self.do_line_search(
452
+ prev_energy,
453
+ energy,
454
+ prev_gradient_trans[min_indices],
455
+ gradient_trans[min_indices],
456
+ prev_step=prev_step_trans[min_indices],
457
+ maximize=False,
458
+ logger=self.logger,
459
+ )
460
+ if min_gradient is not None:
461
+ ip_gradient_trans[min_indices] = min_gradient
462
+ ip_step[min_indices] = min_step
463
+ return ip_step, ip_gradient_trans
@@ -0,0 +1,23 @@
1
+ import logging
2
+
3
+ from pysisyphus.tsoptimizers.RSPRFOptimizer import RSPRFOptimizer
4
+ from pysisyphus.tsoptimizers.TRIM import TRIM
5
+ from pysisyphus.tsoptimizers.RSIRFOptimizer import RSIRFOptimizer
6
+
7
+ __all__ = [
8
+ "RSPRFOptimizer",
9
+ "TRIM",
10
+ "RSIRFOptimizer",
11
+ "TSHessianOptimizer",
12
+ ]
13
+
14
+
15
+ logger = logging.getLogger("tsoptimizer")
16
+ logger.setLevel(logging.DEBUG)
17
+ # delay = True prevents creation of empty logfiles
18
+ handler = logging.FileHandler("tsoptimizer.log", mode="w", delay=True)
19
+ # fmt_str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
20
+ fmt_str = "%(message)s"
21
+ formatter = logging.Formatter(fmt_str)
22
+ handler.setFormatter(formatter)
23
+ logger.addHandler(handler)