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,504 @@
1
+ # [1] https://pubs.acs.org/doi/pdf/10.1021/j100180a030.
2
+ # Toward a Systematic Molecular Orbital Theory for Excited States
3
+ # Foresman, Head-Gordon, Pople, Frisch, 1991
4
+
5
+ import operator
6
+ from pathlib import Path
7
+ from typing import Dict, Literal, List, Optional, Tuple
8
+ import warnings
9
+
10
+ import numpy as np
11
+ from numpy.typing import NDArray
12
+
13
+ from pysisyphus.elem_data import nuc_charges_for_atoms, MASS_DICT
14
+ from pysisyphus.Geometry import Geometry
15
+ from pysisyphus.helpers_pure import file_or_str
16
+ from pysisyphus.wavefunction.helpers import BFType
17
+ from pysisyphus.wavefunction.multipole import (
18
+ get_multipole_moment,
19
+ get_transition_multipole_moment,
20
+ )
21
+ from pysisyphus.wavefunction.shells import Shells
22
+
23
+
24
+ Center = Literal["coc", "com"]
25
+
26
+
27
+ class Wavefunction:
28
+ def __init__(
29
+ self,
30
+ atoms: Tuple[str],
31
+ coords: NDArray[float],
32
+ charge: int,
33
+ mult: int,
34
+ unrestricted: bool,
35
+ occ: Tuple[int],
36
+ C: NDArray[float],
37
+ bf_type: BFType,
38
+ shells: Optional[Shells] = None,
39
+ ecp_electrons=None,
40
+ strict=True,
41
+ warn_charge=4,
42
+ ):
43
+ self.atoms = atoms
44
+ self.coords = np.array(coords).flatten()
45
+ assert 3 * len(self.atoms) == len(self.coords)
46
+
47
+ self.mult = mult
48
+ if self.mult != 1:
49
+ unrestricted = True
50
+ self.unrestricted = unrestricted
51
+ self.occ = occ
52
+ if not self.unrestricted:
53
+ assert self.occ[0] == self.occ[1]
54
+ # MOs are stored in columns
55
+ self.C = np.array(C)
56
+ # Always keep α and β coefficients separate. If we get only one set
57
+ # of MO coefficients (one square matrix with ndim == 2) we assume a
58
+ # restricted calculation and use the same set for alpha and beta electrons.
59
+ if C.ndim == 2:
60
+ self.C = np.array((self.C, self.C.copy()))
61
+ self.bf_type = bf_type
62
+ self.shells = shells
63
+ if ecp_electrons is None:
64
+ ecp_electrons = np.zeros(len(self.atoms))
65
+ elif isinstance(ecp_electrons, dict):
66
+ _ecp_electrons = np.zeros(len(self.atoms))
67
+ for k, v in ecp_electrons.items():
68
+ _ecp_electrons[k] = v
69
+ ecp_electrons = _ecp_electrons
70
+ self.ecp_electrons = np.array(ecp_electrons, dtype=int)
71
+ self.charge = charge
72
+ if abs(self.charge) > warn_charge:
73
+ warnings.warn(
74
+ f"Encountered charge={self.charge} with high absolute value!\n"
75
+ "This may happen in systems with ECPs. In such cases please set "
76
+ "'ecp_electrons' or at least the correct total charge."
77
+ )
78
+
79
+ self._masses = np.array([MASS_DICT[atom.lower()] for atom in self.atoms])
80
+ self._densities = dict()
81
+
82
+ if strict:
83
+ self.check_sanity()
84
+
85
+ def check_sanity(self):
86
+ assert self.shells is not None
87
+ S = self.S # Overlap matrix
88
+ diag_S = np.diag(S)
89
+ np.testing.assert_allclose(diag_S, np.ones_like(diag_S), atol=1e-12)
90
+ Pa_mo, Pb_mo = [
91
+ C.T @ S @ P @ S @ C for C, P in zip(self.C, self.P)
92
+ ] # Density matrices in MO basis
93
+ calc_occ_a = np.trace(Pa_mo)
94
+ calc_occ_b = np.trace(Pb_mo)
95
+ assert np.isclose((calc_occ_a, calc_occ_b), self.occ).all()
96
+
97
+ assert (
98
+ self.ecp_electrons >= 0
99
+ ).all(), "All entries in 'ecp_electrons' must be >= 0!"
100
+ # We can't use self.nuc_charges, as it already contains ecp_electrons
101
+ electrons_expected = (
102
+ nuc_charges_for_atoms(self.atoms).sum()
103
+ - self.charge # Negative charge means MORE electrons, not less!
104
+ - self.ecp_electrons.sum()
105
+ )
106
+ electrons_present = sum(self.occ)
107
+ electrons_missing = electrons_expected - electrons_present
108
+ assert electrons_missing == 0, (
109
+ f"{electrons_missing} electrons are missing! Did you forget to specify "
110
+ "'ecp_electrons' and/or the correct 'charge'?"
111
+ )
112
+
113
+ @property
114
+ def atom_num(self):
115
+ return len(self.atoms)
116
+
117
+ @property
118
+ def coords3d(self):
119
+ return self.coords.reshape(-1, 3)
120
+
121
+ @property
122
+ def masses(self):
123
+ return self._masses
124
+
125
+ @property
126
+ def nuc_charges(self):
127
+ return nuc_charges_for_atoms(self.atoms) - self.ecp_electrons
128
+
129
+ @property
130
+ def mo_num(self):
131
+ return self.C.shape[1]
132
+
133
+ @staticmethod
134
+ def from_file(fn, **kwargs):
135
+ path = Path(fn)
136
+
137
+ from_funcs = {
138
+ ".json": Wavefunction.from_orca_json,
139
+ ".fchk": Wavefunction.from_fchk,
140
+ }
141
+ from_funcs_for_str = (
142
+ # ORCA
143
+ ("Molden file created by orca_2mkl", Wavefunction.from_orca_molden),
144
+ ("[AOMix Format", Wavefunction.from_aomix),
145
+ # OpenMolcas
146
+ # ("[N_Atoms]", Wavefunction.from_molden), # seems buggy right now
147
+ )
148
+ try:
149
+ from_func = from_funcs[path.suffix.lower()]
150
+ except KeyError:
151
+ # Search for certain strings in the file
152
+ with open(fn) as handle:
153
+ text = handle.read()
154
+ for key, func in from_funcs_for_str:
155
+ if key in text:
156
+ from_func = func
157
+ break
158
+ else:
159
+ raise Exception("Could not determine file format!")
160
+ return from_func(fn, **kwargs)
161
+
162
+ @staticmethod
163
+ @file_or_str(".molden", ".molden.input")
164
+ def from_molden(text, **kwargs):
165
+ from pysisyphus.io.molden import wavefunction_from_molden
166
+
167
+ wf = wavefunction_from_molden(text, **kwargs)
168
+ return wf
169
+
170
+ @staticmethod
171
+ @file_or_str(".json")
172
+ def from_orca_json(text):
173
+ """Create wavefunction from ORCA JSON.
174
+
175
+ As of version 5.0.3 ORCA does not create JSON files for systems
176
+ containing an ECP, so this method does not take any additional
177
+ args or kwargs in contrast to from_orca_molden."""
178
+ from pysisyphus.io.orca import wavefunction_from_json
179
+
180
+ wf = wavefunction_from_json(text)
181
+ return wf
182
+
183
+ @staticmethod
184
+ @file_or_str(".molden", ".molden.input")
185
+ def from_orca_molden(text, **kwargs):
186
+ """Create wavefunction from ORCA molden file.
187
+
188
+ While ORCA refuses to create JSON files for systems containing
189
+ ECPs, this is not the case for 'orca_2mkl [fn] -molden'. So we may
190
+ encounter ECPs here. To handle this 'wavefunction_from_molden' accepts
191
+ an additional charge argument, to specify the correct charge, e.g. as
192
+ stored in an ORCA calculator. If the actual, true charge is not availble
193
+ wavefunction_from_molden will come up with an absurdly high charge.
194
+ """
195
+
196
+ from pysisyphus.io.orca import wavefunction_from_molden
197
+
198
+ wf = wavefunction_from_molden(text, **kwargs)
199
+ return wf
200
+
201
+ @staticmethod
202
+ @file_or_str(".molden", ".molden.input")
203
+ def from_fchk(text, **kwargs):
204
+ from pysisyphus.io.fchk import wavefunction_from_fchk
205
+
206
+ wf = wavefunction_from_fchk(text, **kwargs)
207
+ return wf
208
+
209
+ @staticmethod
210
+ @file_or_str(".in")
211
+ def from_aomix(text, **kwargs):
212
+ from pysisyphus.io.aomix import wavefunction_from_aomix
213
+
214
+ wf = wavefunction_from_aomix(text, **kwargs)
215
+ return wf
216
+
217
+ @property
218
+ def C_occ(self):
219
+ occ_a, occ_b = self.occ
220
+ C_a, C_b = self.C
221
+ return C_a[:, :occ_a], C_b[:, :occ_b]
222
+
223
+ @property
224
+ def C_virt(self):
225
+ occ_a, occ_b = self.occ
226
+ C_a, C_b = self.C
227
+ return C_a[:, occ_a:], C_b[:, occ_b:]
228
+
229
+ @property
230
+ def P(self):
231
+ return [C_occ @ C_occ.T for C_occ in self.C_occ]
232
+
233
+ @property
234
+ def P_tot(self):
235
+ return operator.add(*self.P)
236
+
237
+ def P_exc(self, trans_dens):
238
+ """
239
+ Eqs. (2.25) and (2.26) in [1].
240
+ """
241
+ trans_dens *= 2**0.5 / 2
242
+ occ_a, occ_b = self.occ
243
+ assert occ_a == occ_b
244
+ occ = occ_a
245
+ occupations = np.zeros(self.mo_num)
246
+ occupations[:occ_a] = 2
247
+ if self.unrestricted:
248
+ raise Exception("Fix density matrix construction!")
249
+ P = np.diag(occupations)
250
+ dP_oo = np.einsum("ia,ja->ij", trans_dens, trans_dens)
251
+ dP_vv = np.einsum("ia,ic->ac", trans_dens, trans_dens)
252
+ P[:occ, :occ] -= 2 * dP_oo
253
+ P[occ:, occ:] += 2 * dP_vv
254
+ C, _ = self.C
255
+ # The density matric is currently still in the MO basis. Transform
256
+ # it to the AO basis and return.
257
+ return C @ P @ C.T
258
+
259
+ def store_density(self, P, name, ao_or_mo="ao"):
260
+ assert P.ndim == 2, "Handling of alpha/beta densities is not yet implemented!"
261
+ if ao_or_mo == "mo":
262
+ C, _ = self.C
263
+ P_ao = C @ P @ C.T
264
+ elif ao_or_mo == "ao":
265
+ P_ao = P.copy()
266
+ self._densities[name] = P_ao
267
+
268
+ def get_density(self, name):
269
+ return self._densities[name]
270
+
271
+ def eval_density(self, coords3d, P=None):
272
+ if P is None:
273
+ P = self.P_tot
274
+ spherical = self.bf_type == BFType.PURE_SPHERICAL
275
+ vals = self.shells.eval(coords3d, spherical=spherical)
276
+ rho = np.einsum(
277
+ "uv,iu,iv->i", P, vals, vals, optimize=["einsum_path", (0, 1), (0, 1)]
278
+ )
279
+ return rho
280
+
281
+ def eval_esp(self, coords3d, with_nuc=True):
282
+ charges = np.ones(1) # Assume positive charge of 1 e
283
+ esp = np.zeros(len(coords3d))
284
+ nuc_coords3d = self.coords3d
285
+ Pa, Pb = self.P
286
+ for i, c3d in enumerate(coords3d):
287
+ V = self.get_V(c3d[None, :], charges) # 1el Coulomb integrals
288
+ el = np.einsum("uv,uv->", Pa, V)
289
+ if self.unrestricted:
290
+ el += np.einsum("uv,uv->", Pb, V)
291
+ else:
292
+ el *= 2.0
293
+ if with_nuc:
294
+ nuc = (
295
+ self.nuc_charges
296
+ / np.linalg.norm(nuc_coords3d - c3d[None, :], axis=1)
297
+ ).sum()
298
+ else:
299
+ nuc = 0.0
300
+ esp[i] = el + nuc
301
+ return esp
302
+
303
+ @property
304
+ def ao_centers(self) -> List[int]:
305
+ return list(
306
+ {
307
+ BFType.CARTESIAN: lambda: self.shells.cart_ao_centers,
308
+ BFType.PURE_SPHERICAL: lambda: self.shells.sph_ao_centers,
309
+ }[self.bf_type]()
310
+ )
311
+
312
+ @property
313
+ def ao_center_map(self) -> Dict[int, List[int]]:
314
+ ao_center_map = dict()
315
+ for i, aoc in enumerate(self.ao_centers):
316
+ ao_center_map.setdefault(aoc, list()).append(i)
317
+ return ao_center_map
318
+
319
+ def as_geom(self, **kwargs):
320
+ return Geometry(self.atoms, self.coords, **kwargs)
321
+
322
+ @property
323
+ def is_cartesian(self) -> bool:
324
+ return self.bf_type == BFType.CARTESIAN
325
+
326
+ #####################
327
+ # Overlap Integrals #
328
+ #####################
329
+
330
+ @property
331
+ def S(self):
332
+ # Check what type of basis functions we are using.
333
+ return {
334
+ BFType.CARTESIAN: lambda: self.shells.S_cart,
335
+ BFType.PURE_SPHERICAL: lambda: self.shells.S_sph,
336
+ }[self.bf_type]()
337
+
338
+ def S_with_shells(self, other_shells):
339
+ return {
340
+ BFType.CARTESIAN: lambda: self.shells.get_S_cart(other_shells),
341
+ BFType.PURE_SPHERICAL: lambda: self.shells.get_S_sph(other_shells),
342
+ }[self.bf_type]()
343
+
344
+ def S_with(self, other):
345
+ other_shells = other.shells
346
+ return self.S_with_shells(other_shells)
347
+
348
+ def S_MO_with(self, other):
349
+ assert (not self.unrestricted) and (
350
+ self.mult == 1
351
+ ), "Currently only Cα is considered!"
352
+ S_AO = self.S_with(other)
353
+ C = self.C[0]
354
+ C_other = other.C[0]
355
+ return C.T @ S_AO @ C_other
356
+
357
+ #####################
358
+ # Multipole Moments #
359
+ #####################
360
+
361
+ def get_origin(self, kind="coc"):
362
+ kind = kind.lower()
363
+ assert kind in ("com", "coc")
364
+
365
+ coords3d = self.coords.reshape(-1, 3).copy()
366
+ _factors = {
367
+ "coc": self.nuc_charges, # Center of charge
368
+ "com": self.masses, # Center of mass
369
+ }
370
+ factors = _factors[kind]
371
+ tot_factors = factors.sum()
372
+
373
+ return np.sum(coords3d * factors[:, None], axis=0) / tot_factors
374
+
375
+ def dipole_ints(
376
+ self, origin: Optional[NDArray] = None, kind: Center = "coc"
377
+ ) -> NDArray[float]:
378
+ if origin is None:
379
+ origin = self.get_origin(kind=kind)
380
+
381
+ dipole_ints = {
382
+ BFType.CARTESIAN: lambda *args: self.shells.get_dipole_ints_cart(*args),
383
+ BFType.PURE_SPHERICAL: lambda *args: self.shells.get_dipole_ints_sph(*args),
384
+ }[self.bf_type](origin)
385
+ return dipole_ints
386
+
387
+ def quadrupole_ints(
388
+ self, origin: Optional[NDArray] = None, kind: Center = "coc"
389
+ ) -> NDArray[float]:
390
+ if origin is None:
391
+ origin = self.get_origin(kind=kind)
392
+
393
+ quadrupole_ints = {
394
+ BFType.CARTESIAN: lambda *args: self.shells.get_quadrupole_ints_cart(*args),
395
+ BFType.PURE_SPHERICAL: lambda *args: self.shells.get_quadrupole_ints_sph(
396
+ *args
397
+ ),
398
+ }[self.bf_type](origin)
399
+ return quadrupole_ints
400
+
401
+ def get_dipole_moment(
402
+ self,
403
+ P: Optional[NDArray[float]] = None,
404
+ origin: Optional[NDArray[float]] = None,
405
+ kind: Center = "coc",
406
+ ) -> NDArray[float]:
407
+ if origin is None:
408
+ origin = self.get_origin(kind=kind)
409
+ if P is None:
410
+ P = self.P_tot
411
+ dipole_ints = self.dipole_ints(origin)
412
+ return get_multipole_moment(
413
+ 1, self.coords3d, origin, dipole_ints, self.nuc_charges, P
414
+ )
415
+
416
+ @property
417
+ def dipole_moment(self) -> NDArray[float]:
418
+ return self.get_dipole_moment()
419
+
420
+ def get_quadrupole_moment(
421
+ self,
422
+ P: Optional[NDArray[float]] = None,
423
+ origin: Optional[NDArray[float]] = None,
424
+ kind: Center = "coc",
425
+ ) -> NDArray[float]:
426
+ if origin is None:
427
+ origin = self.get_origin(kind=kind)
428
+ if P is None:
429
+ P = self.P_tot
430
+ quadrupole_ints = self.quadrupole_ints(origin)
431
+ return get_multipole_moment(
432
+ 2, self.coords3d, origin, quadrupole_ints, self.nuc_charges, P
433
+ )
434
+
435
+ @property
436
+ def quadrupole_moment(self) -> NDArray[float]:
437
+ return self.get_quadrupole_moment()
438
+
439
+ ################################
440
+ # Transition Multipole Moments #
441
+ ################################
442
+
443
+ def get_transition_multipole_moment(
444
+ self,
445
+ order: int,
446
+ T_a: NDArray[float],
447
+ T_b: NDArray[float] = None,
448
+ origin: Optional[NDArray[float]] = None,
449
+ kind: Center = "coc",
450
+ full=False,
451
+ ) -> NDArray[float]:
452
+ if origin is None:
453
+ origin = self.get_origin(kind=kind)
454
+ if order == 1:
455
+ multipole_ints = self.dipole_ints(origin)
456
+ elif order == 2:
457
+ multipole_ints = self.quadrupole_ints(origin)
458
+ else:
459
+ raise Exception("Multipoles of order {order} are not implemented!")
460
+ C_a, C_b = self.C
461
+ occ_a, occ_b = self.occ
462
+ return get_transition_multipole_moment(
463
+ multipole_ints,
464
+ C_a,
465
+ C_b,
466
+ T_a,
467
+ T_b,
468
+ occ_a,
469
+ occ_b,
470
+ full=full,
471
+ )
472
+
473
+ def get_transition_dipole_moment(self, *args, **kwargs):
474
+ return self.get_transition_multipole_moment(1, *args, **kwargs)
475
+
476
+ def get_transition_quadrupole_moment(self, *args, **kwargs):
477
+ return self.get_transition_multipole_moment(2, *args, **kwargs)
478
+
479
+ def oscillator_strength(
480
+ self, exc_ens: NDArray[float], trans_moms: NDArray[float]
481
+ ) -> NDArray[float]:
482
+ """Oscillator strength from TDMs and excitation energies."""
483
+ exc_ens = np.atleast_1d(exc_ens)
484
+ if trans_moms.ndim == 1:
485
+ trans_moms = trans_moms[None, :]
486
+ fosc = 2 / 3 * exc_ens * (trans_moms**2).sum(axis=1)
487
+ return fosc
488
+
489
+ #########################
490
+ # 1el Coulomb Integrals #
491
+ #########################
492
+
493
+ def get_V(self, coords3d, charges):
494
+ return {
495
+ BFType.CARTESIAN: self.shells.get_V_cart,
496
+ BFType.PURE_SPHERICAL: self.shells.get_V_sph,
497
+ }[self.bf_type](coords3d, charges)
498
+
499
+ def __str__(self):
500
+ is_restricted = "unrestricted" if self.unrestricted else "restricted"
501
+ return (
502
+ f"Wavefunction({self.atom_num} atoms, charge={self.charge}, {is_restricted}, "
503
+ f"mult={self.mult})"
504
+ )
@@ -0,0 +1,11 @@
1
+ import logging
2
+
3
+
4
+ logger = logging.getLogger("mwfn")
5
+ logger.setLevel(logging.DEBUG)
6
+ handler = logging.FileHandler("mwfn.log", mode="w", delay=True)
7
+ # fmt_str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
8
+ fmt_str = "%(asctime)s %(message)s"
9
+ formatter = logging.Formatter(fmt_str, datefmt='%Y-%m-%d %H:%M:%S')
10
+ handler.setFormatter(formatter)
11
+ logger.addHandler(handler)
@@ -0,0 +1,2 @@
1
+ class SegfaultException(Exception):
2
+ pass
@@ -0,0 +1,120 @@
1
+ import subprocess
2
+ import tempfile
3
+ from pathlib import Path
4
+
5
+ import jinja2
6
+ import numpy as np
7
+
8
+ from pysisyphus.config import get_cmd
9
+ from pysisyphus.constants import BOHR2ANG
10
+ from pysisyphus.helpers_pure import interpolate_colors
11
+
12
+
13
+ CUBE_ISO_VAL = 0.001
14
+ TPL_BASE = """
15
+ {{ orient }}
16
+
17
+ function _setModelState() {
18
+
19
+ select;
20
+ Spacefill 0.0;
21
+
22
+ frank off;
23
+ font frank 16.0 SansSerif Plain;
24
+ select *;
25
+ set fontScaling false;
26
+ background white
27
+ frank off
28
+ set showhydrogens True;
29
+
30
+ }
31
+ _setModelState;
32
+ """
33
+
34
+ CUBE_TPL = jinja2.Template(
35
+ "load {{ cube_fn }}\n"
36
+ + TPL_BASE
37
+ + """isosurface cutoff {{ isoval }} sign {{ colors }} "{{ cube_fn }}"
38
+ color isosurface translucent
39
+ {% if png_fn %}write image pngt "{{ png_fn }}"{% endif %}
40
+ """
41
+ )
42
+
43
+
44
+ def call_jmol(spt_str, show=False):
45
+ with tempfile.NamedTemporaryFile("w", suffix=".spt") as spt_handle:
46
+ spt_handle.write(spt_str)
47
+ spt_handle.flush()
48
+ jmol_cmd = [get_cmd("jmol"), "-n", spt_handle.name]
49
+ if show:
50
+ del jmol_cmd[1]
51
+ proc = subprocess.Popen(
52
+ jmol_cmd,
53
+ universal_newlines=True,
54
+ stdout=subprocess.PIPE,
55
+ stderr=subprocess.PIPE,
56
+ )
57
+ proc.wait()
58
+ stdout = proc.stdout.read()
59
+ stderr = proc.stderr.read()
60
+ return stdout, stderr
61
+
62
+
63
+ def view_cdd_cube(cdd_cube, isoval=CUBE_ISO_VAL, orient=""):
64
+ spt = CUBE_TPL.render(
65
+ orient=orient,
66
+ cube_fn=cdd_cube,
67
+ isoval=isoval,
68
+ colors="red blue",
69
+ )
70
+ with open("jmol.spt", "w") as handle:
71
+ handle.write(spt)
72
+ stdout, stderr = call_jmol(spt, show=True)
73
+
74
+
75
+ def render_cdd_cube(cdd_cube, isoval=CUBE_ISO_VAL, orient=""):
76
+ png_fn = Path(cdd_cube).with_suffix(".png")
77
+ spt = CUBE_TPL.render(
78
+ orient=orient,
79
+ cube_fn=cdd_cube,
80
+ isoval=isoval,
81
+ colors="red blue",
82
+ png_fn=png_fn,
83
+ )
84
+ with open("jmol.spt", "w") as handle:
85
+ handle.write(spt)
86
+ stdout, stderr = call_jmol(spt)
87
+ return png_fn
88
+
89
+
90
+ def render_geom_and_charges(geom, point_charges):
91
+ point_charges = point_charges.copy()
92
+ point_charges[:, :3] *= BOHR2ANG
93
+ charges = point_charges[:, -1]
94
+
95
+ cr = np.array((255, 0, 0)) # red
96
+ cw = np.array((255, 255, 255)) # white
97
+ cb = np.array((0, 0, 255)) # blue
98
+ chrg_min = charges.min()
99
+ chrg_max = charges.max()
100
+ print(
101
+ f"charges:\n{np.array2string(point_charges, precision=4)}\n"
102
+ f"min(charges): {chrg_min: .4f}\nmax(charges): {chrg_max: .4f}\n"
103
+ )
104
+ c1 = cb if chrg_min < 0.0 else cw
105
+ c2 = cr if chrg_max > 0.0 else cw
106
+ rgb_colors, _ = interpolate_colors(charges, c1, c2)
107
+
108
+ # Dump geometry to temporary file
109
+ with tempfile.NamedTemporaryFile("w", suffix=".xyz") as tmp_xyz:
110
+ tmp_xyz.write(geom.as_xyz())
111
+ tmp_xyz.flush()
112
+ spt = f"load {tmp_xyz.name};\n"
113
+ for i, ((x, y, z, pc), (r, g, b)) in enumerate(zip(point_charges, rgb_colors)):
114
+ id_ = f"chrg{i}"
115
+ spt += (
116
+ f"isosurface {id_} center {{{x} {y} {z}}} sphere 0.25;\n"
117
+ f"color ${id_} [{r} {g} {b}];\n"
118
+ )
119
+ print(f"SPT:\n\n{spt}")
120
+ call_jmol(spt, show=True)