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,25 @@
1
+ from pysisyphus.cos.AdaptiveNEB import AdaptiveNEB
2
+
3
+ # [1] https://www.pnas.org/content/pnas/104/9/3031.full.pdf
4
+ # Zhu, 2006
5
+ # Original method
6
+ # [2] http://dx.doi.org/10.1063/1.4962019
7
+ # Zhang, 2016
8
+ # FreeEnd Adaptive NEB
9
+
10
+
11
+ class FreeEndNEB(AdaptiveNEB):
12
+ def __init__(self, *args, fix_first=False, fix_last=False, **kwargs):
13
+ """Simple Free-End-NEB method.
14
+
15
+ Derived from AdaptiveNEB with disabled adaptation.
16
+ Only implements Eq. (7) from [2]. For other implementations
17
+ please see the commit 01bc8812ca6f1cd3645d43e0337d9e3c5fb0ba55.
18
+ There the other variants are present but I think Eq. (7) in [2] is
19
+ the simplest & best bet.
20
+ """
21
+ kwargs["adapt"] = False
22
+ super().__init__(*args, fix_first=fix_first, fix_last=fix_last, **kwargs)
23
+
24
+ assert (not self.fix_first) or (not self.fix_last), \
25
+ "FreeEndNEB without moving end-image(s) is useless!"
@@ -0,0 +1,103 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.Geometry import Geometry
4
+
5
+
6
+ class FreezingString:
7
+
8
+ def __init__(self, images, calc_getter, max_nodes=10, opt_steps=3):
9
+ self.images = images
10
+ self.calc_getter = calc_getter
11
+ self.opt_steps = opt_steps
12
+ self.max_nodes = int(max_nodes)
13
+ assert self.max_nodes % 2 == 0, "max_nodes must be a multiple of 2!"
14
+
15
+ left_frontier, right_frontier = self.images
16
+ self.left_string = [left_frontier, ]
17
+ self.right_string = [right_frontier, ]
18
+ self.opt_steps_left = self.opt_steps
19
+
20
+ self._forces = None
21
+ self.atoms = left_frontier.atoms
22
+ coord_diff = np.linalg.norm(right_frontier.coords - left_frontier.coords)
23
+ self.step_length = coord_diff / (self.max_nodes+1)
24
+ self.set_new_frontier_nodes()
25
+ self.coord_type = "cart"
26
+
27
+ @property
28
+ def left_frontier(self):
29
+ return self.left_string[-1]
30
+
31
+ @property
32
+ def right_frontier(self):
33
+ return self.right_string[0]
34
+
35
+ def get_tangent(self):
36
+ tangent = self.right_frontier.coords - self.left_frontier.coords
37
+ tangent /= np.linalg.norm(tangent)
38
+ return tangent
39
+
40
+ @property
41
+ def forces(self):
42
+ left_forces = self.left_frontier.forces
43
+ right_forces = self.right_frontier.forces
44
+ forces = (left_forces, right_forces)
45
+ tangent = self.get_tangent()
46
+ perp_forces = np.array([f - f.dot(tangent)*tangent for f in forces]).flatten()
47
+ self._forces = perp_forces
48
+ self.energies = [self.left_frontier.energy, self.right_frontier.energy]
49
+
50
+ return self._forces
51
+
52
+ def as_xyz(self):
53
+ return ""
54
+
55
+ @property
56
+ def fully_grown(self):
57
+ return (len(self.left_string) + len(self.right_string)
58
+ == self.max_nodes + 2)
59
+
60
+ @property
61
+ def energy(self):
62
+ return 10
63
+ # return self.energies
64
+
65
+ def set_new_frontier_nodes(self):
66
+ tangent = self.get_tangent()
67
+ new_left_coords = self.left_frontier.coords + tangent*self.step_length
68
+ new_left_frontier = Geometry(self.atoms, new_left_coords)
69
+ new_left_frontier.set_calculator(self.calc_getter())
70
+ self.left_string.append(new_left_frontier)
71
+
72
+ new_right_coords = self.right_frontier.coords - tangent*self.step_length
73
+ new_right_frontier = Geometry(self.atoms, new_right_coords)
74
+ new_right_frontier.set_calculator(self.calc_getter())
75
+ self.right_string.insert(0, new_right_frontier)
76
+
77
+ def get_new_image(self, coords, index):
78
+ new_image = Geometry(self.left_frontier.atoms, coords)
79
+ new_image.set_calculator(self.calc_getter())
80
+ self.images.insert(index, new_image)
81
+ self.log(f"Create new image; insert it before index {index}.")
82
+ return new_image
83
+
84
+ def reparametrize(self):
85
+ self.opt_steps_left -= 1
86
+
87
+ if not self.fully_grown and self.opt_steps_left == 0:
88
+ self.set_new_frontier_nodes()
89
+ self.opt_steps_left = self.opt_steps
90
+
91
+ @property
92
+ def allcoords(self):
93
+ return np.array([img.coords for img in self.left_string + self.right_string]).flatten()
94
+
95
+ @property
96
+ def coords(self):
97
+ return np.array((self.left_frontier.coords, self.right_frontier.coords)).flatten()
98
+
99
+ @coords.setter
100
+ def coords(self, coords):
101
+ left, right = coords.reshape(2, -1)
102
+ self.left_frontier.coords = left
103
+ self.right_frontier.coords = right
@@ -0,0 +1,71 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.cos.ChainOfStates import ChainOfStates
4
+ from pysisyphus.Geometry import Geometry
5
+
6
+
7
+ class GrowingChainOfStates(ChainOfStates):
8
+
9
+ def __init__(self, images, calc_getter, max_nodes=10,
10
+ **kwargs):
11
+ super().__init__(images, **kwargs)
12
+
13
+ self.max_nodes = max_nodes
14
+ self.calc_getter = calc_getter
15
+ self.zero_step = np.zeros_like(self.images[0].coords)
16
+
17
+ def get_new_image_from_coords(self, coords, index):
18
+ new_image = Geometry(
19
+ self.image_atoms,
20
+ coords,
21
+ coord_type=self.coord_type,
22
+ coord_kwargs={"typed_prims": self.typed_prims},
23
+ freeze_atoms=self.images[0].freeze_atoms.copy()
24
+ )
25
+ new_image.set_calculator(self.calc_getter())
26
+ self.images.insert(index, new_image)
27
+ self.log(f"Create new image; insert it before index {index}.")
28
+ return new_image
29
+
30
+ @property
31
+ def arc_dims(self):
32
+ cds = [0, ]
33
+ for i, image in enumerate(self.images[:-1]):
34
+ next_image = self.images[i+1]
35
+ diff = np.linalg.norm(next_image - image)
36
+ cds.append(diff)
37
+ cds = np.cumsum(cds)
38
+ tot_length = cds[-1]
39
+ norm_cds = cds / cds.max()
40
+ return tot_length, norm_cds
41
+
42
+ @property
43
+ def max_image_num(self):
44
+ return self.max_nodes + 2
45
+
46
+ def new_node_coords(self, k):
47
+ l = (self.max_nodes-k) / (self.max_nodes+1-k)
48
+ kth_coords = self.images[k].coords
49
+ last_coords = self.images[-1].coords
50
+ new_coords = l*kth_coords + (1-l)*last_coords
51
+ return new_coords
52
+
53
+ def set_new_node(self, k):
54
+ new_coords = self.new_node_coords(k)
55
+ new_node = Geometry(
56
+ self.image_atoms,
57
+ new_coords,
58
+ freeze_atoms=self.images[0].freeze_atoms.copy()
59
+ )
60
+ new_node.set_calculator(self.calc_getter())
61
+ self.images.insert(k+1, new_node)
62
+ return new_node
63
+
64
+ def prepare_opt_cycle(self, *args, **kwargs):
65
+ parent_result = super().prepare_opt_cycle(*args, **kwargs)
66
+
67
+ # Compare size of coords arrays to determine if new nodes
68
+ # were added in the last reparametrization.
69
+ last_size = self.coords_list[-1].size
70
+ length_changed = last_size != self.coords.size
71
+ return parent_result or length_changed
@@ -0,0 +1,309 @@
1
+ # [1] https://aip.scitation.org/doi/abs/10.1063/1.1885467
2
+ # Quapp, 2005
3
+
4
+ import logging
5
+ import os
6
+ from pathlib import Path
7
+
8
+ import numpy as np
9
+
10
+ from pysisyphus.helpers_pure import rms
11
+ from pysisyphus.intcoords.helpers import get_weighted_bond_mode
12
+
13
+
14
+ class GrowingNT:
15
+ logger = logging.getLogger("cos")
16
+
17
+ def __init__(
18
+ self,
19
+ geom,
20
+ step_len=0.5,
21
+ rms_thresh=1.7e-3,
22
+ r=None,
23
+ final_geom=None,
24
+ between=None,
25
+ bonds=None,
26
+ r_update=True,
27
+ r_update_thresh=1.0,
28
+ stop_after_ts=False,
29
+ require_imag_freq=0.0,
30
+ hessian_at_ts=False,
31
+ out_dir=".",
32
+ dump=True,
33
+ ):
34
+ assert geom.coord_type == "cart"
35
+
36
+ self.geom = geom
37
+ self.step_len = step_len
38
+ self.rms_thresh = rms_thresh
39
+ self.final_geom = final_geom
40
+ self.between = between
41
+ self.bonds = bonds
42
+ self.r_update = r_update
43
+ self.r_update_thresh = r_update_thresh
44
+ self.stop_after_ts = stop_after_ts
45
+ self.require_imag_freq = require_imag_freq
46
+ self.hessian_at_ts = hessian_at_ts
47
+ self.out_dir = Path(out_dir)
48
+ self.dump = dump
49
+
50
+ if not self.out_dir.exists():
51
+ os.mkdir(self.out_dir)
52
+
53
+ self.coord_type = self.geom.coord_type
54
+ if self.final_geom:
55
+ self.converge_to_geom = self.final_geom
56
+
57
+ # Determine search direction
58
+ self.r = self.get_r(self.geom, self.final_geom, self.bonds, r)
59
+ self.r_org = self.r.copy()
60
+ # Determine appropriate step_len from between
61
+ if final_geom and self.between:
62
+ self.step_len = np.linalg.norm(final_geom.coords - geom.coords) / (
63
+ self.between + 1
64
+ )
65
+
66
+ self._initialized = False
67
+ self.images = [self.geom.copy()]
68
+ self.all_energies = list()
69
+ self.all_real_forces = list()
70
+ self.sp_images = [self.geom.copy()] # Stationary points
71
+ self.ts_images = list()
72
+ self.min_images = list()
73
+
74
+ self.ts_imag_freqs = list()
75
+
76
+ # Right now this leads to a gradient calculation in the momement,
77
+ # this object is constructed, which is bad.
78
+ self.initialize()
79
+
80
+ if self.dump:
81
+ self.trj_fn = self.get_path("newton_trajectory_trj.xyz")
82
+
83
+ def get_path(self, fn):
84
+ return self.out_dir / fn
85
+
86
+ @staticmethod
87
+ def get_r(geom, final_geom, bonds, r):
88
+ if final_geom:
89
+ r = final_geom - geom
90
+ # self.converge_to_geom = self.final_geom
91
+ elif bonds is not None:
92
+ r = get_weighted_bond_mode(bonds, geom.coords3d)
93
+ # Use 'r' as it is
94
+ elif r is not None:
95
+ pass
96
+ else:
97
+ raise Exception("Please supply either 'r' or 'final_geom'!")
98
+
99
+ r = r / np.linalg.norm(r)
100
+ return r
101
+
102
+ def log(self, message):
103
+ self.logger.debug(message)
104
+
105
+ @property
106
+ def r(self):
107
+ """Parallel/search direction."""
108
+ return self._r
109
+
110
+ @property
111
+ def P(self):
112
+ """Projector that keeps perpendicular component."""
113
+ return self._P
114
+
115
+ @r.setter
116
+ def r(self, r):
117
+ """Update r and calculate new projector."""
118
+ self._r = r
119
+ self._P = np.eye(self.coords.size) - np.outer(self.r, self.r)
120
+
121
+ @property
122
+ def atoms(self):
123
+ return self.geom.atoms
124
+
125
+ @property
126
+ def coords(self):
127
+ return self.geom.coords
128
+
129
+ @coords.setter
130
+ def coords(self, coords):
131
+ self.geom.coords = coords
132
+
133
+ @property
134
+ def cart_coords(self):
135
+ return self.geom.cart_coords
136
+
137
+ def grow_image(self):
138
+ self.images[-1] = self.geom.copy()
139
+ # Update coordinates of newly grown image. Try to use Eq. (6) in [1].
140
+ if self._initialized and self.final_geom and self.between:
141
+ m = self.between + 2
142
+ k = len(self.images) - 1
143
+ lambda_ = (m - k) / (m + 1 - k)
144
+ # Adapted from [6] to produce a step instead of new coords
145
+ step = self.coords * (lambda_ - 1) + (1 - lambda_) * self.final_geom.coords
146
+ # If no final image is given we just displace along r
147
+ else:
148
+ step = self.step_len * self.r
149
+ self.coords = self.coords + step
150
+
151
+ # Calculate energy and forces at newly grown geometry and append new frontier
152
+ # image.
153
+ real_forces = self.geom.forces
154
+ energy = self.geom.energy
155
+ self.all_energies.append(energy)
156
+ self.all_real_forces.append(real_forces)
157
+ self.images.append(self.geom)
158
+
159
+ def initialize(self):
160
+ assert not self._initialized, "GrowingNT.initialize() can only be called once!"
161
+ # Calculation at initial geometry
162
+ init_results = self.geom.get_energy_and_forces_at(self.images[0].coords)
163
+ self.all_energies.append(init_results["energy"])
164
+ self.all_real_forces.append(init_results["forces"])
165
+ # Do initial displacement
166
+ self.grow_image()
167
+ # Indicate the GrowingNT was properly initialized
168
+ self._initialized = True
169
+
170
+ def calc_hessian_for(self, other_geom):
171
+ res = self.geom.get_energy_and_cart_hessian_at(other_geom.cart_coords)
172
+ cart_hessian = res["hessian"]
173
+ return cart_hessian
174
+
175
+ @property
176
+ def energy(self):
177
+ return self.geom.energy
178
+
179
+ @property
180
+ def forces(self):
181
+ forces = self.geom.forces
182
+ perp_forces = self.P.dot(forces)
183
+ return perp_forces
184
+
185
+ @property
186
+ def cart_forces(self):
187
+ return self.geom.cart_forces
188
+
189
+ def get_energy_at(self, coords):
190
+ return self.geom.get_energy_at(coords)
191
+
192
+ def get_energy_and_forces_at(self, coords):
193
+ return self.geom.get_energy_and_forces_at(coords)
194
+
195
+ def as_xyz(self):
196
+ return self.geom.as_xyz()
197
+
198
+ def clear_passed(self):
199
+ self.passed_min = False
200
+ self.passed_ts = False
201
+
202
+ def reparametrize(self):
203
+ """Check if GNT can be grown."""
204
+
205
+ # Real, unprojected, forces of the underlying geometry
206
+ real_forces = self.geom.forces
207
+ energy = self.energy
208
+ # Update the last element in all_real_forces and energies with the
209
+ # current values.
210
+ self.all_real_forces[-1] = real_forces
211
+ self.all_energies[-1] = energy
212
+
213
+ # See if we can grow the NT, by checking the convergence of the frontier
214
+ # image using projected forces.
215
+ forces = self.forces
216
+ can_grow = rms(forces) <= self.rms_thresh
217
+
218
+ if can_grow:
219
+ if self.dump:
220
+ with open(self.trj_fn, "w") as handle:
221
+ handle.write("\n".join([geom.as_xyz() for geom in self.images]))
222
+
223
+ r"""
224
+ Check if we passed a stationary point (SP).
225
+ ^ Energy
226
+ |
227
+ | -3 -1 -2
228
+ | \ / / \
229
+ | \ / / \
230
+ | -2 -3 -1
231
+ | Minimum TS
232
+ """
233
+ ae = self.all_energies # Shortcut
234
+ self.passed_min = len(ae) >= 3 and ae[-3] > ae[-2] < ae[-1]
235
+ self.passed_ts = len(ae) >= 3 and ae[-3] < ae[-2] > ae[-1]
236
+ passed_sp = self.passed_min or self.passed_ts
237
+ if passed_sp:
238
+ sp_image = self.images[-2].copy()
239
+ sp_kind = "Minimum" if self.passed_min else "TS"
240
+ self.sp_images.append(sp_image)
241
+ self.log(
242
+ f"Passed stationary point! It seems to be a {sp_kind}."
243
+ f"\n{sp_image.as_xyz()}"
244
+ )
245
+ if self.passed_ts:
246
+ self.ts_images.append(sp_image)
247
+ if self.hessian_at_ts:
248
+ sp_hessian = self.calc_hessian_for(sp_image)
249
+ nus, *_ = sp_image.get_normal_modes(sp_hessian)
250
+ self.log(f"First 5 frequencies: {nus[:5]}")
251
+ if self.require_imag_freq < 0.0:
252
+ try:
253
+ sp_hessian
254
+ except NameError:
255
+ sp_hessian = self.calc_hessian_for(sp_image)
256
+ self.ts_imag_freqs.append(
257
+ sp_image.get_imag_frequencies(sp_hessian)
258
+ )
259
+ elif self.passed_min:
260
+ self.min_images.append(sp_image)
261
+
262
+ # Update direction 'r', if requested
263
+ r_new = self.get_r(self.geom, self.final_geom, self.bonds, self.r)
264
+ r_dot = r_new.dot(self.r)
265
+ r_org_dot = r_new.dot(self.r_org)
266
+ self.log(f"r.dot(r')={r_dot:.6f} r_org.dot(r')={r_org_dot:.6f}")
267
+ if (
268
+ self.r_update
269
+ and (r_org_dot <= self.r_update_thresh)
270
+ and self.passed_min
271
+ ):
272
+ self.r = r_new
273
+ self.log("Updated r")
274
+
275
+ # Grow new image
276
+ self.grow_image()
277
+ assert (
278
+ len(self.images) == len(self.all_energies) == len(self.all_real_forces)
279
+ )
280
+
281
+ self.did_reparametrization = can_grow
282
+ return can_grow
283
+
284
+ def check_convergence(self, *args, **kwargs):
285
+ if len(self.ts_images) == 0:
286
+ return False
287
+
288
+ converged = self.stop_after_ts
289
+ if self.require_imag_freq:
290
+ converged = (
291
+ converged and self.ts_imag_freqs[-1][0] <= self.require_imag_freq
292
+ )
293
+ return converged
294
+
295
+ def get_additional_print(self):
296
+ if self.did_reparametrization:
297
+ img_num = len(self.images)
298
+ str_ = f"Grew Newton trajectory to {img_num} images."
299
+ if self.passed_min:
300
+ str_ += f" Passed minimum geometry at image {img_num-1}."
301
+ elif self.passed_ts:
302
+ str_ += f" Passed transition state geometry at image {img_num-1}."
303
+ else:
304
+ str_ = None
305
+
306
+ self.did_reparametrization = False
307
+ self.clear_passed()
308
+
309
+ return str_