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,159 @@
1
+ # [1] https://doi.org/10.1002/jcc.26495
2
+ # Habershon, 2021
3
+
4
+ import itertools as it
5
+
6
+ import numpy as np
7
+
8
+ from pysisyphus.helpers_pure import get_molecular_radius
9
+
10
+
11
+ class HardSphere:
12
+ def __init__(
13
+ self,
14
+ geom,
15
+ frags,
16
+ kappa=1.0,
17
+ permutations=False,
18
+ frag_radii=None,
19
+ radii_offset=0.9452,
20
+ ):
21
+ """Intra-Image Inter-Molecular Hard-Sphere force.
22
+
23
+ See A.2. in [1], Eq. (A1).
24
+ """
25
+ self.frags = frags
26
+ self.kappa = kappa
27
+
28
+ self.frag_num = len(self.frags)
29
+ self.frag_sizes = np.array([len(frag) for frag in self.frags])
30
+ self.pair_inds = np.array(list(it.combinations(range(self.frag_num), 2)))
31
+ it_func = it.permutations if permutations else it.combinations
32
+ self.pair_inds = np.array(list(it_func(range(self.frag_num), 2)))
33
+ self.frag_inds = np.array([m for m, n in self.pair_inds])
34
+
35
+ c3d = geom.coords3d
36
+ frag_c3ds = [c3d[frag] for frag in self.frags]
37
+ self.frag_radii = frag_radii
38
+ if self.frag_radii is None:
39
+ self.frag_radii = [
40
+ get_molecular_radius(frag_c3d, min_offset=radii_offset)
41
+ for frag_c3d in frag_c3ds
42
+ ]
43
+ self.radii_sums = np.array(
44
+ [self.frag_radii[i] + self.frag_radii[j] for i, j in self.pair_inds]
45
+ )
46
+
47
+ def get_forces(self, atoms, coords, kappa=None):
48
+ if kappa is None:
49
+ kappa = self.kappa
50
+ c3d = coords.reshape(-1, 3)
51
+
52
+ # Break early when only 1 fragment is present
53
+ if len(self.pair_inds) == 0:
54
+ return {"energy": 1, "forces": np.zeros_like(coords)}
55
+
56
+ centroids = np.array([c3d[frag].mean(axis=0) for frag in self.frags])
57
+ mm, nn = np.array(self.pair_inds).T
58
+ gdiffs = centroids[mm] - centroids[nn]
59
+ # Add small number to avoid division by zero in 'frag_gradient' calculation
60
+ gnorms = np.linalg.norm(gdiffs, axis=1) + 1e-16
61
+ H = (gnorms < self.radii_sums).astype(int)
62
+ N = H.copy()
63
+ N *= 3 * self.frag_sizes[self.frag_inds]
64
+ N_invs = np.divide(1, N, out=np.zeros_like(N).astype(float), where=N != 0)
65
+ phi = kappa * N_invs * (gnorms - self.radii_sums)
66
+ frag_gradient = (phi * H / gnorms)[:, None] * gdiffs
67
+ gradient = np.zeros_like(c3d)
68
+ # Distribute gradient onto fragments
69
+ for frag_ind, ff in zip(self.frag_inds, frag_gradient):
70
+ gradient[self.frags[frag_ind]] += ff
71
+ forces = -gradient.flatten()
72
+
73
+ f3d = forces.reshape(-1, 3)
74
+ f3d -= f3d.mean(axis=0)[None, :]
75
+
76
+ return {"energy": 1, "forces": forces}
77
+
78
+
79
+ class PWHardSphere:
80
+ def __init__(
81
+ self,
82
+ geom,
83
+ frags,
84
+ sub_frags,
85
+ kappa=1.0,
86
+ ):
87
+ """Inter-Molecular pairwise Hard-Sphere forces between atoms.
88
+
89
+ Hardsphere forces are only applied between certain atoms of given fragments,
90
+ but the whole fragment is moved. Can be used to remove atom inter-molecular
91
+ atom clashes.
92
+ """
93
+ self.frags = frags
94
+ self.sub_frags = sub_frags
95
+ self.kappa = kappa
96
+
97
+ self.frag_num = len(self.frags)
98
+ self.frag_sizes = np.array([len(frag) for frag in self.frags])
99
+ self.pair_inds = np.array(list(it.combinations(range(self.frag_num), 2)))
100
+ cov_rads = geom.covalent_radii
101
+ self.pair_atom_inds = list()
102
+ self.pair_cov_radii = list()
103
+ for m, n in self.pair_inds:
104
+ frag_m = self.sub_frags[m]
105
+ frag_n = self.sub_frags[n]
106
+ painds = list()
107
+ pcr = list()
108
+ for fm in frag_m:
109
+ crm = cov_rads[m]
110
+ for fn in frag_n:
111
+ crn = cov_rads[m]
112
+ crsum = crm + crn
113
+ painds.append([fm, fn])
114
+ pcr.append(crsum)
115
+ self.pair_atom_inds.append(painds)
116
+ self.pair_cov_radii.append(pcr)
117
+
118
+ def get_forces(self, atoms, coords, kappa=None):
119
+ if kappa is None:
120
+ kappa = self.kappa
121
+ c3d = coords.reshape(-1, 3)
122
+
123
+ # Break early when only 1 fragment is present
124
+ if len(self.pair_inds) == 0:
125
+ return {"energy": 1, "forces": np.zeros_like(coords)}
126
+
127
+ forces = np.zeros_like(c3d)
128
+ centroids = np.array([c3d[frag].mean(axis=0) for frag in self.frags])
129
+ N = 1.0
130
+ N_inv = 1 / N
131
+ for (m, n), pai, pcr in zip(
132
+ self.pair_inds, self.pair_atom_inds, self.pair_cov_radii
133
+ ):
134
+ frag_m = self.frags[m]
135
+ frag_n = self.frags[n]
136
+ centr_m = centroids[m]
137
+ centr_n = centroids[n]
138
+ dcentr = centr_m - centr_n
139
+ force_dir = dcentr / np.linalg.norm(dcentr)
140
+ for (am, an), crmn in zip(pai, pcr):
141
+ amn = c3d[am] - c3d[an]
142
+ distmn = np.linalg.norm(amn)
143
+ diff = distmn - crmn
144
+ fact = int(distmn < crmn)
145
+ if not fact:
146
+ continue
147
+ # Magnitude of applied force
148
+ magn = kappa * N_inv * diff
149
+ force = magn * force_dir
150
+ # Distribute half of the force onto each fragment
151
+ force_2 = force / 2
152
+ # The signs below depend on the difference centr_m - centr_n above
153
+ forces[frag_m] -= force_2
154
+ forces[frag_n] += force_2
155
+
156
+ forces -= forces.mean(axis=0)[None, :]
157
+ forces = forces.flatten()
158
+
159
+ return {"energy": 1, "forces": forces}
@@ -0,0 +1,49 @@
1
+ import numpy as np
2
+ from scipy.spatial.distance import pdist, squareform
3
+
4
+ from pysisyphus.calculators.Calculator import Calculator
5
+
6
+
7
+ class IDPPCalculator(Calculator):
8
+
9
+ def __init__(self, target):
10
+ self.target = squareform(target)
11
+
12
+ super().__init__(base_name="idpp")
13
+
14
+ def get_forces(self, atoms, coords):
15
+ coords_reshaped = coords.reshape((-1, 3))
16
+
17
+ D = []
18
+ for c in coords_reshaped:
19
+ Di = coords_reshaped - c
20
+ D.append(Di)
21
+ D = np.array(D)
22
+
23
+ curr_pdist = pdist(coords_reshaped)
24
+ curr_square = squareform(curr_pdist)
25
+ curr_diff = curr_square - self.target
26
+
27
+ curr_square = curr_square + np.eye(curr_square.shape[0])
28
+
29
+ # The bigger the differences 'curr_diff', the bigger the energy.
30
+ # The smaller the current distances 'current_pdist', the bigger
31
+ # the energy.
32
+ energy = 0.5 * (curr_diff**2 / curr_square**4).sum()
33
+
34
+ # Adapted from ASE IDPP calculator
35
+ # https://gitlab.com/ase/ase/blob/master/ase/neb.py, GPL2
36
+ forces = -2 * ((curr_diff *
37
+ (1 - 2 * curr_diff / curr_square) /
38
+ curr_square**5)[...,np.newaxis] * D).sum(0)
39
+
40
+ results = {
41
+ "energy" : energy,
42
+ "forces": forces.flatten()
43
+ }
44
+ return results
45
+
46
+ def __str__(self):
47
+ return "IDPP calculator"
48
+
49
+
@@ -0,0 +1,133 @@
1
+ import struct
2
+ import socket
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.socket_helper import send_closure, recv_closure, get_fmts
7
+
8
+
9
+ def ipi_client(
10
+ addr, atoms, energy_getter, forces_getter, hessian_getter=None, hdrlen=12
11
+ ):
12
+ atom_num = len(atoms)
13
+ # Number of entries in a Caretsian forces/coords vector
14
+ cartesians = 3 * atom_num
15
+ # Formats needed for struct.pack, to cast variables to bytes.
16
+ # Bytes needed, to store a forces/coords vector
17
+ floats_bytes = 8 * cartesians
18
+ # Virial is hardcoded to the zero vector.
19
+ VIRIAL = struct.pack("d" * 9, *np.zeros(9))
20
+ ZERO = struct.pack("i", 0)
21
+
22
+ fmts = get_fmts(cartesians)
23
+
24
+ # Unix socket is hardcoded right now, but may also be inet-socket
25
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
26
+ addr = str(addr)
27
+ sock.connect(addr)
28
+
29
+ send_msg = send_closure(sock, hdrlen, fmts)
30
+ recv_msg = recv_closure(sock, hdrlen, fmts)
31
+
32
+ counter = 0
33
+ while True:
34
+ try:
35
+ # Lets start talking
36
+ recv_msg(expect="STATUS") # The server initiates with a STATUS
37
+ send_msg("READY")
38
+
39
+ status = recv_msg(expect="STATUS")
40
+ if status == "NEEDPOS":
41
+ send_msg("HAVEPOS")
42
+ _ = recv_msg(4, fmt="int")[0] # Recive atom num from IPI
43
+ coords = np.array(
44
+ recv_msg(floats_bytes, "floats")
45
+ ) # Receive current coords
46
+ assert coords.size % 3 == 0 # Assert Cartesian coordinates
47
+ send_msg(atom_num, "int")
48
+ # Just send back the current coordinates or translate all atoms in +X
49
+ coords.reshape(-1, 3)[:, 0] += 1
50
+ send_msg(coords, "floats")
51
+ continue
52
+
53
+ # When the optimization converged EXIT will be returned .. not documented!
54
+ if status == "EXIT":
55
+ print("Exited!")
56
+ break
57
+
58
+ # It seems we have to send READY two times ... not documented!
59
+ send_msg("READY")
60
+ # The server then returns POSDATA.
61
+ recv_msg(expect="POSDATA")
62
+ # Receive cell vectors, inverse cell vectors and number of atoms ...
63
+ # but we don't use them here, so we don't even try to convert them to something.
64
+ sock.recv(72) # cell
65
+ sock.recv(72) # icell
66
+ ipi_atom_num = recv_msg(4, fmt="int")[0]
67
+ assert ipi_atom_num == atom_num
68
+ # ... and the current coordinates.
69
+ coords = np.array(recv_msg(floats_bytes, "floats"))
70
+
71
+ recv_msg(expect="STATUS")
72
+ # Indicate, that calculation is possible
73
+ send_msg("HAVEDATA")
74
+ get_what = recv_msg()
75
+ # Acutal QC calculations
76
+ if get_what == "GETENERGY":
77
+ energy = energy_getter(coords)
78
+ print(f"Calculated energy: {energy:.6f}, counter={counter}")
79
+ send_msg("ENERGYREADY")
80
+ send_msg(energy, "float")
81
+ if get_what == "GETFORCE":
82
+ forces, energy = forces_getter(coords)
83
+ print(f"Calculated energy & forces: {energy:.6f}, counter={counter}")
84
+ send_msg("FORCEREADY")
85
+ # Send everything to the server
86
+ send_msg(energy, "float")
87
+ send_msg(atom_num, "int")
88
+ send_msg(forces, "floats")
89
+ send_msg(VIRIAL, packed=True)
90
+ # We don't want to send additional information, so just send 0.
91
+ send_msg(ZERO, packed=True)
92
+ elif get_what == "GETHESSIAN":
93
+ hessian, energy = hessian_getter(coords)
94
+ hessian_packed = struct.pack("d" * cartesians ** 2, *hessian.flatten())
95
+ print(f"Calculated energy & Hessian: {energy:.6f}, counter={counter}")
96
+ send_msg("HESSIANREADY")
97
+ # Send everything to the server
98
+ send_msg(energy, "float")
99
+ send_msg(atom_num, "int")
100
+ send_msg(hessian_packed, packed=True)
101
+
102
+ counter += 1
103
+ except Exception as err:
104
+ raise err
105
+
106
+
107
+ def calc_ipi_client(addr, atoms, calc, queue=None, **kwargs):
108
+ assert calc is not None, "Supplied calculator must not be None!"
109
+
110
+ def energy_getter(coords):
111
+ if queue is not None:
112
+ queue.put(("coords", coords))
113
+ results = calc.get_energy(atoms, coords)
114
+ energy = results["energy"]
115
+ return energy
116
+
117
+ def forces_getter(coords):
118
+ if queue is not None:
119
+ queue.put(("coords", coords))
120
+ results = calc.get_forces(atoms, coords)
121
+ forces = results["forces"]
122
+ energy = results["energy"]
123
+ return forces, energy
124
+
125
+ def hessian_getter(coords):
126
+ if queue is not None:
127
+ queue.put(("coords", coords))
128
+ results = calc.get_hessian(atoms, coords)
129
+ hessian = results["hessian"]
130
+ energy = results["energy"]
131
+ return hessian, energy
132
+
133
+ ipi_client(addr, atoms, energy_getter, forces_getter, hessian_getter, **kwargs)
@@ -0,0 +1,234 @@
1
+ import os
2
+ import socket
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.calculators.Calculator import Calculator
7
+ from pysisyphus.socket_helper import (
8
+ send_closure,
9
+ recv_closure,
10
+ get_fmts,
11
+ EYE3,
12
+ )
13
+
14
+
15
+ class IPIServer(Calculator):
16
+ listen_kinds = ("coords", "energy", "forces", "hessian")
17
+
18
+ def __init__(
19
+ self,
20
+ *args,
21
+ address=None,
22
+ host=None,
23
+ port=None,
24
+ unlink=True,
25
+ hdrlen=12,
26
+ max_retries=0,
27
+ verbose=False,
28
+ **kwargs,
29
+ ):
30
+ super().__init__(*args, **kwargs)
31
+ self.address = address
32
+ self.host = host
33
+ self.port = port
34
+ if self.host:
35
+ assert self.port is not None
36
+ self.hdrlen = hdrlen
37
+ self.max_retries = max_retries
38
+ self.verbose = verbose
39
+
40
+ if self.address and unlink:
41
+ self.unlink(self.address)
42
+
43
+ if self.address:
44
+ family = socket.AF_UNIX
45
+ bind_args = (self.address,)
46
+ else:
47
+ family = socket.AF_INET
48
+ bind_args = (self.host, self.port)
49
+
50
+ # Create socket
51
+ self.sock = socket.socket(family, socket.SOCK_STREAM)
52
+ self.sock.bind(*bind_args)
53
+ self.sock.listen(1)
54
+
55
+ self.fmts = None
56
+ self.send_msg = None
57
+ self.recv_msg = None
58
+ self.reset_client_connection()
59
+
60
+ def unlink(self, address):
61
+ try:
62
+ os.unlink(address)
63
+ except OSError as err:
64
+ if os.path.exists(address):
65
+ raise err
66
+
67
+ def reset_client_connection(self):
68
+ self.log("Resetting client connection info.")
69
+ try:
70
+ self.conn.close()
71
+ except AttributeError:
72
+ self.log("No client connection present.")
73
+ self._client_conn = None
74
+ self._client_address = None
75
+ self.cur_retries = 0
76
+
77
+ def listen_for_client_atom_num(self, atom_num):
78
+ client_atom_num = self.recv_msg(4, fmt="int")[0]
79
+ self.log(
80
+ f"Client sent number of atoms: {client_atom_num}, expecting {atom_num}."
81
+ )
82
+ assert atom_num == client_atom_num
83
+ return atom_num
84
+
85
+ def listen_for_energy(self):
86
+ send_msg = self.send_msg
87
+ recv_msg = self.recv_msg
88
+
89
+ send_msg("GETENERGY")
90
+ recv_msg(expect="ENERGYREADY")
91
+ energy = recv_msg(8, fmt="float")[0]
92
+ results = {
93
+ "energy": energy,
94
+ }
95
+ return results
96
+
97
+ def listen_for_forces(self, atom_num):
98
+ send_msg = self.send_msg
99
+ recv_msg = self.recv_msg
100
+
101
+ send_msg("GETFORCE")
102
+ recv_msg(expect="FORCEREADY")
103
+ energy = recv_msg(8, fmt="float")[0]
104
+ self.listen_for_client_atom_num(atom_num)
105
+ coord_num = 3 * atom_num
106
+ forces = recv_msg(coord_num * 8, fmt="floats", expect="forces")
107
+ recv_msg(72, fmt="nine_floats", expect="virial")
108
+ recv_msg(4, fmt="int", expect="zero")
109
+ results = {
110
+ "energy": energy,
111
+ "forces": np.array(forces),
112
+ }
113
+ return results
114
+
115
+ def listen_for_hessian(self, atom_num):
116
+ send_msg = self.send_msg
117
+ recv_msg = self.recv_msg
118
+
119
+ send_msg("GETHESSIAN")
120
+ recv_msg(expect="HESSIANREADY")
121
+ energy = recv_msg(8, fmt="float")[0]
122
+ self.listen_for_client_atom_num(atom_num)
123
+ coord_num = 3 * atom_num
124
+ hessian = recv_msg(coord_num ** 2 * 8, fmt="floats_sq", expect="Hessian")
125
+ hessian = np.array(hessian).reshape(-1, coord_num)
126
+ results = {
127
+ "energy": energy,
128
+ "hessian": hessian,
129
+ }
130
+ return results
131
+
132
+ def listen_for(self, atoms, coords, kind="forces"):
133
+ assert kind in self.listen_kinds
134
+
135
+ atom_num = len(atoms)
136
+ coords_num = len(coords)
137
+
138
+ # Setup connection
139
+ if (self._client_conn is None) or (self._client_address is None):
140
+ self.log("Waiting for a connection.")
141
+ self._client_conn, self._client_address = self.sock.accept()
142
+ if self._client_address != "":
143
+ conn_msg = f"Got new connection from {self._client_address}."
144
+ else:
145
+ conn_msg = "Got new connection."
146
+ self.log(conn_msg)
147
+ # Create send/receive functions for this connection
148
+ self.fmts = get_fmts(coords_num)
149
+ self.send_msg = send_closure(
150
+ self._client_conn, self.hdrlen, self.fmts, verbose=self.verbose
151
+ )
152
+ self.recv_msg = recv_closure(
153
+ self._client_conn, self.hdrlen, self.fmts, verbose=self.verbose
154
+ )
155
+
156
+ # Reuse existing connection self._client_conn, wrapped in the
157
+ # functions below.
158
+ send_msg = self.send_msg
159
+ recv_msg = self.recv_msg
160
+
161
+ # Lets start talking
162
+ send_msg("STATUS")
163
+ recv_msg(expect="READY")
164
+
165
+ # This path handles a coordinate update through the client.
166
+ if kind == "coords":
167
+ send_msg("NEEDPOS")
168
+ # TODO: allow skipping the update
169
+ recv_msg(expect="HAVEPOS")
170
+ # Send current atom number and coordinates
171
+ send_msg(atom_num, fmt="int")
172
+ send_msg(coords, fmt="floats")
173
+ # Receive atom number and potentially modified coordinates from the client.
174
+ self.listen_for_client_atom_num(atom_num)
175
+ new_coords = recv_msg(atom_num * 3 * 8, fmt="floats")
176
+ results = {"coords": np.array(new_coords)}
177
+ # The path below leads to sending of coordinates and calculation of
178
+ # energy and maybe its derivatives by the client.
179
+ else:
180
+ send_msg("STATUS")
181
+ recv_msg(expect="READY")
182
+ send_msg("POSDATA")
183
+ # Send cell vectors, inverse cell vectors, number of atoms and coordinates
184
+ send_msg(EYE3, packed=True) # cell vectors
185
+ send_msg(EYE3, packed=True) # inverse cell vectors
186
+ send_msg(atom_num, fmt="int")
187
+ send_msg(coords, fmt="floats")
188
+ send_msg("STATUS")
189
+ recv_msg(expect="HAVEDATA")
190
+ if kind == "energy":
191
+ results = self.listen_for_energy()
192
+ elif kind == "forces":
193
+ results = self.listen_for_forces(atom_num)
194
+ elif kind == "hessian":
195
+ results = self.listen_for_hessian(atom_num)
196
+ return results
197
+
198
+ def retried_listen_for(self, atoms, coords):
199
+ while self.cur_retries < self.max_retries:
200
+ try:
201
+ result = self.listen_for(atoms, coords)
202
+ break
203
+ except Exception as err:
204
+ self.log(f"Caught exception: {err}.")
205
+ self.cur_retries += 1
206
+ self.reset_client_connection()
207
+ result = self.listen_for(atoms, coords)
208
+ return result
209
+
210
+ def __del__(self):
211
+ self.send_msg("STATUS")
212
+ _ = self.recv_msg()
213
+ self.send_msg("EXIT")
214
+ self.log("Sent EXIT to client.")
215
+ self.reset_client_connection()
216
+ # self.unlink(self.address)
217
+
218
+ def get_energy(self, atoms, coords):
219
+ return self.listen_for(atoms, coords, kind="energy")
220
+
221
+ # def get_forces(self, atoms, coords):
222
+ # if self.max_retries:
223
+ # result = self.retried_listen_for(atoms, coords)
224
+ # else:
225
+ # result = self.listen_for(atoms, coords)
226
+
227
+ # def get_coords(self, atoms, coords):
228
+ # return self.listen_for(atoms, coords, kind="coords")
229
+
230
+ def get_forces(self, atoms, coords):
231
+ return self.listen_for(atoms, coords, kind="forces")
232
+
233
+ def get_hessian(self, atoms, coords):
234
+ return self.listen_for(atoms, coords, kind="hessian")
@@ -0,0 +1,24 @@
1
+ from pysisyphus.calculators.AnaPotBase import AnaPotBase
2
+ from pysisyphus.calculators.LEPSExpr import LEPSExpr
3
+
4
+
5
+ class LEPSBase(AnaPotBase):
6
+
7
+ def __init__(self, pot_type="leps"):
8
+ leps_expr = LEPSExpr()
9
+ V_expr, xlim, ylim, levels = leps_expr.get_expr(pot_type)
10
+ V_str = str(V_expr)
11
+
12
+ super().__init__(V_str=V_str, xlim=xlim, ylim=ylim, levels=levels)
13
+
14
+ def __str__(self):
15
+ return "LEPSBase calculator"
16
+
17
+
18
+ if __name__ == "__main__":
19
+ import matplotlib.pyplot as plt
20
+ choices = "leps harmonic tot dimer".split()
21
+ for c in choices:
22
+ lp = LEPSBase(pot_type=c)
23
+ lp.plot()
24
+ plt.show()