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,266 @@
1
+ # [1] https://doi.org/10.1063/1.3463717
2
+ # Comparisons of classical and Wigner sampling of transition state
3
+ # energy levels for quasiclassical trajectory chemical dynamics simulations
4
+ # Sun, Hase, 2010
5
+ # [2] https://doi.org/10.1002/qua.25049
6
+ # Effects of different initial condition samplings on photodynamics and
7
+ # spectrum of pyrrole
8
+ # Barbatti, Sen, 2015
9
+ # [3] https://doi.org/10.1063/1.453761
10
+ # The Morse oscillator in position space, momentum space, and phase space
11
+ # Dahl, Springborg, 1988
12
+ #
13
+ # An interesting paper also seems to be (but i never read it ...)
14
+ #
15
+ # [4] https://doi.org/10.1063/5.0039592
16
+ # Sampling initial positions and momenta for nuclear trajectories
17
+ # from quantum mechanical distributions
18
+ # Yao, Hase, Granucci, Persico
19
+ # [5] https://doi.org/10.1039/C8CP03273D
20
+ # Finite-temperature Wigner phase-space sampling and temperature effects on the
21
+ # excited-state dynamics of 2-nitronaphthalene.
22
+ # Zobel, Nogueira, Gonzalez
23
+
24
+ import argparse
25
+ import functools
26
+ from math import exp, pi
27
+ from typing import Callable, Optional
28
+ import sys
29
+
30
+ import matplotlib.pyplot as plt
31
+ import numpy as np
32
+ from numpy.typing import NDArray
33
+ from numpy.polynomial.laguerre import Laguerre
34
+
35
+ from pysisyphus.constants import AMU2AU, AU2EV, AU2SEC, C, KB, PLANCK
36
+ from pysisyphus.helpers_pure import eigval_to_wavenumber
37
+ from pysisyphus.io import geom_from_hessian
38
+ from pysisyphus.Geometry import Geometry, get_trans_rot_projector
39
+
40
+
41
+ # From cm⁻¹ to angular frequency in atomic units
42
+ # cm⁻¹ * 100 -> m⁻¹
43
+ # m⁻¹ * C -> s⁻¹
44
+ NU2ANGFREQAU = 2 * pi * 100 * C * AU2SEC
45
+
46
+
47
+ def get_vib_state(wavenumber: float, temperature: Optional[float] = None) -> int:
48
+ """Return random vibrational state n for given wavenumber and temperature."""
49
+ if temperature is None:
50
+ return 0 # Ground state
51
+
52
+ freq = wavenumber * 100 * C # from cm⁻¹ to s⁻¹
53
+ vib_en_J = PLANCK * freq # Energy in J
54
+ quot = vib_en_J / (KB * temperature)
55
+ Z = np.exp(-quot / 2) / (1 - np.exp(-quot)) # Partition function
56
+ _1overZ = 1 / Z
57
+ # TODO: check for sensible values?
58
+
59
+ def get_p(n):
60
+ """Probability of vibrational state with quantum number n.
61
+
62
+ Given by a Boltzmann distribution:
63
+
64
+ exp(-e_n / kT)
65
+ p_n = ----------------------------
66
+ sum_{n = 0}^N exp(-e_n / kT)
67
+
68
+ for a harmonic oscillator e_n = h * freq * (n + 1/2)
69
+
70
+ See also https://chemistry.stackexchange.com/a/61120.
71
+
72
+ """
73
+ return np.exp(-quot * (n + 0.5)) * _1overZ
74
+
75
+ # Determine sensible maximum vibrational state n.
76
+ n = 0
77
+ probabilities = list()
78
+ probability_sum = 0.0
79
+ # 1.0 may never be reached, so we stop earlier.
80
+ thresh = 0.999999
81
+ while True:
82
+ p = get_p(n)
83
+ probabilities.append(p)
84
+ probability_sum += p
85
+ if probability_sum >= thresh:
86
+ break
87
+ n += 1
88
+
89
+ # Generate random number that is smaller than the current sum.
90
+ while True:
91
+ # Sample from the possible interval
92
+ random_state = np.random.random() * thresh
93
+ if random_state < probability_sum:
94
+ break
95
+
96
+ cumsum = np.cumsum(probabilities)
97
+ for n, cs in enumerate(cumsum):
98
+ if cs >= random_state:
99
+ break
100
+ return n
101
+
102
+
103
+ def normal_mode_reduced_masses(masses_rep, normal_modes):
104
+ return 1 / (np.square(normal_modes) / masses_rep[:, None]).sum(axis=0)
105
+
106
+
107
+ @functools.singledispatch
108
+ def get_wigner_sampler(
109
+ coords3d: NDArray[float],
110
+ masses: NDArray[float],
111
+ hessian: NDArray[float],
112
+ temperature: Optional[float] = None,
113
+ nu_thresh: float = 20.0,
114
+ stddevs: float = 6.0,
115
+ ) -> Callable:
116
+ assert coords3d.shape == (len(masses), 3)
117
+ assert hessian.shape == (coords3d.size, coords3d.size)
118
+
119
+ # Projector to remove translation & rotation
120
+ Proj = get_trans_rot_projector(coords3d, masses, full=True)
121
+ masses_rep = np.repeat(masses, 3)
122
+ PM = Proj @ np.diag(1 / np.sqrt(masses_rep))
123
+
124
+ # Diagonalize projected, mass-weighted Hessian.
125
+ w, v = np.linalg.eigh(PM @ hessian @ PM.T)
126
+ nus = eigval_to_wavenumber(w)
127
+
128
+ # TODO: dectect if system is linear and don't hardcode dropping of first 6 modes.
129
+ # small_nu_mask = np.abs(nus) < nu_thresh
130
+ small_nu_mask = np.zeros_like(nus, dtype=bool)
131
+ small_nu_mask[:6] = True
132
+ # w = w[~small_nu_mask]
133
+ v = v[:, ~small_nu_mask]
134
+ nus = nus[~small_nu_mask]
135
+ # Square root of angular frequencies in atomic units. Required to convert the
136
+ # dimensionless Q and P values into atomic units.
137
+ ang_freqs_au_sqrt = np.sqrt(nus * NU2ANGFREQAU)
138
+
139
+ assert (nus >= nu_thresh).all(), "Imaginary wavenumbers are not yet handled!"
140
+ nnus = len(nus) # Number of non-zero wavenumbers
141
+
142
+ span = 2 * stddevs
143
+ # Pre-calculate some of the Laguerre polynomials
144
+ # We use some shortcuts for n == 0 and n == 1
145
+ laguerres = {
146
+ 0: lambda _: 1.0,
147
+ 1: lambda x: 1.0 - x,
148
+ }
149
+
150
+ def get_laguerre(n):
151
+ lag_coeffs = np.zeros(n + 1)
152
+ lag_coeffs[n] = 1.0
153
+ return Laguerre(lag_coeffs)
154
+
155
+ for i in range(2, 11):
156
+ laguerres[i] = get_laguerre(i)
157
+
158
+ mm_sqrt_au = np.sqrt(masses_rep * AMU2AU)
159
+ M_inv_au = np.diag(1 / mm_sqrt_au)
160
+
161
+ def sampler():
162
+ Qs = np.zeros(nnus)
163
+ Ps = np.zeros(nnus)
164
+ for i in range(nnus):
165
+ n = get_vib_state(nus[i], temperature)
166
+ try:
167
+ lag = laguerres[n]
168
+ except KeyError:
169
+ lag = get_laguerre(n)
170
+ laguerres[n] = lag
171
+ # According to eq. (31) in [3], the absolute value of the Wigner function is
172
+ # bound between 0 and 1/π (see also Figure 3 in [3]). By omitting 1/π in the
173
+ # Wigner function (eq. (28) in [3]) its absolute value will be between 0 and 1.
174
+ # This saves us some multiplications/division as with 1/π it would also be sensible
175
+ # to map 'ref' from [0, 1) to [0, 1/π)].
176
+ prefact = (-1) ** n
177
+ while True:
178
+ q, p, ref = np.random.random_sample(3)
179
+ # Map q and p from [0, 1) onto chosen interval [-stddevs, stddevs)
180
+ q = q * span - stddevs
181
+ p = p * span - stddevs
182
+ r2 = q**2 + p**2
183
+ # Wigner function. Eq. (2) in [2] or (28) in [3]. Both equations
184
+ # differ in the presence or absence of a n! term. Here and in [3]
185
+ # the n! is absorbed into the Laguerre polynomial.
186
+ p_wig = prefact * exp(-r2) * lag(2 * r2)
187
+ # We don't use p and q that correspond to a negative value of the
188
+ # Wigner function. See the SI of [5] for a discussion.
189
+ if 0.0 < p_wig >= ref:
190
+ break
191
+ Qs[i] = q
192
+ Ps[i] = p
193
+
194
+ # The actual displacements/momenta depend on the vibrational frequencies.
195
+ # Now we the dimensionless units to atomic units. See eq. (5) in [1].
196
+ Qs /= ang_freqs_au_sqrt
197
+ Ps *= ang_freqs_au_sqrt
198
+
199
+ # Convert to Cartesian coordinates
200
+ displ = M_inv_au @ v @ Qs
201
+ velocities = M_inv_au @ v @ Ps
202
+
203
+ # The COM remains unaffected, as we displace along vibrations,
204
+ # not translations.
205
+ displ_coords3d = coords3d.copy() + displ.reshape(-1, 3)
206
+
207
+ # Remove rotation & translation from velocities at new coordinates.
208
+ P = get_trans_rot_projector(displ_coords3d, masses, full=True)
209
+ velocities = P.dot(velocities)
210
+ return displ_coords3d, velocities.reshape(-1, 3)
211
+
212
+ return sampler
213
+
214
+
215
+ @get_wigner_sampler.register
216
+ def _(geom: Geometry, **kwargs):
217
+ return get_wigner_sampler(geom.coords3d, geom.masses, geom.hessian, **kwargs)
218
+
219
+
220
+ @get_wigner_sampler.register
221
+ def _(h5_fn: str, **kwargs):
222
+ geom = geom_from_hessian(h5_fn)
223
+ return get_wigner_sampler(geom)
224
+
225
+
226
+ def parse_args(args):
227
+ parser = argparse.ArgumentParser()
228
+ parser.add_argument("h5_fn", type=str, help="Filename of pysisyphus HDF5 Hessian.")
229
+ parser.add_argument("-n", type=int, default=100, help="Number of samples.")
230
+ parser.add_argument("-T", type=float, default=None, help="Temperature in K.")
231
+ parser.add_argument("--plotekin", action="store_true", help="Plot kinetic energy.")
232
+ return parser.parse_args(args)
233
+
234
+
235
+ def run():
236
+ args = parse_args(sys.argv[1:])
237
+
238
+ h5_fn = args.h5_fn
239
+ n = args.n
240
+ temperature = args.T
241
+ plotekin = args.plotekin
242
+
243
+ geom = geom_from_hessian(h5_fn)
244
+
245
+ sampler = get_wigner_sampler(geom, temperature=temperature)
246
+ xyzs = list()
247
+ velocities = np.zeros((n, len(geom.atoms), 3))
248
+ for i in range(n):
249
+ c3d, velocities[i] = sampler()
250
+ xyzs.append(geom.as_xyz(cart_coords=c3d))
251
+
252
+ trj_fn = f"samples_{n}_trj.xyz"
253
+ with open(trj_fn, "w") as handle:
254
+ handle.write("\n".join(xyzs))
255
+
256
+ if plotekin:
257
+ half_masses_au = geom.masses * AMU2AU / 2
258
+
259
+ def E_kin(v_au):
260
+ return (half_masses_au[:, None] * (v_au**2)).sum()
261
+
262
+ E_kins = np.array([E_kin(v) for v in velocities])
263
+ E_kins_eV = E_kins * AU2EV
264
+ _, ax = plt.subplots()
265
+ ax.hist(E_kins_eV, bins=100)
266
+ plt.show()