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,76 @@
1
+ # [1] http://dx.doi.org/10.1021/acs.jctc.8b00885
2
+ # Exploring Potential Energy Surface with External Forces
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.calculators.Calculator import Calculator
7
+
8
+
9
+ class EGO(Calculator):
10
+ def __init__(
11
+ self,
12
+ calculator,
13
+ ref_geom,
14
+ max_force=0.175,
15
+ **kwargs,
16
+ ):
17
+ super().__init__(**kwargs)
18
+
19
+ self.calculator = calculator
20
+ self.ref_geom = ref_geom
21
+ self.max_force = max_force
22
+ assert (
23
+ self.max_force > 0.0
24
+ ), f"Maximum force must be positve bug to max_force={self.max_force:.4f} au"
25
+
26
+ self._ref_hessian = None
27
+ self._s = None
28
+
29
+ @property
30
+ def ref_hessian(self):
31
+ if self._ref_hessian is None:
32
+ geom = self.ref_geom
33
+ results = self.calculator.get_hessian(geom.atoms, geom.cart_coords)
34
+ self._ref_hessian = results["hessian"]
35
+ Hr0 = self._ref_hessian @ self.ref_geom.cart_coords[:, None]
36
+ self._s = self.max_force / np.abs(Hr0).max()
37
+ self.log(f"Set EGO s={self._s:.6f}")
38
+ return self._ref_hessian
39
+
40
+ @property
41
+ def s(self):
42
+ return self._s
43
+
44
+ def get_mods(self, atoms, coords):
45
+ assert atoms == self.ref_geom.atoms
46
+ Hr = self.ref_hessian @ coords[:, None]
47
+ s = self.s
48
+ energy_mod = float(coords[None, :] @ Hr)
49
+ forces_mod = -s * Hr.flatten()
50
+ return energy_mod, forces_mod
51
+
52
+ def get_energy(self, atoms, coords, **prepare_kwargs):
53
+ true_energy = self.calculator.get_energy(atoms, coords)["energy"]
54
+ energy_mod, _ = self.get_mods(atoms, coords)
55
+
56
+ results = {
57
+ "energy": true_energy + energy_mod,
58
+ "true_energy": true_energy,
59
+ }
60
+ self.calc_counter += 1
61
+ return results
62
+
63
+ def get_forces(self, atoms, coords, **prepare_kwargs):
64
+ true_results = self.calculator.get_forces(atoms, coords, **prepare_kwargs)
65
+ true_energy = true_results["energy"]
66
+ true_forces = true_results["forces"]
67
+ energy_mod, forces_mod = self.get_mods(atoms, coords)
68
+
69
+ results = {
70
+ "energy": true_energy + energy_mod,
71
+ "forces": true_forces + forces_mod,
72
+ "true_forces": true_forces,
73
+ "true_energy": true_energy,
74
+ }
75
+ self.calc_counter += 1
76
+ return results
@@ -0,0 +1,224 @@
1
+ # [1] https://doi.org/10.1063/5.0021923
2
+ # Extending NEB method to reaction pathways involving multiple spin states
3
+ # Zhao et al, 2020
4
+ # [2] https://doi.org/10.1021/jp0761618
5
+ # Optimizing Conical Intersections without Derivative Coupling Vectors:
6
+ # Application to Multistate Multireference Second-Order Perturbation Theory
7
+ # Levine, Coe, Martinez 2008
8
+
9
+ import numpy as np
10
+
11
+ from pysisyphus.calculators.Calculator import Calculator
12
+ from pysisyphus.constants import AU2KJPERMOL
13
+ from pysisyphus.helpers import norm_max_rms
14
+
15
+
16
+ class EnergyMin(Calculator):
17
+ def __init__(
18
+ self,
19
+ calculator1: Calculator,
20
+ calculator2: Calculator,
21
+ mix: bool = False,
22
+ alpha: float = 0.02, # Hartree
23
+ sigma: float = 3.5, # Unitless; default for ethene case in [1]
24
+ min_energy_diff: float = 0.0,
25
+ check_after: int = 0,
26
+ **kwargs,
27
+ ):
28
+ """
29
+ Use energy and derivatives of the calculator with lower energy.
30
+
31
+ This calculators carries out two calculations with different settings
32
+ and returns the results of the lower energy one. This can be used
33
+ to consider flips between a singlet and a triplet PES etc.
34
+
35
+ Parameters
36
+ ----------
37
+ calculator1
38
+ Wrapped QC calculator that provides energies and its derivatives.
39
+ calculator2
40
+ Wrapped QC calculator that provides energies and its derivatives.
41
+ mix
42
+ Enable mixing of both forces, according to the approach outlined
43
+ in [2]. Can be used to optimize guesses for MECPs.
44
+ Pass
45
+ alpha
46
+ Smoothing parameter in Hartree. See [2] for a discussion.
47
+ sigma
48
+ Unitless gap size parameter. The final gap becomes
49
+ smaller for bigga sigmas. Has to be adapted for each case. See
50
+ [2] for a discussion (p. 407 right column and p. 408 left column.)
51
+ min_energy_diff
52
+ Energy difference in Hartree. When set to a value != 0 and the
53
+ energy difference between both
54
+ calculators drops below this value, execution of both calculations
55
+ is diabled for 'check_after' cycles. In these cycles the calculator choice
56
+ remains fixed. After 'check_after' cycles, both energies
57
+ will be calculated and it is checked, if the previous calculator
58
+ choice remains valid.
59
+ In conjunction with 'check_after' both arguments can be used to
60
+ save computational ressources.
61
+ check_after
62
+ Amount of cycles in which the calculator choice remains fixed.
63
+
64
+ Other Parameters
65
+ ----------------
66
+ **kwargs
67
+ Keyword arguments passed to the Calculator baseclass.
68
+ """
69
+ super().__init__(**kwargs)
70
+ self.calc1 = calculator1
71
+ self.calc2 = calculator2
72
+ self.alpha = alpha
73
+ self.sigma = sigma
74
+ self.min_energy_diff = float(min_energy_diff)
75
+ self.check_after = int(check_after)
76
+ assert self.check_after >= 0, "'check_after' must not be negative!"
77
+
78
+ self.mix = mix
79
+ self.recalc_in = self.check_after
80
+ self.fixed_calc = None
81
+
82
+ def do_calculations(self, name, atoms, coords, **prepare_kwargs):
83
+ def run_calculation(calc, name=name):
84
+ results = getattr(calc, name)(atoms, coords, **prepare_kwargs)
85
+ return results
86
+
87
+ if (self.fixed_calc is not None) and self.recalc_in > 0:
88
+ self.log(
89
+ f"Used fixed calculator '{self.fixed_calc}'. Re-checking both "
90
+ f"calculators in {self.recalc_in} cycles."
91
+ )
92
+ results = run_calculation(self.fixed_calc)
93
+ self.recalc_in -= 1
94
+ self.calc_counter += 1
95
+ return results
96
+ elif (self.fixed_calc is not None) and self.recalc_in == 0:
97
+ self.log(f"Unset fixed calculator {self.calc1}.")
98
+ self.fixed_calc = None
99
+
100
+ # Avoid unnecessary costly Hessian calculations; decide which Hessian
101
+ # to calculate from previous energy calculation.
102
+ if name == "get_hessian":
103
+ tmp_energy1 = run_calculation(self.calc1, "get_energy")["energy"]
104
+ tmp_energy2 = run_calculation(self.calc2, "get_energy")["energy"]
105
+ if tmp_energy1 <= tmp_energy2:
106
+ results1 = run_calculation(self.calc1)
107
+ results2 = {"energy": tmp_energy2}
108
+ self.log("Calculated Hessian for calc1, skipped it for calc2.")
109
+ else:
110
+ results1 = {"energy": tmp_energy1}
111
+ results2 = run_calculation(self.calc2)
112
+ self.log("Calculated Hessian for calc2, skipped it for calc1.")
113
+ # Do both full calculation otherwise
114
+ else:
115
+ results1 = run_calculation(self.calc1, name)
116
+ results2 = run_calculation(self.calc2, name)
117
+ energy1 = results1["energy"]
118
+ energy2 = results2["energy"]
119
+ all_energies = np.array((energy1, energy2))
120
+
121
+ # Mixed forces to optimize crossing points
122
+ if self.mix:
123
+ # Must be positive, so substract lower energy from higher energy.
124
+ # I is the higher state, j the lower one.
125
+ en_i, en_j = (
126
+ (energy2, energy1) if (energy1 < energy2) else (energy1, energy2)
127
+ )
128
+ energy_diff = en_i - en_j
129
+ energy_diff_kJ = energy_diff * AU2KJPERMOL
130
+ assert energy_diff > 0.0
131
+ self.log(
132
+ f"Mix mode, ΔE={energy_diff:.6f} au ({energy_diff_kJ:.2f} kJ mol⁻¹)"
133
+ )
134
+ energy_diff_sq = energy_diff**2
135
+ denom = energy_diff + self.alpha
136
+ energy = (en_i + en_j) / 2 + self.sigma * energy_diff_sq / denom
137
+ results = {
138
+ "energy": energy,
139
+ "all_energies": all_energies,
140
+ }
141
+ self.log(f"Mixed energy: {energy:.6f} au")
142
+ if name == "get_forces":
143
+ forces1 = results1["forces"]
144
+ forces2 = results2["forces"]
145
+ forces_i, forces_j = (
146
+ (forces2, forces1) if (energy1 < energy2) else (forces1, forces2)
147
+ )
148
+ # There seems to be a typo in Eq. (8) in [1]; the final term
149
+ # should be (dV_J - dV_I) instead of the (dV_I - dV_J).
150
+ # The formula is correct though, in the original publication
151
+ # (Eq. (7) in [2]).
152
+ forces = (forces_i + forces_j) / 2 + self.sigma * (
153
+ energy_diff_sq + 2 * self.alpha * energy_diff
154
+ ) / denom**2 * (forces_i - forces_j)
155
+ results["forces"] = forces
156
+ for key, forces in (
157
+ ("mixed forces", forces),
158
+ ("forces1", forces1),
159
+ ("forces2", forces2),
160
+ ):
161
+ norm, max_, rms_ = norm_max_rms(forces)
162
+ self.log(
163
+ f"{key: >14s}: (norm={norm:.4f}, max(|{key: >14s}|)={max_:.4f}, "
164
+ f"rms={rms_:.4f}) au a0⁻¹"
165
+ )
166
+ self.calc_counter += 1
167
+ return results
168
+ # Mixed forces end
169
+
170
+ min_ind = [1, 0][int(energy1 < energy2)]
171
+ en1_or_en2 = ("calc1", "calc2")[min_ind]
172
+ energy_diff = energy1 - energy2
173
+ # Try to fix calculator, if requested
174
+ if (self.min_energy_diff and self.check_after) and (
175
+ # When the actual difference is above to minimum differences
176
+ # or
177
+ # no calculator is fixed yet
178
+ (energy_diff > self.min_energy_diff)
179
+ or (self.fixed_calc is None)
180
+ ):
181
+ self.fixed_calc = (self.calc1, self.calc2)[min_ind]
182
+ self.recalc_in = self.check_after
183
+ self.log(
184
+ f"Fixed calculator choice ({en1_or_en2}) for {self.recalc_in} cycles."
185
+ )
186
+ results = (results1, results2)[min_ind]
187
+ results["all_energies"] = all_energies
188
+ energy_diff_kJ = abs(energy_diff) * AU2KJPERMOL
189
+
190
+ self.log(
191
+ f"energy_calc1={energy1:.6f} au, energy_calc2={energy2:.6f} au, returning "
192
+ f"results for {en1_or_en2}, {energy_diff_kJ: >10.2f} kJ mol⁻¹ lower."
193
+ )
194
+ self.calc_counter += 1
195
+ return results
196
+
197
+ def get_energy(self, atoms, coords, **prepare_kwargs):
198
+ return self.do_calculations("get_energy", atoms, coords, **prepare_kwargs)
199
+
200
+ def get_forces(self, atoms, coords, **prepare_kwargs):
201
+ return self.do_calculations("get_forces", atoms, coords, **prepare_kwargs)
202
+
203
+ def get_hessian(self, atoms, coords, **prepare_kwargs):
204
+ return self.do_calculations("get_hessian", atoms, coords, **prepare_kwargs)
205
+
206
+ def get_chkfiles(self) -> dict:
207
+ chkfiles = {}
208
+ for key in ("calc1", "calc2"):
209
+ try:
210
+ chkfiles[key] = getattr(self, key).get_chkfiles()
211
+ except AttributeError:
212
+ pass
213
+ return chkfiles
214
+
215
+ def set_chkfiles(self, chkfiles: dict):
216
+ for key in ("calc1", "calc2"):
217
+ try:
218
+ getattr(self, key).set_chkfiles(chkfiles[key])
219
+ msg = f"Set chkfile on '{key}'"
220
+ except KeyError:
221
+ msg = f"Found no information for '{key}' in chkfiles!"
222
+ except AttributeError:
223
+ msg = f"Setting chkfiles is not supported by '{key}'"
224
+ self.log(msg)
@@ -0,0 +1,264 @@
1
+ from math import pi
2
+ from typing import Optional
3
+
4
+ import numpy as np
5
+ from numpy.typing import ArrayLike
6
+
7
+ from pysisyphus.calculators.Calculator import Calculator
8
+ from pysisyphus.constants import KB, AU2J
9
+ from pysisyphus.Geometry import Geometry
10
+ from pysisyphus.intcoords.PrimTypes import prims_from_prim_inputs
11
+ from pysisyphus.intcoords.update import correct_dihedrals
12
+ from pysisyphus.intcoords import Torsion
13
+ from pysisyphus.linalg import rmsd_grad
14
+ from pysisyphus.calculators.DFTD3 import DFTD3
15
+
16
+ class LogFermi:
17
+ def __init__(self, beta, radius, T=300, origin=(0.0, 0.0, 0.0), geom=None):
18
+ """As described in the XTB docs.
19
+
20
+ https://xtb-docs.readthedocs.io/en/latest/xcontrol.html#confining-in-a-cavity
21
+ """
22
+ self.beta = beta
23
+ self.radius = radius
24
+ self.T = T
25
+ self.origin = np.array(origin)
26
+
27
+ # In Hartree
28
+ self.kT = KB * self.T / AU2J
29
+
30
+ def calc(self, coords3d, gradient=False):
31
+ t0 = coords3d - self.origin[None, :]
32
+ t1 = np.linalg.norm(t0, axis=1)
33
+ t2 = np.exp(self.beta * (t1 - self.radius))
34
+
35
+ energy = (self.kT * np.log(1 + t2)).sum()
36
+ if not gradient:
37
+ return energy
38
+
39
+ grad = self.kT * ((self.beta * t2) / ((1 + t2) * t1))[:, None] * t0
40
+ return energy, grad.flatten()
41
+
42
+ def __repr__(self):
43
+ return (
44
+ f"LogFermi(beta={self.beta:.6f}, radius={self.radius:.6f}, "
45
+ f"T={self.T:.6f}, origin={self.origin})"
46
+ )
47
+
48
+
49
+ class HarmonicSphere:
50
+ def __init__(self, k, radius, origin=(0.0, 0.0, 0.0), geom=None):
51
+ self.k = k
52
+ self.radius = radius
53
+ self.origin = np.array(origin)
54
+
55
+ def calc(self, coords3d, gradient=False):
56
+ c3d_wrt_origin = coords3d - self.origin
57
+ distances = np.linalg.norm(c3d_wrt_origin, axis=1)
58
+ energies = np.where(distances > self.radius, self.k * distances**2, 0.0)
59
+ energy = energies.sum()
60
+
61
+ if not gradient:
62
+ return energy
63
+
64
+ """
65
+ E(r(x)) = k*r**2
66
+ dE(r(x))/dx = dE/dr * dr/dx
67
+ dE/dr = 2*k*r
68
+ dr/dx = x/r
69
+ dE/dr * dr/dx = 2*k*x
70
+ """
71
+ grad = np.where(distances > self.radius, 2 * self.k * c3d_wrt_origin, 0.0)
72
+
73
+ return energy, grad.flatten()
74
+
75
+ @property
76
+ def surface_area(self):
77
+ """In Bohr**2"""
78
+ return 4 * pi * self.radius**2
79
+
80
+ def instant_pressure(self, coords3d):
81
+ _, gradient = self.calc(coords3d, gradient=True)
82
+ norm = np.linalg.norm(gradient)
83
+ p = norm / self.surface_area
84
+ return p
85
+
86
+
87
+ class Restraint:
88
+ def __init__(self, restraints, geom=None):
89
+ self.restraints = list()
90
+
91
+ for prim_inp, *rest in restraints:
92
+ prims = prims_from_prim_inputs((prim_inp,))
93
+ assert len(prims) == 1
94
+ prim = prims[0]
95
+ force_const = rest.pop(0)
96
+
97
+ try:
98
+ ref_val = rest.pop(0)
99
+ except IndexError:
100
+ assert (
101
+ geom is not None
102
+ ), "Need initial coordinates when no reference value is specified!"
103
+ ref_val = prim.calculate(geom.coords3d)
104
+
105
+ self.restraints.append((prim, force_const, ref_val))
106
+
107
+ @staticmethod
108
+ def calc_prim_restraint(prim, coords3d, force_const, ref_val):
109
+ val, grad = prim.calculate(coords3d, gradient=True)
110
+ if isinstance(prim, Torsion):
111
+ # correct_dihedrals always returns a 1d array, even for scalar inputs
112
+ val = correct_dihedrals(val, ref_val)[0]
113
+ diff = val - ref_val
114
+ pot = force_const * diff**2
115
+ pot_grad = 2 * force_const * diff * grad
116
+ return pot, pot_grad
117
+
118
+ def calc(self, coords3d, gradient=False):
119
+ energy = 0.0
120
+ grad = np.zeros(coords3d.size)
121
+
122
+ for prim, force_const, ref_val in self.restraints:
123
+ penergy, pgrad = self.calc_prim_restraint(
124
+ prim, coords3d, force_const, ref_val
125
+ )
126
+ energy += penergy
127
+ grad += pgrad
128
+
129
+ if not gradient:
130
+ return energy
131
+
132
+ return energy, grad.flatten()
133
+
134
+
135
+ class RMSD:
136
+ def __init__(
137
+ self,
138
+ geom: Geometry,
139
+ k: float,
140
+ beta: float = 0.5,
141
+ atom_indices: Optional[ArrayLike] = None,
142
+ ):
143
+ """Restrain based on RMSD with a reference geometry.
144
+
145
+ As described in https://doi.org/10.1021/acs.jctc.0c01306, Eq. (5).
146
+
147
+ Parameters
148
+ ----------
149
+
150
+ geom:
151
+ Reference geometry for RMSD calculation.
152
+ k:
153
+ Gaussian height in units of energy. Should be a negative number if the system
154
+ under study should stay close to the reference geometry (pulling k).
155
+ A positive Gaussian height k results in forces that push the system under study
156
+ away from the reference geometry (pushing k).
157
+ b:
158
+ Gaussian width in inverse units of lengths.
159
+ atom_indices
160
+ Optional, numpy array or iterable of integer atom indices. Restricts the RMSD
161
+ calculation to these atoms. If omitted, all atoms are used.
162
+ """
163
+
164
+ self.k = k
165
+ self.beta = beta
166
+ natoms = len(geom.atoms)
167
+ if atom_indices is None:
168
+ atom_indices = np.arange(natoms)
169
+ self.atom_indices = np.array(atom_indices, dtype=int)
170
+ assert (self.atom_indices.min() >= 0) and (
171
+ self.atom_indices.max() <= (natoms - 1)
172
+ ), "Got atom_indices outside the valid range!"
173
+ self.ref_coords3d = geom.coords3d.copy()
174
+ # print("Using {self.atom_indices.size} of {natoms} atoms for RMSD calculations.")
175
+
176
+ def calc(self, coords3d, gradient=False):
177
+ rmsd, grad_ = rmsd_grad(
178
+ coords3d[self.atom_indices], self.ref_coords3d[self.atom_indices]
179
+ )
180
+
181
+ k = self.k
182
+ beta = self.beta
183
+ energy = k * np.exp(-beta * rmsd**2)
184
+
185
+ if not gradient:
186
+ return energy
187
+
188
+ grad = np.zeros_like(self.ref_coords3d)
189
+ grad[self.atom_indices] = -beta * 2 * grad_ * energy
190
+ return energy, grad.flatten()
191
+
192
+ def __repr__(self):
193
+ return f"RMSD(k={self.k:.4f}, beta={self.beta:.6f}, {self.atom_indices.size} atoms)"
194
+
195
+
196
+ class ExternalPotential(Calculator):
197
+
198
+ available_potentials = {
199
+ "logfermi": LogFermi,
200
+ "harmonic_sphere": HarmonicSphere,
201
+ "restraint": Restraint,
202
+ "rmsd": RMSD,
203
+ "d3": DFTD3,
204
+ }
205
+
206
+ def __init__(self, calculator=None, potentials=None, geom=None, **kwargs):
207
+ super().__init__(**kwargs)
208
+
209
+ self.calculator = calculator
210
+
211
+ self.potentials = list()
212
+ self.log("Creating external potentials")
213
+ for i, pot_kwargs in enumerate(potentials):
214
+ pot_kwargs.update({"geom": geom})
215
+ pot_key = pot_kwargs.pop("type")
216
+ pot_cls = self.available_potentials[pot_key]
217
+ pot = pot_cls(**pot_kwargs)
218
+ self.potentials.append(pot)
219
+ self.log(f"\t{i:02d}: {pot}")
220
+
221
+ def get_potential_energy(self, coords):
222
+ coords3d = coords.reshape(-1, 3)
223
+ potential_energies = [pot.calc(coords3d) for pot in self.potentials]
224
+ potential_energy = sum(potential_energies)
225
+ self.log(f"Energies from external potential: {potential_energies}")
226
+ return potential_energy
227
+
228
+ def get_energy(self, atoms, coords):
229
+ potential_energy = self.get_potential_energy(coords)
230
+ if self.calculator is not None:
231
+ results = self.calculator.get_energy(atoms, coords)
232
+ else:
233
+ results = {"energy": 0.0}
234
+ results["energy"] += potential_energy
235
+ return results
236
+
237
+ def get_potential_forces(self, coords):
238
+ coords3d = coords.reshape(-1, 3)
239
+ energies_gradients = [
240
+ pot.calc(coords3d, gradient=True) for pot in self.potentials
241
+ ]
242
+ energies, gradients = zip(*energies_gradients)
243
+ self.log(f"Energies from external potential: {energies}")
244
+ energy = sum(energies)
245
+ forces = -np.sum(gradients, axis=0)
246
+ self.log(f"Forces from external potential: {forces}")
247
+ return energy, forces
248
+
249
+ def get_forces(self, atoms, coords):
250
+ potential_energy, potential_forces = self.get_potential_forces(coords)
251
+ if self.calculator is not None:
252
+ results = self.calculator.get_forces(atoms, coords)
253
+ else:
254
+ results = {"energy": 0.0, "forces": np.zeros_like(coords)}
255
+ results["energy"] += potential_energy
256
+ results["forces"] += potential_forces
257
+ return results
258
+
259
+ def get_hessian(self, atoms, coords):
260
+ raise Exception("Hessian is not implemented for ExternalPotential!")
261
+
262
+ def __str__(self):
263
+ pots = ", ".join([str(pot) for pot in self.potentials])
264
+ return f"ExternalPotential({pots})"
@@ -0,0 +1,35 @@
1
+ from pysisyphus.constants import BOHR2ANG
2
+
3
+ class FakeASE:
4
+
5
+ def __init__(self, calc):
6
+ self.calc = calc
7
+
8
+ self.results = dict()
9
+
10
+ def get_atoms_coords(self, atoms):
11
+ return (atoms.get_chemical_symbols(),
12
+ # Convert ASE Angstrom to Bohr for pysisyphus
13
+ atoms.get_positions().flatten() / BOHR2ANG
14
+ )
15
+
16
+ def get_potential_energy(self, atoms=None):
17
+ atoms, coords = self.get_atoms_coords(atoms)
18
+ results = self.calc.get_energy(atoms, coords)
19
+
20
+ energy = results["energy"]
21
+ # self.results["energy"] = results["energy"]
22
+
23
+ return energy
24
+
25
+ def get_forces(self, atoms=None):
26
+ atoms, coords = self.get_atoms_coords(atoms)
27
+ results = self.calc.get_forces(atoms, coords)
28
+
29
+ # Convert back to Angstrom for ASE
30
+ forces = results["forces"].reshape(-1, 3) / BOHR2ANG
31
+
32
+ # self.results["energy"] = results["energy"]
33
+ # self.results["forces"] = forces
34
+
35
+ return forces
@@ -0,0 +1,28 @@
1
+ from pysisyphus.calculators.AnaPotBase import AnaPotBase
2
+
3
+ # See J. Chem. Phys. 122 174106 (2005)
4
+ # https://doi.org/10.1063/1.1885467
5
+ # Eq. (11)
6
+
7
+ class FourWellAnaPot(AnaPotBase):
8
+
9
+ def __init__(self):
10
+ V_str = "x**4 + y**4 - 2*x**2 - 4*y**2 + x*y + 0.3*x + 0.1*y"
11
+ xlim = (-1.75, 1.75)
12
+ ylim = (-1.75, 1.75)
13
+ minima = (
14
+ (1.12410175, -1.48527428, 0.0),
15
+ (-0.82190767, -1.36672971, 0.0),
16
+ (-1.17405609, 1.47708706, 0.0),
17
+ )
18
+ super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, minima=minima)
19
+
20
+ def __str__(self):
21
+ return "FourWellAnaPot calculator"
22
+
23
+
24
+ if __name__ == "__main__":
25
+ fw = FourWellAnaPot()
26
+ fw.plot()
27
+ import matplotlib.pyplot as plt
28
+ plt.show()
@@ -0,0 +1,39 @@
1
+ # import numpy as np
2
+ from sympy import atan, symbols
3
+
4
+ from pysisyphus.calculators.AnaPotBase import AnaPotBase
5
+ from pysisyphus.calculators.LEPSExpr import LEPSExpr
6
+
7
+ # [1] 10.1063/1.4962019 Free-end adaptive NEB
8
+
9
+ class FreeEndNEBPot(AnaPotBase):
10
+
11
+ def __init__(self):
12
+ """Analyitcal potential as described in [1] Appendix A"""
13
+ leps_expr = LEPSExpr()
14
+ V_expr, xlim, ylim, levels = leps_expr.get_expr("harmonic")
15
+
16
+ self.x0 = 1.93
17
+ x = symbols("x")
18
+
19
+ V_expr = V_expr - 2*atan(5*(x-self.x0)) - 2*x
20
+ V_str = str(V_expr)
21
+ # xlim = (0.5, 2.25)
22
+ # ylim = (0.0, 1.6)
23
+ # levels = np.linspace(-10, 0, 125)
24
+ xlim = (0.5, 4)
25
+ ylim = (-4, 2)
26
+ minima = ((0.828758, 1.2027524, 0), (3.0894413, -1.4060824, 0))
27
+
28
+ super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, levels=levels,
29
+ minima=minima)
30
+
31
+ def __str__(self):
32
+ return "FreeEndNEBPot calculator"
33
+
34
+
35
+ if __name__ == "__main__":
36
+ import matplotlib.pyplot as plt
37
+ fep = FreeEndNEBPot()
38
+ fep.plot()
39
+ plt.show()
@@ -0,0 +1,18 @@
1
+ from pysisyphus.calculators.Gaussian16 import Gaussian16
2
+
3
+
4
+ class Gaussian09(Gaussian16):
5
+
6
+ conf_key = "gaussian09"
7
+
8
+ def __init__(self, *args, **kwargs):
9
+ super().__init__(*args, **kwargs)
10
+ self.fn_base = "gaussian09"
11
+ self.inp_fn = f"{self.fn_base}.com"
12
+ self.out_fn = f"{self.fn_base}.log"
13
+ self.chk_fn = f"{self.fn_base}.chk"
14
+ self.base_cmd = self.get_cmd()
15
+ self.formchk_cmd = self.get_cmd("formchk")
16
+
17
+ def __str__(self):
18
+ return "Gaussian09 calculator"