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,80 @@
1
+ import logging
2
+ import random
3
+
4
+ import numpy as np
5
+
6
+
7
+ class PrimInternal:
8
+ def __init__(self, inds, val, grad=None):
9
+ self.inds = inds
10
+ self.val = val
11
+ self.grad = grad
12
+
13
+ def __str__(self):
14
+ return f"PrimInternal({self.inds})"
15
+
16
+ def __repr__(self):
17
+ return f"PrimInternal({self.inds}, {self.val:.4f})"
18
+
19
+
20
+ def eval_primitives(coords3d, primitives):
21
+ prim_internals = list()
22
+ for primitive in primitives:
23
+ value, gradient = primitive.calculate(coords3d, gradient=True)
24
+ prim_internal = PrimInternal(primitive.indices, value, gradient)
25
+ prim_internals.append(prim_internal)
26
+ return prim_internals
27
+
28
+
29
+ def eval_B(coords3d, primitives):
30
+ prim_internals = eval_primitives(coords3d, primitives)
31
+ return np.array([prim_int.grad for prim_int in prim_internals])
32
+
33
+
34
+ def check_primitives(coords3d, primitives, B=None, thresh=1e-6, logger=None):
35
+ assert len(primitives) > 0
36
+
37
+ def log(msg, level=logging.DEBUG):
38
+ if logger is not None:
39
+ logger.log(level, msg)
40
+
41
+ if B is None:
42
+ B = eval_B(coords3d, primitives)
43
+ G = B.T.dot(B)
44
+ w, v = np.linalg.eigh(G)
45
+ nonzero_inds = np.abs(w) > thresh
46
+ # More coordinates may be expected when collinear atoms are present.
47
+ expected = coords3d.size - 6
48
+ nonzero_num = sum(nonzero_inds)
49
+ missing = expected - nonzero_num
50
+ if missing > 0:
51
+ log(
52
+ "Not enough internal coordinates defined! Expected at least "
53
+ f"{expected} nonzero eigenvalues. Found only {nonzero_num}!"
54
+ )
55
+ nonzero_w = w[nonzero_inds]
56
+ # Condition number
57
+ kappa = abs(nonzero_w.max() / nonzero_w.min())
58
+ log(f"Condition number of B^T.B=G: {kappa:.4e}")
59
+ return missing + 1, kappa
60
+
61
+
62
+ def augment_primitives(missing_prims, coords3d, prim_indices, fragments):
63
+ add_bonds = list()
64
+ add_bends = list()
65
+ add_dihedrals = list()
66
+
67
+ fragment_tpls = [tuple(fragment) for fragment in fragments]
68
+ if len(fragments) > 1:
69
+ bond_inds = prim_indices[0]
70
+ bond_sets = [frozenset(bond) for bond in bond_inds]
71
+ while missing_prims > 0:
72
+ random.shuffle(fragment_tpls)
73
+ frag1, frag2 = fragment_tpls[:2]
74
+ atom1 = random.choice(frag1)
75
+ atom2 = random.choice(frag2)
76
+ bond_set = frozenset((atom1, atom2))
77
+ if (bond_set not in bond_sets) and (bond_set not in add_bonds):
78
+ add_bonds.append(list(bond_set))
79
+ missing_prims -= 1
80
+ return add_bonds, add_bends, add_dihedrals
@@ -0,0 +1,37 @@
1
+ class NeedNewInternalsException(Exception):
2
+
3
+ def __init__(
4
+ self, coords3d, *args, invalid_inds=None, invalid_prims=None, **kwargs
5
+ ):
6
+ super().__init__(*args, **kwargs)
7
+
8
+ self.coords3d = coords3d
9
+ if invalid_inds is None:
10
+ invalid_inds = ()
11
+ self.invalid_inds = invalid_inds
12
+ if invalid_prims is None:
13
+ invalid_prims = ()
14
+ self.invalid_prims = invalid_prims
15
+
16
+
17
+ class RebuiltInternalsException(Exception):
18
+
19
+ def __init__(self, *args, typed_prims=None, **kwargs):
20
+ super().__init__(*args, **kwargs)
21
+
22
+ self.typed_prims = typed_prims
23
+
24
+
25
+ class DifferentPrimitivesException(Exception):
26
+ pass
27
+
28
+
29
+ class DifferentCoordLengthsException(Exception):
30
+ pass
31
+
32
+
33
+ class PrimitiveNotDefinedException(Exception):
34
+
35
+ def __init__(self, typed_prim, *args, **kwargs):
36
+ self.typed_prim = typed_prim
37
+ super().__init__(*args, **kwargs)
@@ -0,0 +1,48 @@
1
+ import itertools as it
2
+
3
+ import numpy as np
4
+
5
+
6
+ def fin_diff_prim(primitive, coords3d, delta=1e-6):
7
+ """Derivatives of a primitive internal gradient wrt its defining
8
+ cartesian coordinates."""
9
+ displacement_inds = [(i, j) for i, j in it.product(primitive.indices, (0, 1, 2))]
10
+
11
+ prim_grads = list()
12
+ for atom_ind, ax_ind in displacement_inds:
13
+ plus = coords3d.copy()
14
+ plus[atom_ind, ax_ind] += delta
15
+ plus_val = primitive.calculate(plus)
16
+ minus = coords3d.copy()
17
+ minus[atom_ind, ax_ind] -= delta
18
+ minus_val = primitive.calculate(minus)
19
+ # Select the appropriate item of the primitive internal gradient
20
+ prim_grad = (plus_val - minus_val) / (2 * delta)
21
+ prim_grads.append(prim_grad)
22
+ prim_grads = np.array(prim_grads)
23
+ return prim_grads
24
+
25
+
26
+ def fin_diff_B(primitive, coords3d, delta=1e-6):
27
+ """Derivatives of a primitive internal gradient wrt its defining
28
+ cartesian coordinates."""
29
+ displacement_inds = [(i, j) for i, j in it.product(primitive.indices, (0, 1, 2))]
30
+
31
+ B_grads = list()
32
+ for grad_atom_ind, grad_ax_ind in displacement_inds:
33
+ # Calculate the derivative of an entry of the Wilson B-matrix.
34
+ for atom_ind, ax_ind in displacement_inds:
35
+ plus = coords3d.copy()
36
+ plus[atom_ind, ax_ind] += delta
37
+ _, plus_val = primitive.calculate(plus, gradient=True)
38
+ plus_val = plus_val.reshape(-1, 3)
39
+ minus = coords3d.copy()
40
+ minus[atom_ind, ax_ind] -= delta
41
+ _, minus_val = primitive.calculate(minus, gradient=True)
42
+ minus_val = minus_val.reshape(-1, 3)
43
+ # Select the appropriate item of the primitive internal gradient
44
+ B_grad = (plus_val[grad_atom_ind, grad_ax_ind]
45
+ - minus_val[grad_atom_ind, grad_ax_ind]) / (2 * delta)
46
+ B_grads.append(B_grad)
47
+ B_grads = np.array(B_grads)
48
+ return B_grads
@@ -0,0 +1,414 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Johannes Steinmetzer 2020
4
+ # As describend in:
5
+ # V. Bakken, T. Helgaker, J. Chem. Phys., 117, 20, 2002
6
+ # [1] https://aip.scitation.org/doi/abs/10.1063/1.1515483
7
+ # [2] https://doi.org/10.1002/(SICI)1096-987X(19960115)17:1<49::AID-JCC5>3.0.CO;2-0
8
+ # [3] TRANSITION-STATE OPTIMIZATION METHODS USING INTERNAL COORDINATES
9
+ # Sandra Rabi, PhD Thesis
10
+
11
+ from collections import namedtuple
12
+ import itertools as it
13
+ import random
14
+ import string
15
+ import textwrap
16
+
17
+ from jinja2 import Template
18
+ import sympy as sym
19
+ from sympy import cse
20
+ from sympy.codegen.ast import Assignment
21
+ from sympy.printing.pycode import pycode, MpmathPrinter
22
+ from sympy.vector import CoordSys3D
23
+ from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray
24
+
25
+
26
+ FuncResult = namedtuple("FuncResult", "d0 d1 d2 f0 f1 f2")
27
+
28
+
29
+ def make_py_func(exprs, args=None, name=None, comment="", use_mpmath=False):
30
+ if args is None:
31
+ args = list()
32
+ if name is None:
33
+ name = "func_" + "".join(
34
+ [random.choice(string.ascii_letters) for i in range(8)]
35
+ )
36
+ arg_strs = [arg.strip() for arg in args.split(",")]
37
+
38
+ is_scalar = not isinstance(exprs, ImmutableDenseNDimArray)
39
+ if is_scalar:
40
+ repls, reduced = cse(exprs)
41
+ reduced = reduced[0]
42
+ else:
43
+ if len(exprs.shape) == 2:
44
+ exprs = it.chain(*exprs)
45
+ repls, reduced = cse(list(exprs))
46
+
47
+ print_func = pycode
48
+ if use_mpmath:
49
+ print_func = MpmathPrinter().doprint
50
+
51
+ assignments = [Assignment(lhs, rhs) for lhs, rhs in repls]
52
+ py_lines = [print_func(as_) for as_ in assignments]
53
+ return_val = print_func(reduced)
54
+
55
+ tpl = Template(
56
+ """
57
+ def {{ name }}({{ args }}):
58
+ {% if comment %}
59
+ \"\"\"{{ comment }}\"\"\"
60
+ {% endif %}
61
+
62
+ {% if use_mpmath %}
63
+ {% for arg in arg_strs %}
64
+ {{ arg }} = mpmath.mpf({{ arg }})
65
+ {% endfor %}
66
+ {% endif %}
67
+
68
+ {% for line in py_lines %}
69
+ {{ line }}
70
+ {% endfor %}
71
+
72
+ {% if is_scalar %}
73
+ return {{ return_val }}
74
+ {% else %}
75
+ return np.array({{ return_val }}, dtype=np.float64)
76
+ {% endif %}
77
+ """,
78
+ trim_blocks=True,
79
+ lstrip_blocks=True,
80
+ )
81
+
82
+ rendered = textwrap.dedent(
83
+ tpl.render(
84
+ name=name,
85
+ args=args,
86
+ py_lines=py_lines,
87
+ return_val=return_val,
88
+ comment=comment,
89
+ is_scalar=is_scalar,
90
+ use_mpmath=use_mpmath,
91
+ arg_strs=arg_strs,
92
+ )
93
+ ).strip()
94
+ return rendered
95
+
96
+
97
+ # def make_deriv_funcs(base_expr, dx, args, names, comments):
98
+ def make_deriv_funcs(base_expr, dx, args, names, comment, use_mpmath=True):
99
+ q_name, d1_name, d2_name = names
100
+ q_comment, d1_comment, d2_comment = [
101
+ comment + add
102
+ for add in [
103
+ "",
104
+ ", first derivative wrt. Cartesians",
105
+ ", 2nd derivative wrt. Cartesians",
106
+ ]
107
+ ]
108
+
109
+ # Actual function
110
+ print(f"\tmpmath: {use_mpmath}")
111
+ print("\tFunction")
112
+ q_func = make_py_func(
113
+ base_expr, args=args, name=q_name, comment=q_comment, use_mpmath=use_mpmath
114
+ )
115
+
116
+ # First derivative
117
+ print("\t1st derivative")
118
+ deriv1 = sym.derive_by_array(base_expr, dx)
119
+ deriv1_func = make_py_func(
120
+ deriv1, args=args, name=d1_name, comment=d1_comment, use_mpmath=use_mpmath
121
+ )
122
+
123
+ # Second derivative
124
+ print("\t2nd derivative")
125
+ deriv2 = sym.derive_by_array(deriv1, dx)
126
+ deriv2_func = make_py_func(
127
+ deriv2, args=args, name=d2_name, comment=d2_comment, use_mpmath=use_mpmath
128
+ )
129
+
130
+ return FuncResult(
131
+ # Expressions
132
+ d0=base_expr,
133
+ d1=deriv1,
134
+ d2=deriv2,
135
+ # Functions
136
+ f0=q_func,
137
+ f1=deriv1_func,
138
+ f2=deriv2_func,
139
+ )
140
+
141
+
142
+ def generate_wilson(generate=None, out_fn="derivatives.py", use_mpmath=False):
143
+ m0, m1, m2, n0, n1, n2, o0, o1, o2, p0, p1, p2 = sym.symbols("m:3 n:3 o:3 p:3")
144
+
145
+ # Coordinate system
146
+ Sys = CoordSys3D("Sys")
147
+ M = Sys.origin.locate_new("M", m0 * Sys.i + m1 * Sys.j + m2 * Sys.k)
148
+ N = Sys.origin.locate_new("N", n0 * Sys.i + n1 * Sys.j + n2 * Sys.k)
149
+ O = Sys.origin.locate_new("O", o0 * Sys.i + o1 * Sys.j + o2 * Sys.k)
150
+ P = Sys.origin.locate_new("P", p0 * Sys.i + p1 * Sys.j + p2 * Sys.k)
151
+
152
+ def bond():
153
+ # Bond/Stretch
154
+ U = M.position_wrt(N)
155
+ q_b = U.magnitude()
156
+ dx_b = (m0, m1, m2, n0, n1, n2)
157
+ args_b = "m0, m1, m2, n0, n1, n2"
158
+ func_result_b = make_deriv_funcs(
159
+ q_b,
160
+ dx_b,
161
+ args_b,
162
+ ("q_b", "dq_b", "d2q_b"),
163
+ "Stretch",
164
+ use_mpmath=use_mpmath,
165
+ )
166
+ return func_result_b
167
+
168
+ def bend():
169
+ # Bend/Angle
170
+ U = M.position_wrt(O)
171
+ V = N.position_wrt(O)
172
+ q_a = sym.acos(U.dot(V) / (U.magnitude() * V.magnitude()))
173
+ dx_a = (m0, m1, m2, o0, o1, o2, n0, n1, n2)
174
+ args_a = "m0, m1, m2, o0, o1, o2, n0, n1, n2"
175
+ func_result_a = make_deriv_funcs(
176
+ q_a,
177
+ dx_a,
178
+ args_a,
179
+ ("q_a", "dq_a", "d2q_a"),
180
+ "Bend",
181
+ use_mpmath=use_mpmath,
182
+ )
183
+ return func_result_a
184
+
185
+ def bend2():
186
+ # atan2 based Bend/Angle
187
+ U = M.position_wrt(O)
188
+ V = N.position_wrt(O)
189
+ q_a2 = sym.atan2(U.cross(V).magnitude(), U.dot(V))
190
+ dx_a2 = (m0, m1, m2, o0, o1, o2, n0, n1, n2)
191
+ args_a2 = "m0, m1, m2, o0, o1, o2, n0, n1, n2"
192
+ func_result_a = make_deriv_funcs(
193
+ q_a2,
194
+ dx_a2,
195
+ args_a2,
196
+ ("q_a2", "dq_a2", "d2q_a2"),
197
+ "Bend2",
198
+ use_mpmath=use_mpmath,
199
+ )
200
+ return func_result_a
201
+
202
+ def dihedral():
203
+ # Dihedral/Torsion
204
+ U = M.position_wrt(O)
205
+ W = P.position_wrt(O)
206
+ V = N.position_wrt(P)
207
+ U_ = U.normalize()
208
+ W_ = W.normalize()
209
+ V_ = V.normalize()
210
+ phi_u = sym.acos(U_.dot(W_))
211
+ phi_v = sym.acos(-W_.dot(V_))
212
+ q_d = sym.acos(
213
+ U_.cross(W_).dot(V_.cross(W_)) / (sym.sin(phi_u) * sym.sin(phi_v))
214
+ )
215
+ dx_d = (m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2)
216
+ args_d = "m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2"
217
+ func_result_d = make_deriv_funcs(
218
+ q_d,
219
+ dx_d,
220
+ args_d,
221
+ ("q_d", "dq_d", "d2q_d"),
222
+ "Torsion",
223
+ use_mpmath=use_mpmath,
224
+ )
225
+ return func_result_d
226
+
227
+ def dihedral2():
228
+ # atan2 based Dihedral/Torsion
229
+ U1 = O.position_wrt(M)
230
+ U2 = P.position_wrt(O)
231
+ U3 = N.position_wrt(P)
232
+ cross_U2U3 = U2.cross(U3)
233
+ q_d2 = sym.atan2(
234
+ (U2.magnitude() * U1).dot(cross_U2U3), cross_U2U3.dot(U1.cross(U2))
235
+ )
236
+ dx_d2 = (m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2)
237
+ args_d2 = "m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2"
238
+ func_result_d = make_deriv_funcs(
239
+ q_d2,
240
+ dx_d2,
241
+ args_d2,
242
+ ("q_d2", "dq_d2", "d2q_d2"),
243
+ "Torsion2",
244
+ use_mpmath=use_mpmath,
245
+ )
246
+ return func_result_d
247
+
248
+ def robust_dihedral1():
249
+ # First component of robust dihedral
250
+ # See Eq. (3.1) in [3]
251
+ U = M.position_wrt(O)
252
+ V = N.position_wrt(P)
253
+ U_ = U.normalize()
254
+ V_ = V.normalize()
255
+ q_rd1 = U_.dot(V_)
256
+ dx_rd1 = (m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2)
257
+ args_rd1 = "m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2"
258
+ func_result_rd1 = make_deriv_funcs(
259
+ q_rd1,
260
+ dx_rd1,
261
+ args_rd1,
262
+ ("q_rd1", "dq_rd1", "d2q_rd1"),
263
+ "RobustTorsion1",
264
+ use_mpmath=use_mpmath,
265
+ )
266
+ return func_result_rd1
267
+
268
+ def robust_dihedral2():
269
+ # Second component of robust dihedral
270
+ # See Eq. (3.2) in [3]
271
+ U = M.position_wrt(O)
272
+ W = P.position_wrt(O)
273
+ V = N.position_wrt(P)
274
+ U_ = U.normalize()
275
+ W_ = W.normalize()
276
+ V_ = V.normalize()
277
+ q_rd2 = W_.dot(U_.cross(V_))
278
+ dx_rd2 = (m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2)
279
+ args_rd2 = "m0, m1, m2, o0, o1, o2, p0, p1, p2, n0, n1, n2"
280
+ func_result_rd2 = make_deriv_funcs(
281
+ q_rd2,
282
+ dx_rd2,
283
+ args_rd2,
284
+ ("q_rd2", "dq_rd2", "d2q_rd2"),
285
+ "RobustTorsion2",
286
+ use_mpmath=use_mpmath,
287
+ )
288
+ return func_result_rd2
289
+
290
+ def linear_bend():
291
+ # Linear Bend
292
+ U = M.position_wrt(O)
293
+ V = N.position_wrt(O)
294
+ W = P.position_wrt(Sys)
295
+ q_lb = W.dot(U.cross(V)) / (U.magnitude() * V.magnitude())
296
+ dx_lb = (m0, m1, m2, o0, o1, o2, n0, n1, n2)
297
+ # Additional args, as we also supply an orthogonal direction
298
+ args_lb = "m0, m1, m2, o0, o1, o2, n0, n1, n2, p0, p1, p2"
299
+ func_result_lb = make_deriv_funcs(
300
+ q_lb,
301
+ dx_lb,
302
+ args_lb,
303
+ ("q_lb", "dq_lb", "d2q_lb"),
304
+ "Linear Bend",
305
+ use_mpmath=use_mpmath,
306
+ )
307
+ return func_result_lb
308
+
309
+ def out_of_plane():
310
+ U = M.position_wrt(P)
311
+ V = N.position_wrt(P)
312
+ W = O.position_wrt(P)
313
+
314
+ U_ = U.normalize()
315
+ W_ = W.normalize()
316
+ V_ = V.normalize()
317
+
318
+ Z = U_.cross(V_) + V_.cross(W_) + W_.cross(U_)
319
+ Z_ = Z.normalize()
320
+
321
+ q_oop = Z_.dot(U_)
322
+
323
+ dx_oop = (m0, m1, m2, n0, n1, n2, o0, o1, o2, p0, p1, p2)
324
+ args_oop = "m0, m1, m2, n0, n1, n2, o0, o1, o2, p0, p1, p2"
325
+ func_result_oop = make_deriv_funcs(
326
+ q_oop,
327
+ dx_oop,
328
+ args_oop,
329
+ ("q_oop", "dq_oop", "d2q_oop"),
330
+ "OutOfPlane",
331
+ use_mpmath=use_mpmath,
332
+ )
333
+ return func_result_oop
334
+
335
+ def linear_displacement():
336
+ U = M.position_wrt(O)
337
+ V = N.position_wrt(O)
338
+ W = N.position_wrt(M)
339
+ U_ = U.normalize()
340
+ V_ = V.normalize()
341
+ W_ = W.normalize()
342
+
343
+ # Vector for cross product. For the complement X should correspond
344
+ # to the first orthogonal direction (X = W_.cross(X)).
345
+ X = P.position_wrt(Sys)
346
+ # Orthogonal direction
347
+ Y = W_.cross(X)
348
+ Y_ = Y.normalize()
349
+
350
+ q_ld = Y_.dot(U_) + Y_.dot(V_)
351
+ dx_ld = (m0, m1, m2, o0, o1, o2, n0, n1, n2)
352
+ # Additional args, as we also supply an orthogonal direction
353
+ args_ld = "m0, m1, m2, o0, o1, o2, n0, n1, n2, p0, p1, p2"
354
+ func_result_ld = make_deriv_funcs(
355
+ q_ld,
356
+ dx_ld,
357
+ args_ld,
358
+ ("q_ld", "dq_ld", "d2q_ld"),
359
+ "Linear Displacement",
360
+ use_mpmath=use_mpmath,
361
+ )
362
+ return func_result_ld
363
+
364
+ if generate is None:
365
+ generate = (
366
+ "bond",
367
+ "bend",
368
+ "bend2",
369
+ "dihedral",
370
+ "dihedral2",
371
+ "robust_dihedral1",
372
+ "robust_dihedral2",
373
+ "linear_bend",
374
+ "out_of_plane",
375
+ "linear_displacement",
376
+ )
377
+
378
+ avail_funcs = {
379
+ "bond": bond,
380
+ "bend": bend,
381
+ "bend2": bend2,
382
+ "dihedral": dihedral,
383
+ "dihedral2": dihedral2,
384
+ "robust_dihedral1": robust_dihedral1,
385
+ "robust_dihedral2": robust_dihedral2,
386
+ "linear_bend": linear_bend,
387
+ "out_of_plane": out_of_plane,
388
+ "linear_displacement": linear_displacement,
389
+ }
390
+ funcs = [avail_funcs[key] for key in generate]
391
+ func_results = list()
392
+ for name, func in zip(generate, funcs):
393
+ print(f"Generating expressions for: '{name}'")
394
+ func_res = func()
395
+ func_results.append(func_res)
396
+
397
+ import_str = "import mpmath" if use_mpmath else "import math"
398
+ if out_fn:
399
+ with open(out_fn, "w") as handle:
400
+ handle.write(f"{import_str}\n\nimport numpy as np\n\n\n")
401
+ for fr in func_results:
402
+ handle.write(fr.f0 + "\n\n\n")
403
+ handle.write(fr.f1 + "\n\n\n")
404
+ handle.write(fr.f2 + "\n\n\n")
405
+ print(f"Wrote generated code to '{out_fn}'")
406
+
407
+ return func_results
408
+
409
+
410
+ if __name__ == "__main__":
411
+ generate_wilson(out_fn="derivatives.py", use_mpmath=False)
412
+ # print()
413
+ generate_wilson(out_fn="mp_derivatives.py", use_mpmath=True)
414
+ # generate_wilson(out_fn="lindisp.py", use_mpmath=False)