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,318 @@
1
+ from dataclasses import dataclass
2
+ import itertools as it
3
+ import pickle
4
+ from typing import Dict, List
5
+
6
+ import numpy as np
7
+ from numpy.typing import NDArray
8
+
9
+ from pysisyphus.Geometry import Geometry
10
+ from pysisyphus.io.pdb import parse_pdb
11
+ from pysisyphus.io.psf import parse_psf
12
+
13
+
14
+ @dataclass
15
+ class Atom:
16
+ id: int
17
+ segment: str
18
+ resid: int
19
+ resname: str
20
+ name: str
21
+ type: str
22
+ charge: float
23
+ mass: float
24
+ coords: NDArray[float]
25
+ element: str
26
+
27
+ @staticmethod
28
+ def from_psf_line(line, coords, element):
29
+ return Atom(
30
+ id=line["id"],
31
+ segment=line["segment"],
32
+ resid=line["resid"],
33
+ resname=line["resname"],
34
+ name=line["atom_name"],
35
+ type=line["atom_type"],
36
+ charge=line["charge"],
37
+ mass=line["mass"],
38
+ coords=coords,
39
+ element=element,
40
+ )
41
+
42
+
43
+ @dataclass
44
+ class Residue:
45
+ id: int
46
+ name: str
47
+ segment: str
48
+ atoms: List[Atom]
49
+
50
+ @staticmethod
51
+ def from_psf_lines(lines, coords3d, elements):
52
+ assert len(lines) == len(coords3d) == len(elements)
53
+ atoms = [
54
+ Atom.from_psf_line(line, coords, element)
55
+ for line, coords, element in zip(lines, coords3d, elements)
56
+ ]
57
+ atom0 = atoms[0]
58
+ resid0 = atom0.resid
59
+ resname0 = atom0.resname
60
+ segment0 = atom0.segment
61
+ if len(lines) > 1:
62
+ resids, resnames = zip(*[(atom.resid, atom.resname) for atom in atoms[1:]])
63
+ assert all([resname == resname0 for resname in resnames])
64
+ assert all([resid == resid0 for resid in resids])
65
+ return Residue(resid0, resname0, segment0, atoms)
66
+
67
+ @property
68
+ def key(self):
69
+ return self.segment, self.id
70
+
71
+ @property
72
+ def charge(self):
73
+ charge = sum([atom.charge for atom in self.atoms])
74
+ # assert abs(charge % 1) <= 1e-10 # I guess charges must not be integer ...
75
+ return charge
76
+
77
+ @property
78
+ def masses(self):
79
+ return np.array([atom.mass for atom in self.atoms])
80
+
81
+ @property
82
+ def total_mass(self):
83
+ return sum(self.masses)
84
+
85
+ @property
86
+ def atom_indices(self):
87
+ return [atom.id for atom in self.atoms]
88
+
89
+ @property
90
+ def elements_coords3d(self):
91
+ elements = [atom.element for atom in self.atoms]
92
+ return elements, self.coords3d
93
+
94
+ @property
95
+ def coords3d(self):
96
+ return np.array([atom.coords for atom in self.atoms])
97
+
98
+ @property
99
+ def center_of_mass(self):
100
+ return (
101
+ 1 / self.total_mass * np.sum(self.coords3d * self.masses[:, None], axis=0)
102
+ )
103
+
104
+ @property
105
+ def com(self):
106
+ return self.center_of_mass
107
+
108
+ def __len__(self):
109
+ return len(self.atoms)
110
+
111
+ def __str__(self):
112
+ return f"{self.resname}{self.resid}"
113
+
114
+
115
+ """
116
+ @dataclass
117
+ class Residues:
118
+ residues: Dict
119
+ psf_data: Dict
120
+
121
+ def as_geom(self, with_link_atoms=True):
122
+ geom = geom_from_residues(self.residues)
123
+ atoms = geom.atoms
124
+ coords3d = geom.coords3d
125
+ bonds = np.array(self.psf_data["nbond"]["inds"], dtype=int).reshape(-1, 2)
126
+ if with_link_atoms:
127
+ link_hosts, link_atoms, link_coords3d = link_atoms_for_residues(
128
+ self.residues, bonds, coords3d, atom_map
129
+ )
130
+ atoms += link_atoms
131
+ coords3d = np.concatenate((coords3d, link_coords3d), axis=0)
132
+ geom = Geometry(atoms, coords3d)
133
+ return geom
134
+ """
135
+
136
+
137
+ def residues_from_psf(psf_data, atoms, coords3d, atom_map):
138
+ psf_atoms = psf_data["atoms"]
139
+ res_key = lambda atom: (atom["segment"], atom["resid"])
140
+ psf_atoms = sorted(psf_atoms, key=res_key)
141
+ psf_atoms_by_res = it.groupby(psf_atoms, key=res_key)
142
+ residues = dict()
143
+ for _, g in psf_atoms_by_res:
144
+ res_atoms = sorted(g, key=lambda atom: atom["id"])
145
+ atom_inds = [atom_map[atom["id"]] for atom in res_atoms]
146
+ res_coords3d = coords3d[atom_inds]
147
+ res_elements = [atoms[i] for i in atom_inds]
148
+ res = Residue.from_psf_lines(res_atoms, res_coords3d, res_elements)
149
+ residues[res.key] = res
150
+ return residues
151
+
152
+
153
+ def residues_within_dist(
154
+ residues,
155
+ within_resid,
156
+ within_dist,
157
+ kind="com",
158
+ ):
159
+ def com_within():
160
+ coms = {key: res.com for key, res in residues.items()}
161
+ ref_com = coms[within_resid]
162
+ res_ids_below_dist = [
163
+ key
164
+ for key, res in residues.items()
165
+ if np.linalg.norm(coms[res.key] - ref_com) <= within_dist
166
+ ]
167
+ return res_ids_below_dist
168
+
169
+ def atom_within():
170
+ ref_res = residues[within_resid]
171
+ ref_coords3d = ref_res.coords3d
172
+ res_ids_below_dist = list()
173
+ for key, res in residues.items():
174
+ dist_vecs = ref_coords3d[:, None, :] - res.coords3d
175
+ dists = np.linalg.norm(dist_vecs, axis=2)
176
+ if (dists <= within_dist).any():
177
+ res_ids_below_dist.append(key)
178
+ return res_ids_below_dist
179
+
180
+ if kind == "com":
181
+ within_resid = com_within()
182
+ elif kind == "atom":
183
+ within_resid = atom_within()
184
+ pass
185
+ else:
186
+ raise Exception(f"{kind=} is not supported!")
187
+
188
+ residues_within = [residues[resid] for resid in within_resid]
189
+ return residues_within
190
+
191
+
192
+ def geom_from_residues(residues):
193
+ atoms = list()
194
+ coords3d = np.zeros((sum([len(res) for res in residues]), 3))
195
+ i = 0
196
+ for res in residues:
197
+ res_elements, res_coords3d = res.elements_coords3d
198
+ len_res = len(res)
199
+ coords3d[i : i + len_res] = res_coords3d
200
+ atoms.extend(res_elements)
201
+ i += len_res
202
+ return Geometry(atoms, coords3d)
203
+
204
+
205
+ def link_atoms_for_residues(
206
+ residues, bonds, coords3d, atom_map, link_element="H", g=0.709
207
+ ):
208
+ atom_inds = list(it.chain(*[res.atom_indices for res in residues]))
209
+
210
+ bond_dict = dict()
211
+ for bond in bonds:
212
+ from_, to_ = bond
213
+ bond_dict.setdefault(from_, set()).add(to_)
214
+ bond_dict.setdefault(to_, set()).add(from_)
215
+ atom_set = set(atom_inds)
216
+
217
+ cut_bonds = list()
218
+ # Check all bonds from residue-atoms. Determine which bonds are cut.
219
+ for atom in atom_inds:
220
+ try:
221
+ cut_bonds_with = bond_dict[atom] - atom_set
222
+ # Single ions/atoms may not have any bonds.
223
+ except KeyError:
224
+ cut_bonds_with = list()
225
+ for cbw in cut_bonds_with:
226
+ cut_bonds.append((atom, cbw))
227
+
228
+ link_atoms = list()
229
+ link_hosts = np.zeros(len(cut_bonds))
230
+ link_coords3d = np.zeros((len(cut_bonds), 3))
231
+ for i, cut_bond in enumerate(cut_bonds):
232
+ from_, to_ = cut_bond
233
+ link_atoms.append(link_element)
234
+ link_hosts[i] = to_
235
+ from_coords = coords3d[atom_map[from_]]
236
+ to_coords = coords3d[atom_map[to_]]
237
+ bond_vec = to_coords - from_coords
238
+ link_coords3d[i] = from_coords + g * bond_vec
239
+ link_atoms = tuple(link_atoms)
240
+ return link_hosts, link_atoms, link_coords3d
241
+
242
+
243
+ def load_psf(psf_fn):
244
+ if str(psf_fn).lower().endswith(".psf"):
245
+ psf_data = parse_psf(psf_fn)
246
+ else:
247
+ with open(psf_fn, "rb") as handle:
248
+ psf_data = pickle.load(handle)
249
+ return psf_data
250
+
251
+
252
+ def cluster_from_psf_pdb(
253
+ # psf_fn, pdb_fn, within_resid=None, within_dist=0.0, ref_residues=None, kind="atom,"
254
+ psf_data,
255
+ pdb_fn,
256
+ within_resid=None,
257
+ within_dist=0.0,
258
+ ref_residues=None,
259
+ kind="atom",
260
+ ):
261
+ atoms, coords, _, atom_map = parse_pdb(pdb_fn)
262
+ coords3d = coords.reshape(-1, 3)
263
+ print("Loaded PDB data.")
264
+
265
+ residues = residues_from_psf(psf_data, atoms, coords3d, atom_map)
266
+
267
+ # Select according to COM distance
268
+ if within_resid and within_dist:
269
+ # sel_residues = residues_within_com_dist(
270
+ sel_residues = residues_within_dist(
271
+ residues,
272
+ within_resid,
273
+ within_dist,
274
+ kind=kind,
275
+ )
276
+ # Select residues according to provided ref_residues.
277
+ elif ref_residues:
278
+ sel_residues = [residues[ref_res.key] for ref_res in ref_residues]
279
+ # Or complain!
280
+ else:
281
+ raise Exception(
282
+ "Either 'within_resid' and 'within_dist' or 'residues' must be given!"
283
+ )
284
+
285
+ geom = geom_from_residues(sel_residues)
286
+ print("Create cluster geometry.")
287
+ bonds = np.array(psf_data["nbond"]["inds"], dtype=int).reshape(-1, 2)
288
+ link_hosts, link_atoms, link_coords3d = link_atoms_for_residues(
289
+ sel_residues, bonds, coords3d, atom_map
290
+ )
291
+ sat_geom = Geometry(
292
+ geom.atoms + link_atoms, np.concatenate((geom.coords3d, link_coords3d), axis=0)
293
+ )
294
+ print("Created satured geometry with link atoms.")
295
+
296
+ # Determine backbone atoms and/or link atoms and report their indices, so they can
297
+ # be restrained in subsequent RMSD-biased optimizations. Also report the distance
298
+ # between their positions and the COM of the reference residue.
299
+ backbone_names = {"CA", "C", "O", "N"} # HN, HA not included
300
+ i = 0
301
+ backbone_inds = list()
302
+ backbone_com_dists = list()
303
+ ref_com = residues[within_resid].com
304
+ for res in sel_residues:
305
+ for atom in res.atoms:
306
+ if atom.name in backbone_names:
307
+ backbone_inds.append(i)
308
+ bb_dist = np.linalg.norm(ref_com - atom.coords)
309
+ backbone_com_dists.append(bb_dist)
310
+ print(
311
+ f"{res.name: >4s}{res.id: <5d}, {atom.element: >2s}{atom.id: <5d}, "
312
+ f"type={atom.name: >4s}, id={i: >5d}, {bb_dist: >8.4f} au"
313
+ )
314
+ i += 1
315
+ backbone_inds = np.array(backbone_inds, dtype=int)
316
+ backbone_com_dists = np.array(backbone_com_dists, dtype=float)
317
+
318
+ return sat_geom, sel_residues, backbone_inds, backbone_com_dists
@@ -0,0 +1,133 @@
1
+ import argparse
2
+ import itertools as it
3
+ import sys
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ import yaml
8
+
9
+ from pysisyphus.constants import AU2EV
10
+ from pysisyphus.wavefunction.diabatization import dq_diabatization
11
+
12
+
13
+ def make_array(nstates, components, lines):
14
+ if len(lines) == 0:
15
+ return None
16
+
17
+ arr = np.zeros((components, nstates, nstates))
18
+ expect_diag = nstates
19
+ expect_off_diag = sum(range(nstates))
20
+
21
+ for line in lines:
22
+ from_, to_, *props = line
23
+ assert (from_ >= 0) and (to_ >= 0)
24
+ assert (
25
+ len(props) == components
26
+ ), f"Expected line of length {components} but got '{line}'!"
27
+
28
+ if from_ == to_:
29
+ expect_diag -= 1
30
+ elif from_ != to_:
31
+ expect_off_diag -= 1
32
+
33
+ arr[:, from_, to_] = arr[:, to_, from_] = props
34
+ assert expect_diag == 0, "Some diagonal elements are missing!"
35
+ assert expect_off_diag == 0, "Some off-diagonal elements are missing!"
36
+ return arr
37
+
38
+
39
+ def dq_diabatization_from_run_dict(run_dict):
40
+ adia_ens = np.array(run_dict["adiabatic_energies"], dtype=float)
41
+ nstates = adia_ens.size
42
+
43
+ # Dipole moments must be present
44
+ dip_moms = make_array(nstates, 3, run_dict["dipoles"])
45
+ # Quadrupole moments and electrostatic potential are optional.
46
+ quad_moms = make_array(nstates, 1, run_dict.get("quadrupoles", list()))
47
+ epots = make_array(nstates, 1, run_dict.get("epots", list()))
48
+
49
+ kwargs = {}
50
+ if "alpha" in run_dict:
51
+ kwargs["alpha"] = run_dict["alpha"]
52
+ if "beta" in run_dict:
53
+ kwargs["beta"] = run_dict["beta"]
54
+
55
+ return dq_diabatization(
56
+ adia_ens, dip_moms, quad_moms=quad_moms, epots=epots, **kwargs
57
+ )
58
+
59
+
60
+ def diabatize_path(adia_ens, dip_moms, tr_quad_moms=None, epots=None, **kwargs):
61
+ nones = [None for _ in adia_ens]
62
+ if tr_quad_moms is None:
63
+ tr_quad_moms = nones
64
+ if epots is None:
65
+ epots = nones
66
+ assert len(adia_ens) == len(dip_moms) == len(tr_quad_moms) == len(epots)
67
+
68
+ for aens, dpm, qpm, epot in zip(adia_ens, dip_moms, tr_quad_moms, epots):
69
+ yield dq_diabatization(aens, dpm, qpm, epot, **kwargs)
70
+
71
+
72
+ def plot_dia_res(dia_res, show=False):
73
+ nstates = dia_res[0].nstates
74
+ adia_ens = np.zeros((len(dia_res), nstates))
75
+ dia_ens = np.zeros((len(dia_res), nstates))
76
+ keys = list(it.combinations(range(nstates), 2))
77
+ couplings = np.zeros((len(dia_res), len(keys)))
78
+ for i, dr in enumerate(dia_res):
79
+ adia_ens[i] = dr.adia_ens
80
+ dia_ens[i] = dr.dia_ens
81
+ for j, key in enumerate(keys):
82
+ couplings[i, j] = dr.couplings[key]
83
+
84
+ adia_min = adia_ens.min()
85
+ adia_ens -= adia_min
86
+ adia_ens *= AU2EV
87
+ dia_ens -= adia_min
88
+ dia_ens *= AU2EV
89
+ couplings *= AU2EV
90
+
91
+ fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True)
92
+ for i, state in enumerate(adia_ens.T):
93
+ ax0.plot(state, "o--", label=f"$V_{i}$")
94
+ for i, state in enumerate(dia_ens.T):
95
+ ax0.plot(state, "x-", label=f"$U_{i}$")
96
+ ax0.legend()
97
+ ax0.set_xlabel("Step")
98
+ ax0.set_ylabel(r"$\Delta E$ / eV")
99
+
100
+ # Couplings
101
+ for i, cpls in enumerate(couplings.T):
102
+ from_to = "".join([str(_) for _ in keys[i]])
103
+ ax1.plot(cpls, "o-", label=f"$|D_{{{from_to}}}|$")
104
+ ax1.axhline(0.0, ls="--", c="k")
105
+ ax1.legend()
106
+
107
+ fig.tight_layout()
108
+ if show:
109
+ plt.show()
110
+ return fig, (ax0, ax1)
111
+
112
+
113
+ def parse_args(args):
114
+ parser = argparse.ArgumentParser()
115
+ parser.add_argument("yaml")
116
+ return parser.parse_args(args)
117
+
118
+
119
+ def run():
120
+ args = parse_args(sys.argv[1:])
121
+
122
+ yaml_fn = args.yaml
123
+ with open(yaml_fn) as handle:
124
+ run_dict = yaml.load(handle, Loader=yaml.SafeLoader)
125
+ adia_labels = run_dict.pop("adiabatic_labels", None)
126
+ unit = run_dict.pop("unit", "eV")
127
+ dia_res = dq_diabatization_from_run_dict(run_dict)
128
+ report = dia_res.render_report(adia_labels=adia_labels, unit=unit)
129
+ print(report)
130
+
131
+
132
+ if __name__ == "__main__":
133
+ run()