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,669 @@
1
+ # [1] https://doi.org/10.1002/jcc.26495
2
+ # Habershon, 2021
3
+
4
+ """
5
+ prp a901cdfacc579eb63b193cbc9043212e8b57746f
6
+ pysis 340ab6105ac4156f0613b4d0e8f080d9f195530c
7
+ do_trans accidentally disabled in transtorque
8
+ """
9
+
10
+ from functools import reduce
11
+ import itertools as it
12
+
13
+ import numpy as np
14
+
15
+ from pysisyphus.calculators import (
16
+ HardSphere,
17
+ TransTorque,
18
+ AtomAtomTransTorque,
19
+ Composite,
20
+ )
21
+ from pysisyphus.constants import BOHR2ANG
22
+ from pysisyphus.Geometry import Geometry
23
+ from pysisyphus.helpers import align_coords
24
+ from pysisyphus.helpers_pure import highlight_text
25
+ from pysisyphus.init_logging import init_logging
26
+ from pysisyphus.intcoords.setup import get_fragments, get_bond_sets
27
+ from pysisyphus.xyzloader import coords_to_trj, make_xyz_str
28
+
29
+
30
+ init_logging()
31
+
32
+
33
+ class SteepestDescent:
34
+ def __init__(
35
+ self,
36
+ geom,
37
+ max_cycles=1000,
38
+ max_step=0.05,
39
+ rms_force=0.05,
40
+ rms_force_only=True,
41
+ prefix=None,
42
+ dump=False,
43
+ dump_every=100,
44
+ print_every=100,
45
+ ):
46
+ self.geom = geom
47
+ self.max_cycles = max_cycles
48
+ self.max_step = max_step
49
+ self.rms_force = rms_force
50
+ self.rms_force_only = rms_force_only
51
+ if prefix is not None:
52
+ prefix = f"{prefix}_"
53
+ self.prefix = prefix
54
+ self.dump = dump
55
+ self.dump_every = dump_every
56
+ self.print_every = print_every
57
+
58
+ self.all_coords = np.zeros((max_cycles, self.geom.coords.size))
59
+
60
+ def run(self):
61
+ coords = self.geom.coords.copy()
62
+
63
+ to_dump = []
64
+
65
+ for i in range(self.max_cycles):
66
+ self.all_coords[i] = coords.copy()
67
+ if self.dump and (i % self.dump_every) == 0:
68
+ to_dump.append(self.geom.as_xyz(cart_coords=coords))
69
+ results = self.geom.get_energy_and_forces_at(coords)
70
+ forces = results["forces"]
71
+ norm = np.linalg.norm(forces)
72
+ rms = np.sqrt(np.mean(forces**2))
73
+
74
+ if i > 0:
75
+ beta = forces.dot(forces) / self.prev_forces.dot(self.prev_forces)
76
+ step = forces + beta * self.prev_step
77
+ else:
78
+ step = forces.copy()
79
+
80
+ step *= min(self.max_step / np.abs(step).max(), 1)
81
+ converged = rms <= self.rms_force
82
+
83
+ # Append step information when not yet converged
84
+ if i % self.print_every == 0 or converged:
85
+ print(
86
+ f"{i:05d}: |forces|={norm: >12.6f} "
87
+ f"rms(forces)={np.sqrt(np.mean(forces**2)): >12.6f} "
88
+ f" |step|={np.linalg.norm(step): >12.6f}"
89
+ )
90
+
91
+ if converged:
92
+ print(f"Converged in cycle {i}. Breaking.")
93
+ break
94
+
95
+ coords += step
96
+
97
+ self.prev_step = step
98
+ self.prev_forces = forces
99
+ self.geom.coords = coords
100
+ self.all_coords = self.all_coords[: i + 1]
101
+
102
+ if to_dump:
103
+ with open(f"{self.prefix}optimization_trj.xyz", "w") as handle:
104
+ handle.write("\n".join(to_dump))
105
+
106
+
107
+ def get_fragments_and_bonds(geoms):
108
+ if isinstance(geoms, Geometry) or len(geoms) == 1:
109
+ geom = geoms
110
+ atoms = geom.atoms
111
+ coords3d = geom.coords3d
112
+ bonds = [frozenset(bond) for bond in get_bond_sets(atoms, coords3d)]
113
+ fragments = get_fragments(atoms, coords3d.flatten(), bond_inds=bonds)
114
+ frag_inds = list(it.chain(*fragments))
115
+ if len(frag_inds) != len(atoms):
116
+ all_inds = list(range(len(atoms)))
117
+ missing_inds = set(all_inds) - set(frag_inds)
118
+ for mi in missing_inds:
119
+ fragments.append(frozenset((mi,)))
120
+
121
+ frag_bonds = [
122
+ list(filter(lambda bond: bond <= frag, bonds)) for frag in fragments
123
+ ]
124
+ # frag_atoms = [[a for i, a in enumerate(atoms) if i in frag] for frag in fragments]
125
+
126
+ # Assert that we do not have any interfragment bonds
127
+ assert reduce((lambda x, y: x + len(y)), frag_bonds, 0) == len(bonds)
128
+ union_geom = geom.copy(coord_type="cart")
129
+ else:
130
+ # Form union, determine consistent new indices for all atoms and calculate bonds
131
+ raise Exception()
132
+
133
+ # return fragments, frag_bonds, set(bonds), frag_atoms
134
+ return fragments, frag_bonds, set(bonds), union_geom
135
+
136
+
137
+ def get_rot_mat(coords3d_1, coords3d_2, center=False):
138
+ coords3d_1 = coords3d_1.copy().reshape(-1, 3)
139
+ coords3d_2 = coords3d_2.copy().reshape(-1, 3)
140
+
141
+ def _center(coords3d):
142
+ return coords3d - coords3d.mean(axis=0)
143
+
144
+ if center:
145
+ coords3d_1 = _center(coords3d_1)
146
+ coords3d_2 = _center(coords3d_2)
147
+
148
+ tmp_mat = coords3d_1.T.dot(coords3d_2)
149
+ U, W, Vt = np.linalg.svd(tmp_mat)
150
+ rot_mat = U.dot(Vt)
151
+ # Avoid reflections
152
+ if np.linalg.det(rot_mat) < 0:
153
+ U[:, -1] *= -1
154
+ rot_mat = U.dot(Vt)
155
+ return rot_mat
156
+
157
+
158
+ def get_steps_to_active_atom_mean(
159
+ frag_lists, iter_frag_lists, ind_dict, coords3d, skip=True
160
+ ):
161
+ frag_num = len(frag_lists)
162
+ steps = np.zeros((frag_num, 3))
163
+ for m, frag_m in enumerate(frag_lists):
164
+ step_m = np.zeros(3)
165
+ for n, _ in enumerate(iter_frag_lists):
166
+ if skip and m == n:
167
+ continue
168
+ active_inds = ind_dict[(n, m)]
169
+ if len(active_inds) == 0:
170
+ continue
171
+ step_m += coords3d[active_inds].mean(axis=0)
172
+ step_m /= frag_num
173
+ steps[m] = step_m
174
+ return steps
175
+
176
+
177
+ def report_frags(rgeom, pgeom, rfrags, pfrags, rbond_diff, pbond_diff):
178
+ for name, geom in (("Reactant(s)", rgeom), ("Product(s)", pgeom)):
179
+ print(f"{name}: {geom}\n\n{geom.as_xyz()}\n")
180
+
181
+ def get_frag_atoms(geom, frag):
182
+ atoms = geom.atoms
183
+ return [atoms[i] for i in frag]
184
+
185
+ for name, geom, frags in (("reactant", rgeom, rfrags), ("product", pgeom, pfrags)):
186
+ print(f"{len(frags)} Fragment(s) in {name} image:\n")
187
+ for frag in frags:
188
+ frag_atoms = get_frag_atoms(geom, frag)
189
+ frag_coords = geom.coords3d[list(frag)]
190
+ frag_xyz = make_xyz_str(frag_atoms, frag_coords * BOHR2ANG)
191
+ print(frag_xyz + "\n")
192
+
193
+ def print_bonds(geom, bonds):
194
+ for from_, to_ in bonds:
195
+ from_atom, to_atom = [geom.atoms[i] for i in (from_, to_)]
196
+ print(f"\t({from_: >3d}{from_atom} - {to_: >3d}{to_atom})")
197
+
198
+ print("Bonds broken in reactant image:")
199
+ print_bonds(rgeom, rbond_diff)
200
+ print()
201
+ print("Bonds formed in product image:")
202
+ print_bonds(pgeom, pbond_diff)
203
+ print()
204
+
205
+
206
+ def report_mats(name, mats):
207
+ for (m, n), indices in mats.items():
208
+ print(f"{name}({m}, {n}): {indices}")
209
+ print()
210
+
211
+
212
+ def center_fragments(frag_list, geom):
213
+ c3d = geom.coords3d
214
+ for frag in frag_list:
215
+ mean = c3d[frag].mean(axis=0)
216
+ c3d[frag] -= mean[None, :]
217
+
218
+
219
+ def get_which_frag(frags):
220
+ which_frag = dict()
221
+ for frag_ind, frag in enumerate(frags):
222
+ which_frag.update({atom_ind: frag_ind for atom_ind in frag})
223
+ return which_frag
224
+
225
+
226
+ def form_A(frags, which_frag, formed_bonds):
227
+ """Construct the A-matrices.
228
+
229
+ AR[(m, n)] (AP[(m, n)]) contains the subset of atoms in Rm (Pm) that forms
230
+ bonds with Rn (Pn).
231
+ """
232
+ A = dict()
233
+ for m, n in formed_bonds:
234
+ key = (which_frag[m], which_frag[n])
235
+ A.setdefault(key, list()).append(m)
236
+ A.setdefault(key[::-1], list()).append(n)
237
+ return A
238
+
239
+
240
+ def rotate_inplace(frags, union, bonds):
241
+ # which_frag could also be calculated outside of this function
242
+ which_frag = dict()
243
+ for i, frag in enumerate(frags):
244
+ for ind in frag:
245
+ which_frag[ind] = i
246
+ AR = form_A(frags, which_frag, bonds)
247
+
248
+ def form_G(A):
249
+ G = dict()
250
+ for (m, n), inds in A.items():
251
+ G.setdefault(m, set())
252
+ G[m] |= set(inds)
253
+
254
+ for k, v in G.items():
255
+ G[k] = list(v)
256
+ assert len(v) > 0
257
+ return G
258
+
259
+ GR = form_G(AR)
260
+
261
+ # Rotate R fragments
262
+ alphas = get_steps_to_active_atom_mean(frags, frags, AR, union.coords3d)
263
+ gammas = np.zeros_like(alphas)
264
+ for m, rfrag in enumerate(frags):
265
+ Gm = GR[m]
266
+ gammas[m] = union.coords3d[Gm].mean(axis=0)
267
+ r_means = np.array([union.coords3d[frag].mean(axis=0) for frag in frags])
268
+
269
+ for m, rfrag in enumerate(frags):
270
+ gm = r_means[m]
271
+ rot_mat = get_rot_mat(gammas[m] - gm, alphas[m] - gm)
272
+ rot_coords = (union.coords3d[rfrag] - gm).dot(rot_mat)
273
+ union.coords3d[rfrag] = rot_coords + gm - rot_coords.mean(axis=0)
274
+
275
+
276
+ CONFIG = {
277
+ "s2_hs_kappa": 1.0,
278
+ "s4_hs_kappa": 50.0,
279
+ "s4_v_kappa": 1.0,
280
+ "s4_w_kappa": 1.0,
281
+ "s5_v_kappa": 1.0,
282
+ "s5_w_kappa": 3.0,
283
+ "s5_hs_kappa": 10.0,
284
+ "s5_z_kappa": 2.0,
285
+ "s5_trans": True,
286
+ "s5_rms_force": 0.01,
287
+ }
288
+
289
+
290
+ def precon_pos_rot(reactants, products, prefix=None, config=CONFIG):
291
+ c = config
292
+
293
+ if prefix is None:
294
+ prefix = ""
295
+
296
+ def make_fn(fn):
297
+ return prefix + fn
298
+
299
+ rfrags, rfrag_bonds, rbonds, runion = get_fragments_and_bonds(reactants)
300
+ pfrags, pfrag_bonds, pbonds, punion = get_fragments_and_bonds(products)
301
+
302
+ pbond_diff = pbonds - rbonds # Present in product(s)
303
+ rbond_diff = rbonds - pbonds # Present in reactant(s)
304
+ involved_atoms = set(tuple(it.chain(*pbond_diff)))
305
+ involved_atoms |= set(tuple(it.chain(*rbond_diff)))
306
+
307
+ which_rfrag = get_which_frag(rfrags)
308
+ which_pfrag = get_which_frag(pfrags)
309
+
310
+ rfrag_lists = [list(frag) for frag in rfrags]
311
+ pfrag_lists = [list(frag) for frag in pfrags]
312
+
313
+ report_frags(runion, punion, rfrags, pfrags, rbond_diff, pbond_diff)
314
+
315
+ def form_C(m_frags, n_frags):
316
+ """Construct the C-matrices.
317
+
318
+ Returns a dict with (m, n) keys, containing the respective
319
+ unions of rectant fragment n and product fragment m.
320
+ """
321
+ C = dict()
322
+ for m, m_frag in enumerate(m_frags):
323
+ for n, n_frag in enumerate(n_frags):
324
+ C[(m, n)] = list(m_frag & n_frag)
325
+ return C
326
+
327
+ CR = form_C(rfrags, pfrags)
328
+ assert len(set(it.chain(*CR.values()))) == len(runion.atoms)
329
+ CP = {(n, m): union for (m, n), union in CR.items()}
330
+ print("CR(m, n), subset of atoms in molecule Rn which are in Pm after reaction.")
331
+ report_mats("CR", CR)
332
+ print("CP(m, n), subset of atoms in molecule Pn which are in Rm before reaction.")
333
+ report_mats("CP", CP)
334
+
335
+ def form_B(C):
336
+ """Construct the B-matrices.
337
+
338
+ Returns a dict with (m, n) keys, containing the respective
339
+ subsets of C[(m, n)] that acutally participate in bond-breaking/forming.
340
+ """
341
+ B = dict()
342
+ for (m, n), union in C.items():
343
+ key = (m, n)
344
+ B.setdefault(key, set())
345
+ B[key] |= set(union) & involved_atoms
346
+ for k, v in B.items():
347
+ B[k] = list(v)
348
+ return B
349
+
350
+ BR = form_B(CR)
351
+ BP = form_B(CP)
352
+ print(
353
+ "BR(m, n), subset of atoms in CRnm actually involved in bond forming/breaking."
354
+ )
355
+ report_mats("BR", BR)
356
+ print(
357
+ "BP(m, n), subset of atoms in CPnm actually involved in bond forming/breaking."
358
+ )
359
+ report_mats("BP", BP)
360
+
361
+ AR = form_A(rfrags, which_rfrag, pbond_diff)
362
+ AP = form_A(pfrags, which_pfrag, rbond_diff)
363
+ print("AR(m, n), subset of atoms in Rm that form bonds to atoms in Rn.")
364
+ report_mats("AR", AR)
365
+ print(
366
+ "AP(m, n), subset of atoms in Pm which had bonds with Pn (formerly bonded in R)."
367
+ )
368
+ report_mats("AP", AP)
369
+
370
+ def form_G(A):
371
+ G = dict()
372
+ for (m, n), inds in A.items():
373
+ G.setdefault(m, set())
374
+ G[m] |= set(inds)
375
+
376
+ for k, v in G.items():
377
+ G[k] = list(v)
378
+ assert len(v) > 0
379
+ return G
380
+
381
+ GR = form_G(AR)
382
+ # GP = form_G(AP)
383
+ print(f"GR: {GR}")
384
+ # print(f"GP: {GP}")
385
+
386
+ # Initial, centered, coordinates and 5 stages
387
+ r_coords = np.zeros((6, runion.coords.size))
388
+ p_coords = np.zeros((6, punion.coords.size))
389
+
390
+ def backup_coords(stage):
391
+ assert 0 <= stage < 6
392
+ r_coords[stage] = runion.coords.copy()
393
+ p_coords[stage] = punion.coords.copy()
394
+
395
+ """
396
+ STAGE 1
397
+ Initial positioning of reactant and product molecules
398
+ """
399
+
400
+ # Center fragments at their geometric average
401
+ center_fragments(rfrag_lists, runion)
402
+ center_fragments(pfrag_lists, punion)
403
+
404
+ backup_coords(0)
405
+
406
+ # Translate reactant molecules
407
+ alphas = get_steps_to_active_atom_mean(
408
+ rfrag_lists, rfrag_lists, AR, runion.coords3d
409
+ )
410
+ for rfrag, alpha in zip(rfrag_lists, alphas):
411
+ runion.coords3d[rfrag] += alpha
412
+
413
+ # Translate product molecules
414
+ betas = get_steps_to_active_atom_mean(
415
+ pfrag_lists, rfrag_lists, BR, punion.coords3d, skip=False
416
+ )
417
+ sigmas = get_steps_to_active_atom_mean(
418
+ pfrag_lists, rfrag_lists, CR, punion.coords3d, skip=False
419
+ )
420
+ bs_half = (betas + sigmas) / 2
421
+ for pfrag, bsh in zip(pfrag_lists, bs_half):
422
+ punion.coords3d[pfrag] += bsh
423
+
424
+ backup_coords(1)
425
+ print()
426
+
427
+ """
428
+ STAGE 2
429
+ Intra-image Inter-molecular Hard-Sphere forces
430
+ """
431
+
432
+ print(highlight_text("Stage 2, Hard-Sphere Forces"))
433
+
434
+ s2_hs_kappa = c["s2_hs_kappa"]
435
+
436
+ def hardsphere_sd_opt(geom, frag_lists, title):
437
+ print(highlight_text(title, level=1))
438
+ calc = HardSphere(geom, frag_lists, kappa=s2_hs_kappa)
439
+ geom.set_calculator(calc)
440
+ opt_kwargs = {
441
+ "max_cycles": 1000,
442
+ "max_step": 0.5,
443
+ "rms_force": 0.05,
444
+ }
445
+ opt = SteepestDescent(geom, **opt_kwargs)
446
+ opt.run()
447
+
448
+ hardsphere_sd_opt(runion, rfrag_lists, "Reactants")
449
+ hardsphere_sd_opt(punion, pfrag_lists, "Products")
450
+
451
+ backup_coords(2)
452
+ print()
453
+
454
+ """
455
+ STAGE 3
456
+ Initial orientation of molecules
457
+ """
458
+
459
+ print(highlight_text("Stage 3, Initial Orientation"))
460
+
461
+ # Rotate R fragments
462
+ # TODO: refactor to use rotate_inplace()
463
+ if len(rfrag_lists) > 1:
464
+ alphas = get_steps_to_active_atom_mean(
465
+ rfrag_lists, rfrag_lists, AR, runion.coords3d
466
+ )
467
+ gammas = np.zeros_like(alphas)
468
+ for m, rfrag in enumerate(rfrag_lists):
469
+ Gm = GR[m]
470
+ gammas[m] = runion.coords3d[Gm].mean(axis=0)
471
+ r_means = np.array([runion.coords3d[frag].mean(axis=0) for frag in rfrag_lists])
472
+
473
+ for m, rfrag in enumerate(rfrag_lists):
474
+ gm = r_means[m]
475
+ rot_mat = get_rot_mat(gammas[m] - gm, alphas[m] - gm)
476
+ rot_coords = (runion.coords3d[rfrag] - gm).dot(rot_mat)
477
+ runion.coords3d[rfrag] = rot_coords + gm - rot_coords.mean(axis=0)
478
+
479
+ Ns = [0] * len(pfrag_lists)
480
+ for (m, n), CPmn in CP.items():
481
+ Ns[m] += len(CPmn)
482
+
483
+ # Rotate P fragments
484
+ for m, pfrag in enumerate(pfrag_lists):
485
+ pc3d = punion.coords3d[pfrag]
486
+ gm = pc3d.mean(axis=0)
487
+ r0Pm = pc3d - gm[None, :]
488
+ mu_Pm = np.zeros_like(r0Pm)
489
+ N = Ns[m]
490
+ for n, rfrag in enumerate(rfrag_lists):
491
+ # Skip rotation of 1-atom fragments
492
+ if len(rfrag) == 1:
493
+ continue
494
+ CPmn = CP[(m, n)]
495
+ RPmRn = get_rot_mat(
496
+ punion.coords3d[CPmn], runion.coords3d[CPmn], center=True
497
+ )
498
+ print(f"m={m}, n={n}, len(CPmn)={len(CPmn)}")
499
+ # Eq. (A2) in [1]
500
+ r0Pmn = np.einsum("ij,jk->ki", RPmRn, r0Pm.T)
501
+ mu_Pm += len(CPmn) ** 2 / N * r0Pmn
502
+ rot_mat = get_rot_mat(r0Pm, mu_Pm, center=True)
503
+ rot_coords = r0Pm.dot(rot_mat)
504
+ punion.coords3d[pfrag] = rot_coords + gm - rot_coords.mean(axis=0)
505
+
506
+ backup_coords(3)
507
+ print()
508
+
509
+ """
510
+ STAGE 4
511
+ Alignment of reactive atoms
512
+
513
+ This stage involves three forces: hard-sphere forces and two kinds
514
+ of average translational (^t) and rotational (^r) forces (v and w,
515
+ (A3) - (A5) in [1]).
516
+
517
+ v^t and v^r arise from atoms in A^Rnm and A^Rmn, that is atoms that
518
+ participate in bond forming/breaking in R. The translational force
519
+ is usually attractive, which is counteracted by the repulsive hard-sphere
520
+ forces.
521
+ """
522
+
523
+ print(highlight_text("Stage 4, Alignment Of Reactive Atoms"))
524
+
525
+ def composite_sd_opt(geom, keys_calcs, title, rms_force=0.05):
526
+ print(highlight_text(title, level=1))
527
+ final = " + ".join([k for k in keys_calcs.keys()])
528
+ calc = Composite(final, keys_calcs=keys_calcs)
529
+ geom.set_calculator(calc)
530
+ opt_kwargs = {
531
+ "max_step": 0.05,
532
+ "max_cycles": 2000,
533
+ "rms_force": rms_force,
534
+ }
535
+ opt = SteepestDescent(geom, **opt_kwargs)
536
+ opt.run()
537
+
538
+ def get_vr_trans_torque(kappa=1.0, do_trans=True):
539
+ return TransTorque(
540
+ rfrag_lists, rfrag_lists, AR, AR, kappa=kappa, do_trans=do_trans
541
+ )
542
+
543
+ def r_weight_func(m, n, a, b):
544
+ """As required for (A5) in [1]."""
545
+ return 1 if a in BR[(m, n)] else 0.5
546
+
547
+ def get_wr_trans_torque(kappa=1.0, do_trans=True):
548
+ return TransTorque(
549
+ rfrag_lists,
550
+ pfrag_lists,
551
+ CR,
552
+ CP,
553
+ weight_func=r_weight_func,
554
+ skip=False,
555
+ b_coords3d=punion.coords3d,
556
+ kappa=kappa,
557
+ do_trans=do_trans,
558
+ )
559
+
560
+ def get_vp_trans_torque(kappa=1.0, do_trans=True):
561
+ return TransTorque(
562
+ pfrag_lists, pfrag_lists, AP, AP, kappa=kappa, do_trans=do_trans
563
+ )
564
+
565
+ def p_weight_func(m, n, a, b):
566
+ """As required for (A5) in [1]."""
567
+ return 1 if a in BP[(m, n)] else 0.5
568
+
569
+ def get_wp_trans_torque(kappa=1.0, do_trans=True):
570
+ return TransTorque(
571
+ pfrag_lists,
572
+ rfrag_lists,
573
+ CP,
574
+ CR,
575
+ weight_func=p_weight_func,
576
+ skip=False,
577
+ b_coords3d=runion.coords3d,
578
+ kappa=kappa,
579
+ do_trans=do_trans,
580
+ )
581
+
582
+ s4_hs_kappa = c["s4_hs_kappa"]
583
+ s4_v_kappa = c["s4_v_kappa"]
584
+ s4_w_kappa = c["s4_w_kappa"]
585
+
586
+ vr_trans_torque = get_vr_trans_torque(kappa=s4_v_kappa)
587
+ wr_trans_torque = get_wr_trans_torque(kappa=s4_w_kappa)
588
+ r_keys_calcs = {
589
+ "hardsphere": HardSphere(runion, rfrag_lists, kappa=s4_hs_kappa),
590
+ "v": vr_trans_torque,
591
+ "w": wr_trans_torque,
592
+ }
593
+ composite_sd_opt(runion, r_keys_calcs, "Reactants")
594
+
595
+ vp_trans_torque = get_vp_trans_torque(kappa=s4_v_kappa)
596
+ wp_trans_torque = get_wp_trans_torque(kappa=s4_w_kappa)
597
+ p_keys_calcs = {
598
+ "hardsphere": HardSphere(punion, pfrag_lists, kappa=s4_hs_kappa),
599
+ "v": vp_trans_torque,
600
+ "w": wp_trans_torque,
601
+ }
602
+ composite_sd_opt(punion, p_keys_calcs, "Products")
603
+
604
+ backup_coords(4)
605
+ print()
606
+
607
+ """
608
+ STAGE 5
609
+ Refinement of atomic positions using further hard-sphere forces.
610
+ """
611
+
612
+ print(highlight_text("Stage 5, Refinement"))
613
+
614
+ s5_v_kappa = c["s5_v_kappa"]
615
+ s5_w_kappa = c["s5_w_kappa"]
616
+ s5_hs_kappa = c["s5_hs_kappa"]
617
+ s5_z_kappa = c["s5_z_kappa"]
618
+ s5_trans = c["s5_trans"]
619
+ s5_rms_force = c["s5_rms_force"]
620
+
621
+ vr_trans_torque = get_vr_trans_torque(kappa=s5_v_kappa, do_trans=s5_trans)
622
+ wr_trans_torque = get_wr_trans_torque(kappa=s5_w_kappa, do_trans=s5_trans)
623
+ zr_aa_trans_torque = AtomAtomTransTorque(runion, rfrag_lists, AR, kappa=s5_z_kappa)
624
+ r_keys_calcs = {
625
+ "v": vr_trans_torque,
626
+ "w": wr_trans_torque,
627
+ "hardsphere": HardSphere(runion, rfrag_lists, kappa=s5_hs_kappa),
628
+ "z": zr_aa_trans_torque,
629
+ }
630
+ composite_sd_opt(runion, r_keys_calcs, "Reactants", rms_force=s5_rms_force)
631
+
632
+ vp_trans_torque = get_vp_trans_torque(kappa=s5_v_kappa, do_trans=s5_trans)
633
+ wp_trans_torque = get_wp_trans_torque(kappa=s5_w_kappa, do_trans=s5_trans)
634
+ zp_aa_trans_torque = AtomAtomTransTorque(punion, pfrag_lists, AP, kappa=s5_z_kappa)
635
+ p_keys_calcs = {
636
+ "v": vp_trans_torque,
637
+ "w": wp_trans_torque,
638
+ "hardsphere": HardSphere(punion, pfrag_lists, kappa=s5_hs_kappa),
639
+ "z": zp_aa_trans_torque,
640
+ }
641
+ composite_sd_opt(punion, p_keys_calcs, "Products", rms_force=s5_rms_force)
642
+
643
+ backup_coords(5)
644
+ print()
645
+
646
+ with open(make_fn("s5_trj.xyz"), "w") as handle:
647
+ handle.write("\n".join([geom.as_xyz() for geom in (runion, punion)]))
648
+
649
+ def dump_stages(fn, atoms, coords_list):
650
+ align_coords(coords_list)
651
+ comments = [f"Stage {i}" for i in range(coords_list.shape[0])]
652
+ fn = make_fn(fn)
653
+ coords_to_trj(fn, atoms, coords_list, comments=comments)
654
+
655
+ dump_stages("r_coords_trj.xyz", runion.atoms, r_coords)
656
+ dump_stages("p_coords_trj.xyz", punion.atoms, p_coords)
657
+
658
+ runion.set_calculator(None)
659
+ punion.set_calculator(None)
660
+ return runion, punion
661
+
662
+
663
+ def run_precontr(reactant_geom, product_geom, **kwargs):
664
+ print(
665
+ highlight_text("Preconditioning of Translation & Rotation")
666
+ + "\n\nPlease cite https://doi.org/10.1002/jcc.26495\n"
667
+ )
668
+
669
+ return precon_pos_rot(reactant_geom, product_geom, **kwargs)