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,271 @@
1
+ from pathlib import Path
2
+ from time import time
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.config import T_DEFAULT, p_DEFAULT
7
+ from pysisyphus.constants import AU2KJPERMOL
8
+ from pysisyphus.helpers_pure import highlight_text, standard_state_corr
9
+ from pysisyphus.TablePrinter import TablePrinter
10
+ from pysisyphus.thermo import print_thermoanalysis
11
+
12
+
13
+ def do_endopt_ts_barriers(
14
+ ts_geom,
15
+ left_geoms,
16
+ right_geoms=None,
17
+ left_fns=None,
18
+ right_fns=None,
19
+ do_thermo=False,
20
+ T=T_DEFAULT,
21
+ p=p_DEFAULT,
22
+ calc_getter=None,
23
+ solv_calc_getter=None,
24
+ do_standard_state_corr=False,
25
+ ):
26
+ print(highlight_text("Barrier heights after end optimization(s)"))
27
+ print()
28
+
29
+ # Only allow standard state correction when solvent calculator is specified.
30
+ do_ssc = do_standard_state_corr and (solv_calc_getter is not None)
31
+ ssc = standard_state_corr(T=T, p=p) if do_ssc else 0.0
32
+
33
+ if right_geoms is None:
34
+ right_geoms = []
35
+
36
+ def set_fns(fns, geoms):
37
+ if fns is None:
38
+ fns = ["" for geom in geoms]
39
+ else:
40
+ fns = [Path(fn).name for fn in fns]
41
+ return fns
42
+ left_fns = set_fns(left_fns, left_geoms)
43
+ right_fns = set_fns(right_fns, left_geoms)
44
+ ts_fn = "TS"
45
+
46
+ ts_atom_num = len(ts_geom.atoms)
47
+
48
+ def drop_total_geom(geoms):
49
+ atom_nums = [len(geom.atoms) for geom in geoms]
50
+ tot_atom_num = sum(atom_nums)
51
+ total_geom = None
52
+ if tot_atom_num > ts_atom_num:
53
+ total_ind = atom_nums.index(max(atom_nums))
54
+ total_geom = geoms[total_ind]
55
+ geoms = [geom for i, geom in enumerate(geoms) if i != total_ind]
56
+ return geoms, total_geom
57
+
58
+ left_geoms, left_total_geom = drop_total_geom(left_geoms)
59
+ right_geoms, right_total_geom = drop_total_geom(right_geoms)
60
+
61
+ def tot_atom_num(geoms):
62
+ return sum([len(geom.atoms) for geom in geoms])
63
+
64
+ left_atom_num = tot_atom_num(left_geoms)
65
+ assert left_atom_num == ts_atom_num, (
66
+ f"Atom number mismatch between TS ({ts_atom_num} atoms) and "
67
+ f"left side ({left_atom_num} atoms)! Aborting barrier calculation"
68
+ )
69
+ right_tot_atom_num = tot_atom_num(right_geoms)
70
+ assert (right_tot_atom_num == ts_atom_num) or (right_tot_atom_num == 0)
71
+
72
+ def get_energy(geom, base_name):
73
+ try:
74
+ geom.energy
75
+ except AttributeError:
76
+ try:
77
+ geom.set_calculator(calc_getter(base_name=base_name))
78
+ except TypeError:
79
+ raise Exception(
80
+ f"Energy isn't set at '{base_name}' geometry "
81
+ "and no 'calc_getter' was supplied!\nPlease either set "
82
+ "the desired quantities (energy/(Hessian)) or supply "
83
+ "a 'calc_getter' to calculate them."
84
+ )
85
+ return geom.energy
86
+
87
+ def get_energies(geoms, base_name):
88
+ return [
89
+ get_energy(geom, f"{base_name}_{i:02d}") for i, geom in enumerate(geoms)
90
+ ]
91
+
92
+ en_key = "energy"
93
+ ts_energy = get_energy(ts_geom, "ts")
94
+ left_energies = get_energies(left_geoms, "left")
95
+ right_energies = get_energies(right_geoms, "right")
96
+
97
+ def zeros(geoms):
98
+ return np.zeros(len(geoms))
99
+
100
+ # Gibbs free energies
101
+ if do_thermo:
102
+ en_key = "free energy"
103
+
104
+ def get_thermo(geom, title, is_ts=False):
105
+ thermo = geom.get_thermoanalysis(geom, T=T, p=p)
106
+ print_thermoanalysis(thermo, geom=geom, is_ts=is_ts, level=1, title=title)
107
+ print()
108
+ return thermo
109
+
110
+ ts_thermo = get_thermo(ts_geom, "TS", is_ts=True)
111
+ ts_dG = ts_thermo.dG
112
+ left_thermos = [get_thermo(geom, fn) for geom, fn in zip(left_geoms, left_fns)]
113
+ left_dGs = [thermo.dG for thermo in left_thermos]
114
+ right_thermos = [
115
+ get_thermo(geom, fn) for geom, fn in zip(right_geoms, right_fns)
116
+ ]
117
+ right_dGs = [thermo.dG for thermo in right_thermos]
118
+ else:
119
+ ts_dG = 0.0
120
+ left_dGs = zeros(left_geoms)
121
+ right_dGs = zeros(right_geoms)
122
+
123
+ def get_solv_correction(geom, fn=None, name=None):
124
+ fn = str(fn)
125
+ if fn is not None:
126
+ infix = f"'{Path(fn).name: >40s}'"
127
+ else:
128
+ atom_num = len(geom.atoms)
129
+ infix = f"{atom_num} atoms"
130
+
131
+ print(f"Solvated calculation for {infix} ...", end="")
132
+ start = time()
133
+ solv_calc_kwargs = {}
134
+ if name is not None:
135
+ solv_calc_kwargs["base_name"] = f"solv_{name}"
136
+ solv_energy = solv_calc_getter(**solv_calc_kwargs).get_energy(
137
+ geom.atoms, geom.cart_coords
138
+ )["energy"]
139
+ dur = time() - start
140
+ print(f" finished in {dur:.1f} s.")
141
+ # Add standard state correction. ssc will be 0.0 if, disabled.
142
+ return solv_energy, (solv_energy - geom.energy) + ssc
143
+
144
+ def get_solv_corrections(geoms, fns, name):
145
+ return zip(
146
+ *[get_solv_correction(geom, fn, name) for geom, fn in zip(geoms, fns)]
147
+ )
148
+
149
+ if solv_calc_getter is not None:
150
+ print(highlight_text("Calculations with solvent model", level=1) + "\n")
151
+ ts_solv_energy, ts_solv_corr = get_solv_correction(ts_geom, ts_fn, "ts")
152
+ left_solv_energies, left_solv_corrs = get_solv_corrections(
153
+ left_geoms, left_fns, "left"
154
+ )
155
+ right_solv_energies, right_solv_corrs = get_solv_corrections(
156
+ right_geoms, right_fns, "right"
157
+ )
158
+ print()
159
+ # Use zeros, so we can add the term later.
160
+ else:
161
+ ts_solv_corr = 0.0
162
+ left_solv_corrs = zeros(left_geoms)
163
+ right_solv_corrs = zeros(right_geoms)
164
+
165
+ # Calculate total contributions for both sides
166
+ left_dG = sum(left_dGs)
167
+ right_dG = sum(right_dGs)
168
+ left_solv_corr = sum(left_solv_corrs)
169
+ right_solv_corr = sum(right_solv_corrs)
170
+
171
+ ts_energy_corr = ts_energy + ts_solv_corr + ts_dG
172
+ left_energy_corr = sum(left_energies) + left_dG + left_solv_corr
173
+ right_energy_corr = sum(right_energies) + right_dG + right_solv_corr
174
+ energies_corr = [left_energy_corr, ts_energy_corr]
175
+ # TS is always only 1 geometry
176
+ geom_nums = [len(left_geoms), 1]
177
+
178
+ fns = ["Left", "TS"]
179
+ if right_geoms:
180
+ energies_corr.append(right_energy_corr)
181
+ geom_nums.append(len(right_geoms))
182
+ fns.append("Right")
183
+ max_len = max(len(s) for s in fns)
184
+
185
+ def print_table(table, header, width=17):
186
+ col_fmts = ["str"] + (len(header) - 1) * ["float"]
187
+ tp = TablePrinter(header, col_fmts, width=width, sub_underline=False)
188
+ tp.print_header()
189
+ for fn, row in zip(all_fns, table.T):
190
+ fn = str(fn) # fns may be PosixPath etc.
191
+ fn_cut = fn[:4] + ".." + fn[-11:] if (len(fn) > width) else fn
192
+ tp.print_row((fn_cut, *row))
193
+ print()
194
+
195
+ all_fns = left_fns + [ts_fn] + right_fns
196
+ # Electronic energies
197
+ all_energies = np.concatenate((left_energies, [ts_energy], right_energies))
198
+ to_stack = [all_energies]
199
+ gas_titles = ["File", "E_el"]
200
+ if do_thermo:
201
+ # Thermochemical corrections
202
+ all_dGs = np.concatenate((left_dGs, [ts_dG], right_dGs))
203
+ # Free Gibbs energies in the gas phase
204
+ all_Gs_gas = all_energies + all_dGs
205
+ to_stack += [all_dGs, all_Gs_gas]
206
+ gas_titles += ["dG_gas", "G_gas"]
207
+
208
+ gas_table = np.stack(to_stack)
209
+ print("All tabulated quantities are given in au.\n")
210
+ print_table(gas_table, gas_titles)
211
+ full_titles = gas_titles
212
+
213
+ if solv_calc_getter is not None:
214
+ all_solv_energies = np.concatenate(
215
+ (left_solv_energies, [ts_solv_energy], right_solv_energies)
216
+ )
217
+ all_solv_corrs = np.concatenate(
218
+ (left_solv_corrs, [ts_solv_corr], right_solv_corrs)
219
+ )
220
+ to_stack = [all_energies, all_solv_energies, all_solv_corrs]
221
+ solv_titles = ["File", "E_el", "E_solv", "dG_solv"]
222
+ if do_thermo:
223
+ all_Gs_sol = all_Gs_gas + all_solv_corrs
224
+ to_stack += [all_Gs_sol]
225
+ solv_titles += ["G_sol"]
226
+ solv_table = np.stack(to_stack)
227
+ if do_ssc:
228
+ print("dG_solv includes a correction for change of standard state.\n")
229
+ print_table(solv_table, solv_titles)
230
+ full_titles += solv_titles[2:]
231
+
232
+ energies_corr = np.array(energies_corr)
233
+ energies_corr -= energies_corr.min()
234
+ min_ind = energies_corr.argmin()
235
+ energies_corr *= AU2KJPERMOL
236
+
237
+ print(highlight_text("Barriers", level=1))
238
+ print()
239
+ print(f"Temperature: {T:.2f} K")
240
+ print(f"Pressure: {p:.1f} Pa\n")
241
+
242
+ print("Corrections:")
243
+ print(f"Change of standard-state: {do_ssc}, {ssc*AU2KJPERMOL:.2} kJ mol⁻¹")
244
+ print(f" Solvent: {solv_calc_getter is not None}")
245
+ print(f" Thermochemistry: {do_thermo}")
246
+ print()
247
+
248
+ def print_geoms_fns(geoms, fns):
249
+ for i, (geom, fn) in enumerate(zip(geoms, fns)):
250
+ fn_name = Path(fn).name
251
+ print(f"\t{i}: {fn_name} ({geom}, {len(geom.atoms)} atoms)")
252
+
253
+ def get_geom_key(geoms):
254
+ return "geometry" if len(geoms) == 1 else "geometries"
255
+
256
+ print(f"Left {get_geom_key(left_geoms)}:")
257
+ print_geoms_fns(left_geoms, left_fns)
258
+ print("TS geometry:")
259
+ print_geoms_fns((ts_geom,), ("",))
260
+ if right_geoms:
261
+ print(f"Right {get_geom_key(right_geoms)}:")
262
+ print_geoms_fns(right_geoms, right_fns)
263
+ print()
264
+
265
+ print(f"Minimum {en_key} of {energies_corr[min_ind]} kJ mol⁻¹ at '{fns[min_ind]}'.")
266
+ print()
267
+ for fn, en, gnum in zip(fns, energies_corr, geom_nums):
268
+ geom_str = "geometry" if gnum == 1 else "geometries"
269
+ is_sum = " " if gnum == 1 else "Σ"
270
+ print(f"\t{is_sum}{fn:>{max_len}s}: {en:>8.2f} kJ mol⁻¹ ({gnum} {geom_str})")
271
+ print()
@@ -0,0 +1,138 @@
1
+ # [1] https://onlinelibrary.wiley.com/doi/abs/10.1002/jcc.23910
2
+ # Birkholz, Schlegel, 2015
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.Geometry import Geometry
7
+ from pysisyphus.drivers import relaxed_scan
8
+ from pysisyphus.helpers_pure import highlight_text
9
+ from pysisyphus.intcoords.setup import get_bond_mat
10
+ from pysisyphus.intcoords.PrimTypes import normalize_prim_inputs
11
+
12
+
13
+ def bond_order(r, r0, b=2):
14
+ """Bond order for given bond length and reference length.
15
+
16
+ Eq. (3) in [1]."""
17
+ return max(0, (b * (r0 / r) - 1) / (b - 1))
18
+
19
+
20
+ def bond_orders(coords3d, bond_indices, r0s):
21
+ """List of bond orders."""
22
+ bos = list()
23
+ for r0, (a, b) in zip(r0s, bond_indices):
24
+ r = np.linalg.norm(coords3d[a] - coords3d[b])
25
+ bo = bond_order(r, r0)
26
+ bos.append(bo)
27
+ return np.array(bos)
28
+
29
+
30
+ def get_r0s(geom, bond_indices):
31
+ """Reference bond lengths as sum of covalent radii."""
32
+ crs = geom.covalent_radii
33
+ a, b = bond_indices.T
34
+ return crs[a] + crs[b]
35
+
36
+
37
+ def bond_orders_for_geom(geom, bond_indices):
38
+ """Wrapper for bond_orders for simple use with Geometry."""
39
+ r0s = get_r0s(geom, bond_indices)
40
+ return bond_orders(geom.coords3d, bond_indices, r0s)
41
+
42
+
43
+ def length_for_bond_order(bo, r0, b=2):
44
+ """Return bond length for given bond order and reference length.
45
+
46
+ Eq. (3) in [1]."""
47
+ return b / ((b - 1) * bo + 1) * r0
48
+
49
+
50
+ def birkholz_interpolation(geoms, calc_getter, recreate=True):
51
+ assert len(geoms) >= 2
52
+ start = geoms[0]
53
+ end = geoms[-1]
54
+ geoms = (start, end)
55
+ atoms = start.atoms
56
+ print(f"Coordinates of 'start' geometry\n{start.as_xyz()})")
57
+ print(f"Coordinates of 'end' geometry\n{end.as_xyz()})\n")
58
+
59
+ print(highlight_text("Bonding analysis"))
60
+ # Bond matrices
61
+ bm_start, bm_end = [get_bond_mat(geom) for geom in geoms]
62
+ # Determine formed/broken bonds. The lower triangular part of the bond
63
+ # matrices has to be zeroed, to avoid double counting. Changes in bonding
64
+ # are determined with logical XOR.
65
+ #
66
+ # Start End XOR Comment
67
+ # ----- --- --- -------
68
+ # True True False Bond is present at both geometries.
69
+ # False False False Bond is absent at both geometries.
70
+ # True False True Bond is broken when going from start to end.
71
+ # False True True Bond is formed when going from start to end.
72
+ bm_diff = np.triu(bm_start) ^ np.triu(bm_end)
73
+ bond_indices = np.stack(np.nonzero(bm_diff), axis=1)
74
+ bonding_changes = bm_diff.sum()
75
+ print(f"{bonding_changes} bonds are formed/broken when going from start to end.\n")
76
+
77
+ # Determine bond orders at start and end
78
+ all_bos = [bond_orders_for_geom(geom, bond_indices) for geom in geoms]
79
+ # Reference bond lengths
80
+ r0s = get_r0s(start, bond_indices)
81
+
82
+ # Print summary
83
+ for title, geom, bos in zip(("Start", "End"), geoms, all_bos):
84
+ print(highlight_text(title, level=1))
85
+ for bo_, (a, b) in zip(bos, bond_indices):
86
+ aa = atoms[a]
87
+ ba = atoms[b]
88
+ print(f"Bond ({aa}{a: >4},{ba}{b: >4}): BO={bo_:.2f}")
89
+ print(
90
+ f"mean(BOs)={bos.mean():.2f}, max(BOs)={bos.max():.2f}, min(BOs)={bos.min():.2f}"
91
+ )
92
+ print()
93
+
94
+ # Guess goal bond lenghts from mean bond order
95
+ start_bos, end_bos = all_bos
96
+ mean_bos = (start_bos + end_bos) / 2
97
+ # Determine goal bond lenghts that yield the mean bond orders
98
+ goal_lengths = length_for_bond_order(mean_bos, r0s)
99
+
100
+ # Constrain formed/broken bonds
101
+ constrain_prims = normalize_prim_inputs([["BOND", *bond] for bond in bond_indices])
102
+
103
+ # Start relaxed scans towards TS from 'start' and 'end'
104
+ print(highlight_text("Relaxed scan towards TS, from 'start'"))
105
+ start_guess, *_ = relaxed_scan(
106
+ start, calc_getter, constrain_prims, target_values=goal_lengths, title="start"
107
+ )
108
+ print()
109
+ start_guess.dump_xyz("start_guess")
110
+
111
+ print(highlight_text("Relaxed scan towards TS, from 'end'"))
112
+ end_guess, *_ = relaxed_scan(
113
+ end, calc_getter, constrain_prims, target_values=goal_lengths, title="end"
114
+ )
115
+ print()
116
+ end_guess.dump_xyz("end_guess")
117
+
118
+ # Compare energies and take the one with lower energy
119
+ start_en = start_guess.energy
120
+ end_en = end_guess.energy
121
+ print(f"Energy of 'start'-guess: {start_en:.6f} au")
122
+ print(f"Energy of 'end'-guess: {end_en:.6f} au")
123
+ start_lower = start_en <= end_en
124
+ lower = "'start'-guess" if start_lower else "'end'-guess"
125
+ print(f"{lower} has lower energy.")
126
+ ts_guess = start_guess if start_lower else end_guess
127
+
128
+ if recreate:
129
+ print("Recreated Geometry object.")
130
+ ts_guess = Geometry(ts_guess.atoms, ts_guess.cart_coords, coord_type="redund")
131
+ ts_guess.set_calculator(calc_getter())
132
+ print()
133
+ print(f"Coordinates of TS guess\n{ts_guess.as_xyz()})\n")
134
+ ts_guess_fn = "ts_guess.xyz"
135
+ ts_guess.dump_xyz(ts_guess_fn)
136
+ print(f"Dumped TS-guess to '{ts_guess_fn}'.")
137
+
138
+ return ts_guess