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,218 @@
1
+ import re
2
+ import textwrap
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.calculators.Calculator import Calculator
7
+
8
+
9
+ class Psi4(Calculator):
10
+
11
+ conf_key = "psi4"
12
+
13
+ def __init__(
14
+ self,
15
+ method,
16
+ basis,
17
+ to_set=None,
18
+ to_import=None,
19
+ pcm="iefpcm",
20
+ solvent=None,
21
+ write_fchk=False,
22
+ **kwargs,
23
+ ):
24
+ super().__init__(**kwargs)
25
+
26
+ self.method = method
27
+ self.basis = basis
28
+ self.to_set = {} if to_set is None else dict(to_set)
29
+ self.to_import = [] if to_import is None else list(to_import)
30
+ self.pcm = pcm
31
+ self.solvent = solvent
32
+ self.write_fchk = write_fchk
33
+
34
+ self.inp_fn = "psi4.inp"
35
+ self.out_fn = "psi4.out"
36
+ self.to_keep = ("inp", "psi4.out", "grad.npy", "hessian.npy")
37
+
38
+ self.parser_funcs = {
39
+ "energy": self.parse_energy,
40
+ "grad": self.parse_grad,
41
+ "hessian": self.parse_hessian,
42
+ }
43
+
44
+ self.base_cmd = self.get_cmd()
45
+
46
+ self.inp = textwrap.dedent(
47
+ """
48
+ {to_import}
49
+ molecule mol{{
50
+ {xyz}
51
+ {charge} {mult}
52
+ no_reorient
53
+ no_com
54
+ symmetry c1
55
+ }}
56
+
57
+ set_num_threads({pal})
58
+ memory {mem} MB
59
+
60
+ {basis}
61
+ {to_set}
62
+ {pcm}
63
+
64
+ {method}
65
+
66
+ {fchk}
67
+ """
68
+ )
69
+
70
+ def get_fchk_str(self):
71
+ fchk_str = ""
72
+ if self.write_fchk:
73
+ fchk_fn = self.make_fn("wfn.fchk")
74
+ fchk_str = (
75
+ "fchk_writer = psi4.FCHKWriter(wfn)\n" f"fchk_writer.write('{fchk_fn}')"
76
+ )
77
+ return fchk_str
78
+
79
+ def prepare_input(self, atoms, coords, calc_type):
80
+ xyz = self.prepare_coords(atoms, coords)
81
+
82
+ calc_types = {
83
+ "energy": "E, wfn = energy('{}', return_wfn=True)",
84
+ # Right now we don't need the wavefunction
85
+ # "grad": "G, wfn = gradient('{}', return_wfn=True)\n" \
86
+ # "G_arr = np.array(G)\n" \
87
+ # "np.save('grad', G_arr)",
88
+ # "hessian": "H, wfn = hessian('{}', return_wfn=True)\n" \
89
+ # "H_arr = np.array(H)\n" \
90
+ # "np.save('hessian', H_arr)",
91
+ "grad": "G, wfn = gradient('{}', return_wfn=True)\n"
92
+ "G_arr = np.array(G)\n"
93
+ "np.save('grad', G_arr)",
94
+ "hessian": "H, wfn = hessian('{}', return_wfn=True)\n"
95
+ "H_arr = np.array(H)\n"
96
+ "np.save('hessian', H_arr)",
97
+ }
98
+ method = calc_types[calc_type].format(self.method)
99
+ wfn_path = self.make_fn("wfn.npy")
100
+ method += f"\nWavefunction.to_file(wfn, '{wfn_path}')"
101
+ method += "\nprint('PARSE ENERGY:', wfn.energy())"
102
+ set_strs = [f"set {key} {value}" for key, value in self.to_set.items()]
103
+ set_strs = "\n".join(set_strs)
104
+ import_strs = [f"import {mod}" for mod in self.to_import]
105
+ import_strs = "\n".join(import_strs)
106
+
107
+ # Basis section
108
+ basis = self.basis
109
+ # Construct more complex basis input
110
+ if isinstance(basis, dict):
111
+ # Check if a global basis is given for all atoms. This must come
112
+ # first, otherwise Psi4 throws an error.
113
+ basis_lines = [
114
+ "basis {",
115
+ ]
116
+ try:
117
+ basis_lines.append(f"assign {basis['assign']}")
118
+ except KeyError:
119
+ pass
120
+ # Add remaining lines
121
+ basis_lines.extend(
122
+ [
123
+ f"assign {atms} {bas}"
124
+ for atms, bas in basis.items()
125
+ if atms != "assign"
126
+ ]
127
+ )
128
+ basis_lines.append("}")
129
+
130
+ basis = "\n".join(basis_lines)
131
+ # Use set when self.basis is a string
132
+ else:
133
+ basis = f"set basis {basis}"
134
+
135
+ # PCM section
136
+ pcm = ""
137
+ if self.solvent:
138
+ pcm = textwrap.dedent(
139
+ f"""
140
+ set pcm true
141
+
142
+ pcm = {{
143
+ Medium {{
144
+ SolverType = {self.pcm}
145
+ Solvent = {self.solvent}
146
+ }}
147
+
148
+ Cavity {{
149
+ Type = GePol
150
+ }}
151
+ }}
152
+ """
153
+ )
154
+
155
+ inp = self.inp.format(
156
+ xyz=xyz,
157
+ charge=self.charge,
158
+ mult=self.mult,
159
+ basis=basis,
160
+ to_import=import_strs,
161
+ to_set=set_strs,
162
+ pcm=pcm,
163
+ method=method,
164
+ pal=self.pal,
165
+ mem=self.mem,
166
+ fchk=self.get_fchk_str(),
167
+ )
168
+ # inp = "\n".join([line.strip() for line in inp.split("\n")])
169
+ return inp
170
+
171
+ def get_energy(self, atoms, coords, **prepare_kwargs):
172
+ calc_type = "energy"
173
+ inp = self.prepare_input(atoms, coords, calc_type)
174
+ results = self.run(inp, calc="energy")
175
+ return results
176
+
177
+ def get_forces(self, atoms, coords, **prepare_kwargs):
178
+ calc_type = "grad"
179
+ inp = self.prepare_input(atoms, coords, calc_type)
180
+ results = self.run(inp, calc="grad")
181
+ return results
182
+
183
+ def get_hessian(self, atoms, coords, **prepare_kwargs):
184
+ calc_type = "hessian"
185
+ inp = self.prepare_input(atoms, coords, calc_type)
186
+ results = self.run(inp, calc="hessian")
187
+ return results
188
+
189
+ def run_calculation(self, atoms, coords, **prepare_kwargs):
190
+ return self.get_energy(atoms, coords)
191
+
192
+ def parse_energy(self, path):
193
+ with open(path / "psi4.out") as handle:
194
+ text = handle.read()
195
+ en_regex = re.compile(r"PARSE ENERGY: ([\d\-\.]+)")
196
+ mobj = en_regex.search(text)
197
+ result = {"energy": float(mobj[1])}
198
+ return result
199
+
200
+ def parse_grad(self, path):
201
+ gradient = np.load(path / "grad.npy")
202
+ forces = -gradient.flatten()
203
+ result = {
204
+ "forces": forces,
205
+ }
206
+ result.update(self.parse_energy(path))
207
+ return result
208
+
209
+ def parse_hessian(self, path):
210
+ hessian = np.load(path / "hessian.npy")
211
+ result = {
212
+ "hessian": hessian,
213
+ }
214
+ result.update(self.parse_energy(path))
215
+ return result
216
+
217
+ def __str__(self):
218
+ return f"Psi4({self.name})"
@@ -0,0 +1,37 @@
1
+ try:
2
+ import psi4
3
+ except ImportError:
4
+ pass
5
+ import numpy as np
6
+
7
+ from pysisyphus.calculators.Calculator import Calculator
8
+ from pysisyphus.constants import BOHR2ANG
9
+ from pysisyphus.xyzloader import make_xyz_str
10
+
11
+
12
+ class PyPsi4(Calculator):
13
+ def __init__(self, method, basis, **kwargs):
14
+ super().__init__(**kwargs)
15
+
16
+ self.method = method
17
+ self.basis = basis
18
+
19
+ self.meth_bas = f"{self.method}/{self.basis}"
20
+
21
+ psi4.core.be_quiet()
22
+ psi4.set_memory(f"{self.pal*self.mem} MB")
23
+
24
+ def get_forces(self, atoms, coords):
25
+ xyz = make_xyz_str(atoms, coords.reshape(-1, 3) * BOHR2ANG)
26
+ mol = psi4.geometry(xyz)
27
+ energy, wfn = psi4.energy(self.meth_bas, return_wfn=True)
28
+ gradient = psi4.gradient(self.meth_bas, molecule=mol, ref_wfn=wfn)
29
+
30
+ results = {
31
+ "energy": energy,
32
+ "forces": -np.asarray(gradient).flatten(),
33
+ }
34
+ return results
35
+
36
+ def __str__(self):
37
+ return f"PyPsi4({self.name})"
@@ -0,0 +1,341 @@
1
+ import os
2
+ import shutil
3
+
4
+ import numpy as np
5
+ import pyscf
6
+ from pyscf import grad, gto, lib, hessian, qmmm, tddft
7
+
8
+ from pysisyphus.calculators.OverlapCalculator import OverlapCalculator
9
+ from pysisyphus.helpers import geom_loader
10
+
11
+
12
+ class PySCF(OverlapCalculator):
13
+ conf_key = "pyscf"
14
+ drivers = {
15
+ # key: (method, unrestricted?)
16
+ ("dft", False): pyscf.dft.RKS,
17
+ ("dft", True): pyscf.dft.UKS,
18
+ ("scf", False): pyscf.scf.RHF,
19
+ ("scf", True): pyscf.scf.UHF,
20
+ ("mp2", False): pyscf.mp.MP2,
21
+ ("mp2", True): pyscf.mp.UMP2,
22
+ }
23
+ multisteps = {
24
+ "scf": ("scf",),
25
+ "dft": ("dft",),
26
+ "mp2": ("scf", "mp2"),
27
+ "tddft": ("dft", "tddft"),
28
+ "tda": ("dft", "tda"),
29
+ }
30
+ pruning_method = {
31
+ "nwchem": pyscf.dft.gen_grid.nwchem_prune,
32
+ "sg1": pyscf.dft.gen_grid.sg1_prune,
33
+ "treutler": pyscf.dft.gen_grid.treutler_prune,
34
+ "none": None,
35
+ }
36
+
37
+ def __init__(
38
+ self,
39
+ basis,
40
+ xc=None,
41
+ method="scf",
42
+ root=None,
43
+ nstates=None,
44
+ auxbasis=None,
45
+ keep_chk=True,
46
+ verbose=0,
47
+ unrestricted=None,
48
+ grid_level=3,
49
+ pruning="nwchem",
50
+ use_gpu=False,
51
+ **kwargs,
52
+ ):
53
+ super().__init__(**kwargs)
54
+
55
+ self.basis = basis
56
+ self.xc = xc
57
+ self.method = method.lower()
58
+ if self.method in ("tda", "tddft") and self.xc is None:
59
+ self.multisteps[self.method] = ("scf", self.method)
60
+ if self.xc and self.method != "tddft":
61
+ self.method = "dft"
62
+ self.root = root
63
+ self.nstates = nstates
64
+ if self.method == "tddft":
65
+ assert self.nstates, "nstates must be set with method='tddft'!"
66
+ if self.track:
67
+ assert self.root <= self.nstates, (
68
+ "'root' must be smaller " "than 'nstates'!"
69
+ )
70
+ self.auxbasis = auxbasis
71
+ self.keep_chk = keep_chk
72
+ self.verbose = int(verbose)
73
+ if unrestricted is None:
74
+ self.unrestricted = self.mult > 1
75
+ else:
76
+ self.unrestricted = unrestricted
77
+ self.grid_level = int(grid_level)
78
+ self.pruning = pruning.lower()
79
+
80
+ self.chkfile = None
81
+ self.out_fn = "pyscf.out"
82
+
83
+ self.use_gpu = use_gpu
84
+
85
+ lib.num_threads(self.pal)
86
+
87
+ @staticmethod
88
+ def geom_from_fn(fn, **kwargs):
89
+ geom = geom_loader(fn)
90
+ geom.set_calculator(PySCF(**kwargs))
91
+ return geom
92
+
93
+ def set_scf_params(self, mf):
94
+ mf.conv_tol = 1e-8
95
+ mf.max_cycle = 150
96
+
97
+ def build_grid(self, mf):
98
+ mf.grids.level = self.grid_level
99
+ mf.grids.prune = self.pruning_method[self.pruning]
100
+ mf.grids.build()
101
+
102
+ def prepare_mf(self, mf):
103
+ # Method can be overriden in a subclass to modify the mf object.
104
+ if self.use_gpu:
105
+ return mf.to_gpu()
106
+ else:
107
+ return mf
108
+
109
+ def get_driver(self, step, mol=None, mf=None):
110
+ def _get_driver():
111
+ return self.drivers[(step, self.unrestricted)]
112
+
113
+ if mol and (step == "dft"):
114
+ driver = _get_driver()
115
+ mf = driver(mol)
116
+ mf.xc = self.xc
117
+ self.set_scf_params(mf)
118
+ self.build_grid(mf)
119
+ mf = self.prepare_mf(mf)
120
+ elif mol and (step == "scf"):
121
+ driver = _get_driver()
122
+ mf = driver(mol)
123
+ self.set_scf_params(mf)
124
+ mf = self.prepare_mf(mf)
125
+ elif mf and (step == "mp2"):
126
+ mp2_mf = _get_driver()
127
+ mf = mp2_mf(mf)
128
+ elif mf and (step == "tddft"):
129
+ mf = pyscf.tddft.TDDFT(mf)
130
+ mf.nstates = self.nstates
131
+ elif mf and (step == "tda"):
132
+ mf = pyscf.tddft.TDA(mf)
133
+ mf.nstates = self.nstates
134
+ else:
135
+ raise Exception("Unknown method '{step}'!")
136
+ return mf
137
+
138
+ def prepare_mol(self, atoms, coords, build=True):
139
+ mol = gto.Mole()
140
+ mol.atom = [(atom, c) for atom, c in zip(atoms, coords.reshape(-1, 3))]
141
+ mol.basis = self.basis
142
+ mol.unit = "Bohr"
143
+ mol.charge = self.charge
144
+ mol.spin = self.mult - 1
145
+ mol.symmetry = False
146
+ mol.verbose = self.verbose
147
+ # Personally, I patched mole.py so it doesn't print
148
+ # messages regarding the output-file for verbose > QUIET.
149
+ # Just uncomment the lines after
150
+ # if self.verbose > logger.QUIET:
151
+ # ...
152
+ # in 'mole.Mole.build'. Around line 2046 for pyscf 1.6.5.
153
+ # Search for "output file" in gto/mole.py
154
+ # Search for "Large deviations found" in scf/{uhf,dhf,ghf}.py
155
+ mol.output = self.make_fn(self.out_fn)
156
+ mol.max_memory = self.mem * self.pal
157
+ if build:
158
+ mol.build(parse_arg=False)
159
+ return mol
160
+
161
+ def prepare_input(self, atoms, coords, build=True):
162
+ mol = self.prepare_mol(atoms, coords, build=build)
163
+ assert mol._built, "Please call mol.build(parse_arg=False)!"
164
+ return mol
165
+
166
+ def store_and_track(self, results, func, atoms, coords, **prepare_kwargs):
167
+ if self.track:
168
+ self.store_overlap_data(atoms, coords)
169
+ if self.track_root():
170
+ # Redo the calculation with the updated root
171
+ results = func(atoms, coords, **prepare_kwargs)
172
+ results["all_energies"] = self.parse_all_energies()
173
+ return results
174
+
175
+ def get_energy(self, atoms, coords, **prepare_kwargs):
176
+ point_charges = prepare_kwargs.get("point_charges", None)
177
+
178
+ mol = self.prepare_input(atoms, coords)
179
+ mf = self.run(mol, point_charges=point_charges)
180
+ results = {
181
+ "energy": mf.e_tot,
182
+ }
183
+ results = self.store_and_track(
184
+ results, self.get_energy, atoms, coords, **prepare_kwargs
185
+ )
186
+ return results
187
+
188
+ def get_forces(self, atoms, coords, **prepare_kwargs):
189
+ point_charges = prepare_kwargs.get("point_charges", None)
190
+
191
+ mol = self.prepare_input(atoms, coords)
192
+ mf = self.run(mol, point_charges=point_charges)
193
+ grad_driver = mf.Gradients()
194
+ if self.root:
195
+ grad_driver.state = self.root
196
+ gradient = grad_driver.kernel()
197
+ self.log("Completed gradient step")
198
+
199
+ try:
200
+ e_tot = mf._scf.e_tot
201
+ except AttributeError:
202
+ e_tot = mf.e_tot
203
+
204
+ results = {
205
+ "energy": e_tot,
206
+ "forces": -gradient.flatten(),
207
+ }
208
+ results = self.store_and_track(
209
+ results, self.get_forces, atoms, coords, **prepare_kwargs
210
+ )
211
+ return results
212
+
213
+ def get_hessian(self, atoms, coords, **prepare_kwargs):
214
+ point_charges = prepare_kwargs.get("point_charges", None)
215
+
216
+ mol = self.prepare_input(atoms, coords)
217
+ mf = self.run(mol, point_charges=point_charges)
218
+ H = mf.Hessian().kernel()
219
+
220
+ # The returned hessian is 4d ... ok. This probably serves a purpose
221
+ # that I don't understand. We transform H to a nice, simple 2d array.
222
+ H = np.hstack(np.concatenate(H, axis=1))
223
+ results = {
224
+ "energy": mf.e_tot,
225
+ "hessian": H,
226
+ }
227
+ # results = self.store_and_track(
228
+ # results, self.get_hessian, atoms, coords, **prepare_kwargs
229
+ # )
230
+ return results
231
+
232
+ def run_calculation(self, atoms, coords, **prepare_kwargs):
233
+ return self.get_energy(atoms, coords, **prepare_kwargs)
234
+
235
+ def run(self, mol, point_charges=None):
236
+ steps = self.multisteps[self.method]
237
+ self.log(f"Running steps '{steps}' for method {self.method}")
238
+ for i, step in enumerate(steps):
239
+ if i == 0:
240
+ mf = self.get_driver(step, mol=mol)
241
+ assert step in ("scf", "dft")
242
+ if self.chkfile:
243
+ # Copy old chkfile to new chkfile
244
+ new_chkfile = self.make_fn("chkfile", return_str=True)
245
+ shutil.copy(self.chkfile, new_chkfile)
246
+ self.chkfile = new_chkfile
247
+ mf.chkfile = self.chkfile
248
+ mf.init_guess = "chkfile"
249
+ self.log(
250
+ f"Using '{self.chkfile}' as initial guess for {step} calculation."
251
+ )
252
+ if self.auxbasis:
253
+ mf = mf.density_fit(auxbasis=self.auxbasis)
254
+ self.log(f"Using density fitting with auxbasis {self.auxbasis}.")
255
+
256
+ if point_charges is not None:
257
+ mf = qmmm.mm_charge(mf, point_charges[:, :3], point_charges[:, 3])
258
+ self.log(
259
+ f"Added {len(point_charges)} point charges with "
260
+ f"sum(q)={sum(point_charges[:,3]):.4f}."
261
+ )
262
+ else:
263
+ mf = self.get_driver(step, mf=prev_mf) # noqa: F821
264
+
265
+ if self.keep_chk and (self.chkfile is None) and (step in ("dft", "scf")):
266
+ self.chkfile = self.make_fn("chkfile", return_str=True)
267
+ try:
268
+ os.remove(self.chkfile)
269
+ except FileNotFoundError:
270
+ self.log(f"Tried to remove '{self.chkfile}'. It doesn't exist.")
271
+ self.log(f"Created chkfile '{self.chkfile}'")
272
+ mf.chkfile = self.chkfile
273
+ mf.kernel()
274
+ self.log(f"Completed {step} step")
275
+ prev_mf = mf
276
+
277
+ # Keep mf and dump mol
278
+ # save_mol(mol, self.make_fn("mol.chk"))
279
+ self.mf = mf.reset() # release integrals and other temporary intermediates.
280
+ self.calc_counter += 1
281
+
282
+ return mf
283
+
284
+ def parse_all_energies(self, exc_mf=None):
285
+ if exc_mf is None:
286
+ exc_mf = self.mf
287
+
288
+ try:
289
+ gs_energy = exc_mf._scf.e_tot
290
+ exc_energies = exc_mf.e_tot
291
+ all_energies = np.zeros(exc_energies.size + 1)
292
+ all_energies[0] = gs_energy
293
+ all_energies[1:] = exc_energies
294
+ except AttributeError:
295
+ gs_energy = exc_mf.e_tot
296
+ all_energies = np.array((gs_energy,))
297
+
298
+ return all_energies
299
+
300
+ def prepare_overlap_data(self, path):
301
+ gs_mf = self.mf._scf
302
+ exc_mf = self.mf
303
+
304
+ C = gs_mf.mo_coeff
305
+
306
+ first_Y = exc_mf.xy[0][1]
307
+ # In TDA calculations Y is just the integer 0.
308
+ if isinstance(first_Y, int) and (first_Y == 0):
309
+ X = np.array([state[0] for state in exc_mf.xy])
310
+ Y = np.zeros_like(X)
311
+ # In TD-DFT calculations the Y vectors is also present
312
+ else:
313
+ # Shape = (nstates, 2 (X,Y), occ, virt)
314
+ ci_coeffs = np.array(exc_mf.xy)
315
+ X = ci_coeffs[:, 0]
316
+ Y = ci_coeffs[:, 1]
317
+
318
+ all_energies = self.parse_all_energies(exc_mf)
319
+ return C, X, Y, all_energies
320
+
321
+ def parse_charges(self):
322
+ results = self.mf.analyze(with_meta_lowdin=False)
323
+ # Mulliken charges
324
+ charges = results[0][1]
325
+ return charges
326
+
327
+ def get_chkfiles(self):
328
+ return {
329
+ "chkfile": self.chkfile,
330
+ }
331
+
332
+ def set_chkfiles(self, chkfiles):
333
+ try:
334
+ chkfile = chkfiles["chkfile"]
335
+ self.chkfile = chkfile
336
+ self.log(f"Set chkfile '{chkfile}' as chkfile.")
337
+ except KeyError:
338
+ self.log("Found no chkfile information in chkfiles!")
339
+
340
+ def __str__(self):
341
+ return f"PySCF({self.name})"
@@ -0,0 +1,73 @@
1
+ import numpy as np
2
+ try:
3
+ from xtb.interface import Environment, Param, Calculator as XTBCalculator
4
+ from xtb.libxtb import VERBOSITY_MINIMAL, VERBOSITY_FULL, VERBOSITY_MUTED
5
+ except ModuleNotFoundError:
6
+ can_pyxtb = False
7
+
8
+ from pysisyphus.calculators.Calculator import Calculator
9
+ from pysisyphus.elem_data import ATOMIC_NUMBERS
10
+
11
+
12
+ class PyXTB(Calculator):
13
+
14
+ def __init__(self, *args, gfn=2, acc=None, verbosity=0, keep_calculator=False, **kwargs):
15
+ super().__init__(*args, **kwargs)
16
+
17
+ self.env = Environment()
18
+ self.gfn = str(gfn)
19
+ self.acc = acc
20
+ avail_verbosities = {
21
+ 0: VERBOSITY_MUTED,
22
+ 1: VERBOSITY_MINIMAL,
23
+ 2: VERBOSITY_FULL,
24
+ }
25
+ self.verbosity = avail_verbosities[verbosity]
26
+ avail_params = {
27
+ "0": Param.GFN0xTB,
28
+ "1": Param.GFN1xTB,
29
+ "2": Param.GFN2xTB,
30
+ "ff": Param.GFNFF,
31
+ }
32
+ self.keep_calculator = keep_calculator
33
+ self._calculator = None
34
+
35
+ self.param = avail_params[self.gfn]
36
+ self.uhf = self.mult - 1
37
+
38
+ def get_calculator(self, atoms, coords):
39
+ # Reuse old calculator and updatec coordinates
40
+ if self._calculator:
41
+ self._calculator.update(coords.reshape(-1, 3))
42
+ return self._calculator
43
+
44
+ # Create new calculator
45
+ numbers = np.array([ATOMIC_NUMBERS[atom.lower()] for atom in atoms])
46
+ calc = XTBCalculator(
47
+ self.param, numbers, coords.reshape(-1, 3), charge=self.charge, uhf=self.uhf
48
+ )
49
+ calc.set_verbosity(self.verbosity)
50
+ if self.acc:
51
+ calc.set_accuracy(self.acc)
52
+
53
+ # Keep calculator, if requested
54
+ if self.keep_calculator and (self._calculator is None):
55
+ self._calculator = calc
56
+ return calc
57
+
58
+ def get_energy(self, atoms, coords, **prepare_kwargs):
59
+ calc = self.get_calculator(atoms, coords)
60
+ xtb_result = calc.singlepoint(copy=True)
61
+ results = {
62
+ "energy": xtb_result.get_energy(),
63
+ }
64
+ return results
65
+
66
+ def get_forces(self, atoms, coords, **prepare_kwargs):
67
+ calc = self.get_calculator(atoms, coords)
68
+ xtb_result = calc.singlepoint(copy=True)
69
+ results = {
70
+ "energy": xtb_result.get_energy(),
71
+ "forces": -xtb_result.get_gradient().flatten(),
72
+ }
73
+ return results