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,364 @@
1
+ # [1] https://doi.org/10.1063/1.5082885
2
+ # Minimum dynamic path
3
+ # Unke, 2019
4
+
5
+ from collections import namedtuple
6
+ import operator
7
+ import re
8
+
9
+ import numpy as np
10
+
11
+ from pysisyphus.constants import AU2KJPERMOL
12
+ from pysisyphus.dynamics.driver import md, MDResult
13
+ from pysisyphus.dynamics.helpers import (
14
+ dump_coords,
15
+ get_mb_velocities_for_geom,
16
+ temperature_for_kinetic_energy,
17
+ )
18
+ from pysisyphus.helpers_pure import highlight_text
19
+
20
+
21
+ def parse_raw_term_func(raw_term_func):
22
+ funcs = {
23
+ "<": operator.lt,
24
+ ">": operator.gt,
25
+ "<=": operator.le,
26
+ ">=": operator.ge,
27
+ "==": operator.eq,
28
+ }
29
+
30
+ def comp_closure(indices, op, ref_value):
31
+ a_ind, b_ind = indices
32
+ func = funcs[op]
33
+
34
+ def comp_func(coords3d):
35
+ a = coords3d[a_ind]
36
+ b = coords3d[b_ind]
37
+ dist = np.linalg.norm(a - b)
38
+ return func(dist, ref_value)
39
+
40
+ return comp_func
41
+
42
+ operator_re = re.compile("([<>=]+)")
43
+ mobj = operator_re.split(raw_term_func)
44
+ if mobj is None:
45
+ print(f"Could not parse term_func '{raw_term_func}!'")
46
+ return None
47
+ indices, op, ref_value = mobj
48
+ ref_value = float(ref_value)
49
+ indices = [int(ind) for ind in indices.split(",")]
50
+ return comp_closure(indices, op, ref_value)
51
+
52
+
53
+ def parse_raw_term_funcs(raw_term_funcs):
54
+ comp_funcs = {}
55
+ for k, v in raw_term_funcs.items():
56
+ comp_func = parse_raw_term_func(v)
57
+ if comp_func:
58
+ comp_funcs[k] = comp_func
59
+ return comp_funcs
60
+
61
+
62
+ def run_md(geom, dt, steps, v0=None, term_funcs=None, external=False):
63
+ if external and hasattr(geom.calculator, "run_md"):
64
+ t = dt * steps
65
+ t_ps = t * 1e-3
66
+ md_kwargs = {
67
+ "atoms": geom.atoms,
68
+ "coords": geom.coords,
69
+ "t": t,
70
+ "dt": dt,
71
+ "velocities": v0,
72
+ "dump": dt,
73
+ }
74
+ print("Running MD with external calculator implementation.")
75
+ if term_funcs is not None:
76
+ print("Termination functions are not supported in external MD!")
77
+ geoms = geom.calculator.run_md(**md_kwargs)
78
+ md_result = MDResult(
79
+ coords=[geom.coords for geom in geoms],
80
+ t_ps=t_ps,
81
+ step=int(t / dt - 1),
82
+ terminated=None,
83
+ T=None,
84
+ E_tot=None,
85
+ )
86
+ else:
87
+ md_kwargs = {
88
+ "v0": v0,
89
+ "steps": steps,
90
+ "dt": dt,
91
+ "term_funcs": term_funcs,
92
+ "verbose": False,
93
+ "remove_com_v": False,
94
+ }
95
+ print("Running MD with internal implementation.")
96
+ md_result = md(geom, **md_kwargs)
97
+
98
+ return md_result
99
+
100
+
101
+ MDPResult = namedtuple(
102
+ "MDResult",
103
+ "ascent_xs md_init_plus md_init_minus "
104
+ "md_fin_plus md_fin_minus "
105
+ "md_fin_plus_term md_fin_minus_term",
106
+ )
107
+
108
+
109
+ def mdp(
110
+ geom,
111
+ steps,
112
+ dt,
113
+ term_funcs=None,
114
+ steps_init=None,
115
+ E_excess=0.0,
116
+ displ_length=0.1,
117
+ epsilon=5e-4,
118
+ ascent_alpha=0.05,
119
+ max_ascent_steps=25,
120
+ max_init_trajs=10,
121
+ dump=True,
122
+ seed=None,
123
+ external_md=False,
124
+ ):
125
+ # Sanity checks and forcing some types
126
+ dt = float(dt)
127
+ assert dt > 0.0
128
+ steps = int(steps)
129
+ t = dt * steps
130
+ # assert t > dt
131
+ if steps_init is None:
132
+ steps_init = steps // 10
133
+ print(f"No 'steps_init' provided! Using {steps_init}")
134
+ E_excess = float(E_excess)
135
+ assert E_excess >= 0.0
136
+ displ_length = float(displ_length)
137
+ assert displ_length >= 0.0
138
+ if term_funcs is None:
139
+ term_funcs = {}
140
+ for k, v in term_funcs.items():
141
+ if callable(v):
142
+ continue
143
+ elif isinstance(v, str):
144
+ term_funcs[k] = parse_raw_term_func(v)
145
+ else:
146
+ raise Exception(f"Invalid term function '{k}: {v}' encountered!")
147
+
148
+ print(highlight_text("Minimum dynamic path calculation"))
149
+
150
+ if seed is None:
151
+ # 2**32 - 1
152
+ seed = np.random.randint(4294967295)
153
+ np.random.seed(seed)
154
+ print(f"Using seed {seed} to initialize the random number generator.\n")
155
+
156
+ E_TS = geom.energy
157
+ E_tot = E_TS + E_excess
158
+ # Distribute E_excess evenly on E_pot and E_kin
159
+ E_pot_diff = 0.5 * E_excess
160
+ E_pot_desired = E_TS + E_pot_diff
161
+
162
+ print(f"E_TS={E_TS:.6f} au")
163
+
164
+ # Determine transition vector
165
+ w, v = np.linalg.eigh(geom.hessian)
166
+ assert w[0] < -1e-8
167
+ trans_vec = v[:, 0]
168
+
169
+ # Disable removal of translation/rotation for analytical potentials
170
+ remove_com_v = remove_rot_v = geom.cart_coords.size > 3
171
+
172
+ if E_excess == 0.0:
173
+ print("MDP without excess energy.")
174
+ # Without excess energy we have to do an initial displacement along
175
+ # the transition vector to get a non-vanishing gradient.
176
+ initial_displacement = displ_length * trans_vec
177
+ x0_plus = geom.coords + initial_displacement
178
+ x0_minus = geom.coords - initial_displacement
179
+
180
+ v0_zero = np.zeros_like(geom.coords)
181
+ md_kwargs = {
182
+ "v0": v0_zero.copy(),
183
+ "t": t,
184
+ "dt": dt,
185
+ "term_funcs": term_funcs,
186
+ "external": external_md,
187
+ }
188
+
189
+ geom.coords = x0_plus
190
+ md_fin_plus = run_md(geom, **md_kwargs)
191
+
192
+ geom.coords = x0_minus
193
+ md_fin_minus = run_md(geom, **md_kwargs)
194
+
195
+ if dump:
196
+ dump_coords(geom.atoms, md_fin_plus.coords, "mdp_plus_trj.xyz")
197
+ dump_coords(geom.atoms, md_fin_minus.coords, "mdp_minus_trj.xyz")
198
+
199
+ mdp_result = MDPResult(
200
+ ascent_xs=None,
201
+ md_init_plus=None,
202
+ md_init_minus=None,
203
+ md_fin_plus=md_fin_plus,
204
+ md_fin_minus=md_fin_minus,
205
+ )
206
+ return mdp_result
207
+
208
+ print(f"E_excess={E_excess:.6f} au, ({E_excess*AU2KJPERMOL:.1f} kJ/mol)")
209
+ print(f"E_pot,desired=E_TS + {E_pot_diff*AU2KJPERMOL:.1f} kJ/mol")
210
+ print()
211
+
212
+ # Generate random vector perpendicular to transition vector
213
+ perp_vec = np.random.rand(*trans_vec.shape)
214
+ # Zero last element if we have an analytical surface
215
+ if perp_vec.size == 3:
216
+ perp_vec[2] = 0
217
+ # Orthogonalize vector
218
+ perp_vec = perp_vec - (perp_vec @ trans_vec) * trans_vec
219
+ perp_vec /= np.linalg.norm(perp_vec)
220
+
221
+ # Initial displacement from x_TS to x, generating a point with
222
+ # non-vanishing gradient.
223
+ x = geom.coords + epsilon * perp_vec
224
+ geom.coords = x
225
+
226
+ # Do steepest ascent until E_tot is reached
227
+ E_pot = geom.energy
228
+ ascent_xs = list()
229
+ for i in range(max_ascent_steps):
230
+ ascent_xs.append(geom.coords.copy())
231
+ ascent_converged = E_pot >= E_pot_desired
232
+ if ascent_converged:
233
+ break
234
+ gradient = geom.gradient
235
+ E_pot = geom.energy
236
+
237
+ direction = gradient / np.linalg.norm(gradient)
238
+ step = ascent_alpha * direction
239
+ new_coords = geom.coords + step
240
+ geom.coords = new_coords
241
+
242
+ # calc = geom.calculator
243
+ # class Opt:
244
+ # pass
245
+ # _opt = Opt()
246
+ # _opt.coords = np.array(ascent_xs)
247
+ # calc.plot_opt(_opt, show=True)
248
+
249
+ assert ascent_converged, "Steepest ascent didn't converge!"
250
+ assert (E_tot - E_pot) > 0.0, (
251
+ "Potential energy after steepst ascent is greater than the desired "
252
+ f"total energy ({E_pot:.6f} > {E_tot:.6f}). Maybe try a smaller epsilon? "
253
+ f"The current value Ɛ={epsilon:.6f} may be too big!"
254
+ )
255
+
256
+ ascent_xs = np.array(ascent_xs)
257
+ if dump:
258
+ dump_coords(geom.atoms, ascent_xs, "mdp_ee_ascent_trj.xyz")
259
+ x0 = geom.coords.copy()
260
+
261
+ print(highlight_text("Runninig initialization trajectories", level=1))
262
+ for i in range(max_init_trajs):
263
+ # Determine random momentum vector for the given kinetic energy
264
+ E_kin = E_tot - E_pot
265
+ T = temperature_for_kinetic_energy(len(geom.atoms), E_kin)
266
+ v0 = get_mb_velocities_for_geom(
267
+ geom, T, remove_com_v=remove_com_v, remove_rot_v=remove_rot_v
268
+ ).flatten()
269
+
270
+ # Zero last element if we have an analytical surface
271
+ if v0.size == 3:
272
+ v0[2] = 0
273
+
274
+ # Run initial MD to check if both trajectories run towards different
275
+ # basins of attraction.
276
+
277
+ # First MD with positive v0
278
+ md_init_kwargs = {
279
+ "v0": v0.copy(),
280
+ "steps": steps_init,
281
+ "dt": dt,
282
+ "external": external_md,
283
+ }
284
+ geom.coords = x0.copy()
285
+ md_init_plus = run_md(geom, **md_init_kwargs)
286
+ # Second MD with negative v0
287
+ geom.coords = x0.copy()
288
+ md_init_kwargs["v0"] = -v0.copy()
289
+ md_init_minus = run_md(geom, **md_init_kwargs)
290
+
291
+ dump_coords(geom.atoms, md_init_plus.coords, f"mdp_ee_init_plus_{i:02d}_trj.xyz")
292
+ dump_coords(geom.atoms, md_init_minus.coords, f"mdp_ee_init_minus_{i:02d}_trj.xyz")
293
+
294
+ # Check if both MDs run into different basins of attraction.
295
+ # We (try to) do this by calculating the overlap between the
296
+ # transition vector and the normalized vector defined by the
297
+ # difference between x0 and the endpoint of the respective
298
+ # test trajectory. Both overlaps should have different sings.
299
+ end_plus = md_init_plus.coords[-1]
300
+ pls = end_plus - x0
301
+ pls /= np.linalg.norm(pls)
302
+ end_minus = md_init_minus.coords[-1]
303
+ minus = end_minus - x0
304
+ minus /= np.linalg.norm(minus)
305
+ p = trans_vec @ pls
306
+ m = trans_vec @ minus
307
+ init_trajs_converged = np.sign(p) != np.sign(m)
308
+
309
+ if init_trajs_converged:
310
+ print("Trajectories ran into different basins. Breaking.")
311
+ break
312
+ if dump:
313
+ dump_coords(geom.atoms, md_init_plus.coords, "mdp_ee_init_plus_trj.xyz")
314
+ dump_coords(geom.atoms, md_init_minus.coords, "mdp_ee_init_minus_trj.xyz")
315
+ assert init_trajs_converged
316
+ print(f"Ran 2*{i+1} initialization trajectories.")
317
+ print()
318
+
319
+ # Run actual trajectories, using the supplied termination functions if possible.
320
+ print(highlight_text("Running actual full trajectories.", level=1))
321
+
322
+ def print_status(terminated, step):
323
+ if terminated:
324
+ msg = f"\tTerminated by '{terminated}' in step {step}."
325
+ else:
326
+ msg = "\tMax time steps reached!"
327
+ print(msg)
328
+
329
+ # "Production"/Final MDs
330
+ md_fin_kwargs = {
331
+ "v0": v0.copy(),
332
+ "steps": steps,
333
+ "dt": dt,
334
+ "term_funcs": term_funcs,
335
+ "external": external_md,
336
+ }
337
+ # MD with positive v0.
338
+ geom.coords = x0.copy()
339
+ md_fin_plus = run_md(geom, **md_fin_kwargs)
340
+ print_status(md_fin_plus.terminated, md_fin_plus.step)
341
+
342
+ # MD with negative v0.
343
+ geom.coords = x0.copy()
344
+ md_fin_kwargs["v0"] = -v0
345
+ md_fin_minus = run_md(geom, **md_fin_kwargs)
346
+ print_status(md_fin_minus.terminated, md_fin_minus.step)
347
+
348
+ md_fin_plus_term = md_fin_plus.terminated
349
+ md_fin_minus_term = md_fin_minus.terminated
350
+
351
+ if dump:
352
+ dump_coords(geom.atoms, md_fin_plus.coords, "mdp_ee_fin_plus_trj.xyz")
353
+ dump_coords(geom.atoms, md_fin_minus.coords, "mdp_ee_fin_minus_trj.xyz")
354
+
355
+ mdp_result = MDPResult(
356
+ ascent_xs=ascent_xs,
357
+ md_init_plus=md_init_plus,
358
+ md_init_minus=md_init_minus,
359
+ md_fin_plus=md_fin_plus,
360
+ md_fin_minus=md_fin_minus,
361
+ md_fin_plus_term=md_fin_plus_term,
362
+ md_fin_minus_term=md_fin_minus_term,
363
+ )
364
+ return mdp_result
@@ -0,0 +1,121 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.constants import FORCE2ACC
4
+ from pysisyphus.dynamics.helpers import energy_forces_getter_closure, remove_com_velocity
5
+
6
+
7
+ def rattle_closure(geom, constraints, dt, tol=1e-3, max_cycles=25,
8
+ energy_forces_getter=None, remove_com_v=True):
9
+ # Inverse atom masses
10
+ masses = geom.masses
11
+ inv_masses = 1 / masses
12
+ inv_masses_rep = np.repeat(inv_masses, 3)
13
+
14
+ dt2 = 0.5 * dt
15
+ dt2_sq = dt2 * dt
16
+ tol_sq = tol**2
17
+
18
+ constraints = np.array(constraints, dtype=int)
19
+ inv_masses_sums = inv_masses[constraints[:, 0]] + inv_masses[constraints[:, 1]]
20
+ coords3d = geom.coords3d
21
+
22
+ def get_bond_vecs(coords3d):
23
+ return coords3d[constraints[:, 0]] - coords3d[constraints[:, 1]]
24
+
25
+ # Original bond lengths
26
+ lengths = np.linalg.norm(get_bond_vecs(coords3d), axis=1)
27
+ lengths_sq = lengths**2
28
+
29
+ if energy_forces_getter is None:
30
+ energy_forces_getter = energy_forces_getter_closure(geom)
31
+ # def forces_getter(coords):
32
+ # return geom.get_energy_and_forces_at(coords)["forces"]
33
+
34
+ def rattle(coords, velocities, forces):
35
+ acceleration = forces * inv_masses_rep * FORCE2ACC
36
+ # Bond vectors at time t
37
+ bond_vecs = get_bond_vecs(coords.reshape(-1, 3))
38
+
39
+ # Unconstrained position update
40
+ coords3d_updated = (coords + dt*velocities + dt2_sq * acceleration).reshape(-1, 3)
41
+ # Unconstrained velocity update
42
+ velocities3d_updated = (velocities + dt2 * acceleration).reshape(-1, 3)
43
+ if remove_com_v:
44
+ velocities3d_updated = remove_com_velocity(velocities3d_updated, masses)
45
+
46
+ # First part of RATTLE algorithm.
47
+ # Yields updated positions for t+dt and half-updated velocities for t+dt/2
48
+ for i in range(max_cycles):
49
+ corrected = False
50
+ for j, (atom_1, atom_2) in enumerate(constraints):
51
+ bond_vec_updated = coords3d_updated[atom_1] - coords3d_updated[atom_2]
52
+ bond_length_sq = bond_vec_updated.dot(bond_vec_updated)
53
+ ref_length_sq = lengths_sq[j]
54
+ diff_sq = ref_length_sq - bond_length_sq
55
+
56
+ # We have to correct coordinates and velocities if the deviations is
57
+ # above the tolerance.
58
+ if abs(diff_sq) <= (ref_length_sq * tol_sq):
59
+ continue
60
+
61
+ corrected = True
62
+ # Otherwise try to satisfy the constraint by calculating the
63
+ # approximate lagrange multiplier 'g'.
64
+ dot = bond_vec_updated.dot(bond_vecs[j])
65
+ # TODO: test for constraint failure
66
+ g = diff_sq / (2 * inv_masses_sums[j] * dot)
67
+
68
+ # Update positions to satify constraint
69
+ atom_1_factor = g * bond_vecs[j] * inv_masses[atom_1]
70
+ atom_2_factor = g * bond_vecs[j] * inv_masses[atom_2]
71
+ coords3d_updated[atom_1] += atom_1_factor
72
+ coords3d_updated[atom_2] -= atom_2_factor
73
+ # Update velocities to satify constraint
74
+ velocities3d_updated[atom_1] += atom_1_factor / dt
75
+ velocities3d_updated[atom_2] -= atom_2_factor / dt
76
+
77
+ # Stop macro-iterations when no correction was done
78
+ if not corrected:
79
+ # print(f"RATTLE_1 finished after {i+1} macro cycle(s)!")
80
+ break
81
+ else:
82
+ raise Exception("First part of RATTLE did not converge!")
83
+
84
+ # Calculate energy (E_pot) and forces at updated coordinates
85
+ energy_new, forces_new = energy_forces_getter(coords3d_updated.flatten())
86
+ velocities3d_updated += dt2 * (forces_new * inv_masses_rep * FORCE2ACC).reshape(-1, 3)
87
+ if remove_com_v:
88
+ velocities3d_updated = remove_com_velocity(velocities3d_updated, masses)
89
+ # The coordinates aren't updated anymore in the second part, so we can
90
+ # calculate the bond vectors here once and store them.
91
+ bond_vecs = get_bond_vecs(coords3d_updated)
92
+
93
+ # Second part of RATTLE algorithm
94
+ # Update velocities to full time step t+dt
95
+ for i in range(max_cycles):
96
+ corrected = False
97
+ for j, (atom_1, atom_2) in enumerate(constraints):
98
+ velocity_diff = (velocities3d_updated[atom_1]
99
+ - velocities3d_updated[atom_2])
100
+ dot = bond_vecs[j].dot(velocity_diff)
101
+ # Approximate Lagrange multiplier
102
+ k = dot / (inv_masses_sums[j] * lengths_sq[j])
103
+
104
+ if abs(k) <= tol_sq:
105
+ continue
106
+
107
+ corrected = True
108
+ # Update velocities to satify constraint
109
+ velocities3d_updated[atom_1] -= k * bond_vecs[j] * inv_masses[atom_1]
110
+ velocities3d_updated[atom_2] += k * bond_vecs[j] * inv_masses[atom_2]
111
+
112
+ # Stop macro-iterations when no correction was done
113
+ if not corrected:
114
+ # print(f"RATTLE_2 finished after {i+1} macro cycle(s)!")
115
+ break
116
+ else:
117
+ raise Exception("Second part of RATTLE did not converge!")
118
+
119
+ return coords3d_updated.flatten(), velocities3d_updated.flatten(), energy_new, forces_new
120
+
121
+ return rattle
@@ -0,0 +1,128 @@
1
+ from math import exp, sqrt
2
+
3
+ import numpy as np
4
+ from numpy.random import default_rng
5
+
6
+ from pysisyphus.constants import KBAU
7
+
8
+
9
+ """
10
+ [1] https://aip.scitation.org/doi/10.1063/1.2408420
11
+ [2] https://dx.doi.org/10.1016/j.cpc.2008.01.006
12
+ Reformulation fo the algorithm. This is implemented e.g., in YAFF.
13
+ https://github.com/molmod/yaff/blob/master/yaff/sampling/nvt.py
14
+
15
+ csvr_closure() is based on the implementation provided on Bussis homepage:
16
+ https://sites.google.com/site/giovannibussi/downloads/resamplekin.tgz
17
+ (At least in my implementation) there seems to be a problem with
18
+ the conserved quantity, which is not conserved at all ...
19
+ csvr_closure_2() is based on [2]
20
+ """
21
+
22
+
23
+ RNG = default_rng()
24
+
25
+
26
+ def sum_noises(num, rng=None):
27
+ """
28
+ Parameters
29
+ ----------
30
+ num : int
31
+ Number of independent Gaussian noises to be squared.
32
+ rng : numpy.random.Generator, optional
33
+ Instances of a random number generator (RNG). If it is not provided the module-level
34
+ RNG will be used.
35
+ """
36
+
37
+ if rng is None:
38
+ rng = RNG
39
+
40
+ if num == 0:
41
+ sum_ = 0.0
42
+ elif num == 1:
43
+ sum_ = rng.normal()**2
44
+ # nn even, dof - 1 odd
45
+ elif (num % 2) == 0:
46
+ sum_ = 2.0 * rng.gamma(shape=num/2)
47
+ # nn odd, dof - 1 even
48
+ else:
49
+ sum_ = 2.0 * rng.gamma(shape=(num-1)/2) + rng.normal()**2
50
+
51
+ return sum_
52
+
53
+
54
+ def csvr_closure(sigma, dof, dt, tau=100, rng=None):
55
+ """
56
+ Parameters
57
+ ----------
58
+ sigma : float
59
+ Target average value of the kinetic energy (1/2 dof k_b T) in the same units as
60
+ cur_kinetic_energy.
61
+ dof : int
62
+ Degrees of freedom.
63
+ tau : float
64
+ Timeconstant of the thermostat. tau : float
65
+ Timeconstant of the thermostat.
66
+ rng : numpy.random.Generator, optional
67
+ Instances of a random number generator (RNG). If it is not provided the module-level
68
+ RNG will be used.
69
+ """
70
+ # Relaxation time of the thermostat in units of "how often this routine
71
+ # is called" (dt / timeconstant).
72
+ tau_t = dt / tau
73
+
74
+ if tau_t > 0.1:
75
+ factor = exp(-1.0 / tau_t)
76
+ else:
77
+ factor = 0.0
78
+
79
+ if rng is None:
80
+ rng = RNG
81
+
82
+ def resample_kin(cur_kinetic_energy):
83
+ """
84
+ Parameters
85
+ ----------
86
+ cur_kinetic_energy : float
87
+ Present value of the kinetic energy of the atoms to be thermalized
88
+ in arbitrary units.
89
+ """
90
+ rr = rng.normal()
91
+ new_kinetic_energy = (
92
+ cur_kinetic_energy
93
+ + (1.0 - factor)
94
+ * (sigma * (sum_noises(dof-1) + rr**2) / dof - cur_kinetic_energy)
95
+ + 2.0 * rr * sqrt(cur_kinetic_energy * sigma / dof * (1.0 - factor) * factor)
96
+ )
97
+ alpha = sqrt(new_kinetic_energy / cur_kinetic_energy)
98
+ return alpha
99
+ return resample_kin
100
+
101
+
102
+ def csvr_closure_2(sigma, dof, dt, tau=100, rng=None):
103
+ if rng is None:
104
+ rng = RNG
105
+ c = exp(-dt / tau)
106
+
107
+ def resample_kin(cur_kinetic_energy):
108
+ """Canonical stocastical velocity rescaling.
109
+
110
+ See dx.doi.org/10.1016/j.cpc.2008.01.006
111
+ """
112
+ R = rng.normal()
113
+ S = np.sum(rng.normal(size=dof-1)**2)
114
+ quot = (1 - c) * sigma / (dof * cur_kinetic_energy)
115
+ alpha = sqrt(c + quot * (S + R**2) + 2 * R * sqrt(c*quot))
116
+ sign = np.sign(R + sqrt(c / quot))
117
+ return sign * alpha
118
+ return resample_kin
119
+
120
+
121
+ def berendsen_closure(sigma, dof, dt, tau=100, rng=None):
122
+ """ https://doi.org/10.1063/1.448118"""
123
+ tau_t = dt / tau
124
+
125
+ def resample_kin(cur_kinetic_energy):
126
+ alpha = sqrt(1 + tau_t * (sigma / cur_kinetic_energy - 1))
127
+ return alpha
128
+ return resample_kin