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,297 @@
1
+ from collections import namedtuple
2
+ import logging
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.config import T_DEFAULT
7
+ from pysisyphus.constants import FORCE2ACC
8
+ from pysisyphus.dynamics.helpers import (
9
+ kinetic_energy_from_velocities,
10
+ temperature_for_kinetic_energy,
11
+ energy_forces_getter_closure,
12
+ kinetic_energy_for_temperature,
13
+ remove_com_velocity,
14
+ )
15
+ from pysisyphus.dynamics.thermostats import csvr_closure, csvr_closure_2, berendsen_closure
16
+ from pysisyphus.dynamics.rattle import rattle_closure
17
+ from pysisyphus.helpers import check_for_end_sign
18
+ from pysisyphus.helpers_pure import log
19
+ from pysisyphus.io.hdf5 import get_h5_group
20
+
21
+ logger = logging.getLogger("dynamics")
22
+
23
+ MDResult = namedtuple(
24
+ "MDResult",
25
+ "coords t_ps step terminated T E_tot",
26
+ )
27
+
28
+ THERMOSTATS = {
29
+ "csvr": csvr_closure,
30
+ "csvr_2": csvr_closure_2,
31
+ "berendsen": berendsen_closure,
32
+ }
33
+
34
+
35
+ def get_data_model(atoms, dump_steps):
36
+ coord_size = 3 * len(atoms)
37
+ _1d = (dump_steps,)
38
+ _2d = (dump_steps, coord_size)
39
+
40
+ data_model = {
41
+ "cart_coords": _2d,
42
+ "step": _1d,
43
+ "energy_tot": _1d,
44
+ "energy_pot" : _1d,
45
+ "energy_kin": _1d,
46
+ "energy_conserved": _1d,
47
+ "T": _1d,
48
+ "T_avg": _1d,
49
+ "velocity": _2d,
50
+ }
51
+
52
+ return data_model
53
+
54
+
55
+ def md(
56
+ geom,
57
+ v0,
58
+ steps,
59
+ dt,
60
+ remove_com_v=True,
61
+ thermostat=None,
62
+ T=T_DEFAULT,
63
+ timecon=100,
64
+ term_funcs=None,
65
+ constraints=None,
66
+ constraint_kwargs=None,
67
+ gaussians=None,
68
+ verbose=True,
69
+ print_stride=50,
70
+ dump_stride=None,
71
+ h5_group_name="run",
72
+ ):
73
+ """Velocity verlet integrator.
74
+
75
+ Parameters
76
+ ----------
77
+ geom : Geometry
78
+ The system for which the dynamics are to be run.
79
+ v0 : np.array, floats
80
+ Initial velocities in Bohr/fs.
81
+ steps : float
82
+ Number of simulation steps.
83
+ dt : float
84
+ Timestep in fs.
85
+ remove_com_v : bool, default=True
86
+ Remove center-of-mass velocity.
87
+ thermostat : str, optional, default None
88
+ Which and whether to use a thermostat.
89
+ T : float, optional, default=None
90
+ Desired temperature in thermostated runs.
91
+ timecon : float
92
+ Timeconsanst of the thermostat in fs.
93
+ term_funcs : dict, optional
94
+ Iterable of functions that are called with the atomic
95
+ coordinates in every MD cycle and result in termination
96
+ constraints : 2d iterable, optional
97
+ 2D iterable containing atom indices describing constrained
98
+ bond lengths.
99
+ of the MD integration when they evaluate to true.
100
+ constraint_kwargs : dict, optional
101
+ Keyword arguments for the constraint algorithm.
102
+ gaussians: list, optional, default=None
103
+ List of Gaussians to be used in a metadynamics run.
104
+ verbose : bool, default=True
105
+ Do additional printing when True.
106
+ print_stride : int, default=50
107
+ Report every n-th step.
108
+ dump_stride : int, default=None
109
+ If given, MD data will be dumped to a HDF5 file every n-th step.
110
+ h5_group_name = str, optional
111
+ Name of the HDF5 group, used for dumping.
112
+ """
113
+
114
+ assert geom.coord_type == "cart"
115
+
116
+ if term_funcs is None:
117
+ term_funcs = dict()
118
+
119
+ # if dump_stride:
120
+ # dump_steps = steps // dump_stride
121
+ # data_model = get_data_model(geom.atoms, dump_steps)
122
+ # h5_group = get_h5_group("md.h5", h5_group_name, data_model, reset=True)
123
+ # h5_group.attrs["atoms"] = geom.atoms
124
+ # h5_group.attrs["dt"] = dt
125
+ # h5_group.attrs["steps"] = steps
126
+ # h5_group.attrs["masses"] = geom.masses
127
+ # h5_group.attrs["T_target"] = T
128
+
129
+ if verbose:
130
+ t_ps = steps * dt * 1e-3 # Total simulation time
131
+ print(f"Doing {steps} steps of {dt:.4f} fs for a total of {t_ps:.2f} ps.\n")
132
+
133
+ energy_forces_getter = energy_forces_getter_closure(geom)
134
+
135
+ if gaussians is None:
136
+ gaussians = tuple()
137
+ gau_centers = list()
138
+ gau_center_num = np.zeros(len(gaussians), dtype=int)
139
+ for _, gaussian, gau_stride in gaussians:
140
+ num_centers = steps // gau_stride
141
+ gau_centers.append(np.zeros(num_centers))
142
+
143
+ def update_gaussians(step, coords):
144
+ for i, (gau_key, gaussian, gau_stride) in enumerate(gaussians):
145
+ if (step + 1) % gau_stride == 0:
146
+ new_center = gaussian.colvar.value(coords.reshape(-1, 3))
147
+ gau_centers[i][gau_center_num[i]] = new_center
148
+ gau_center_num[i] += 1
149
+ log(
150
+ logger,
151
+ f"Added {gau_center_num[i]: >6d}. '{gau_key}' Gaussian in step {step}.",
152
+ )
153
+ gaussian.dump(step, gaussian.s, gaussian.w, new_center)
154
+
155
+ def gaussian_wrapper(coords):
156
+ E_pot, forces = energy_forces_getter(geom.coords)
157
+ for i, (_, gaussian, _) in enumerate(gaussians):
158
+ center_num = gau_center_num[i]
159
+ gau_pot, gau_grad = gaussian.eval(coords, gau_centers[i][:center_num])
160
+ # print("\tgau_pot", gau_pot)
161
+ gau_forces = -gau_grad.flatten()
162
+ E_pot += gau_pot
163
+ forces += gau_forces
164
+ return E_pot, forces
165
+
166
+ if constraint_kwargs is None:
167
+ constraint_kwargs = dict()
168
+
169
+ # Fixed degrees of freedom
170
+ fixed_dof = 0
171
+ if remove_com_v:
172
+ print("Removing center-of-mass velocity.")
173
+ fixed_dof += 3
174
+ constrained_md = constraints is not None
175
+ # Get RATTLE function from closure for constrained MD
176
+ if constrained_md:
177
+ fixed_dof += len(constraints)
178
+ rattle = rattle_closure(
179
+ geom,
180
+ constraints,
181
+ dt,
182
+ energy_forces_getter=energy_forces_getter,
183
+ **constraint_kwargs,
184
+ )
185
+ print(f"Fixed degrees of freedom: {fixed_dof}")
186
+ dof = len(geom.coords) - fixed_dof
187
+
188
+ if thermostat is not None:
189
+ sigma = kinetic_energy_for_temperature(len(geom.atoms), T, fixed_dof=fixed_dof)
190
+ thermo_func = THERMOSTATS[thermostat](sigma, dof, dt=dt, tau=timecon)
191
+ # In amu
192
+ masses = geom.masses
193
+ masses_rep = geom.masses_rep
194
+
195
+ x = geom.cart_coords
196
+ # v is given in Bohr/fs
197
+ v = v0
198
+ a_prev = np.zeros_like(x)
199
+ xs = list()
200
+ Ts = list()
201
+ E_tots = list()
202
+
203
+ E_pot, forces = energy_forces_getter(geom.coords)
204
+
205
+ t_cur = 0
206
+ terminate = False
207
+ terminate_key = None
208
+ T_avg = 0
209
+ log(logger, f"Running MD with Δt={dt:.2f} fs for {steps} steps.")
210
+ print()
211
+ thermo_corr = 0.0
212
+ for step in range(steps):
213
+ xs.append(x.copy())
214
+
215
+ E_kin = kinetic_energy_from_velocities(masses, v.reshape(-1, 3))
216
+ T = temperature_for_kinetic_energy(len(masses), E_kin, fixed_dof=fixed_dof)
217
+ T_avg += T
218
+ Ts.append(T)
219
+ E_tot = E_pot + E_kin
220
+ E_tots.append(E_tot)
221
+ E_conserved = E_pot + E_kin - thermo_corr
222
+
223
+ status_msg = (
224
+ f"Step {step:06d} {t_cur*1e-3: >6.2f} ps E={E_tot: >8.6f} E_h "
225
+ f"T={T: >8.2f} K <T>={T_avg/(step+1): >8.2f} K"
226
+ )
227
+ if step % print_stride == 0:
228
+ log(logger, status_msg)
229
+ if verbose:
230
+ print(status_msg)
231
+
232
+ # if dump_stride and (step % dump_stride == 0):
233
+ # ind = step // dump_stride
234
+ # h5_group["step"][ind] = step
235
+ # h5_group["cart_coords"][ind] = x
236
+ # h5_group["velocity"][ind] = v
237
+ # h5_group["energy_tot"][ind] = E_tot
238
+ # h5_group["energy_pot"][ind] = E_pot
239
+ # h5_group["energy_kin"][ind] = E_kin
240
+ # h5_group["energy_conserved"][ind] = E_conserved
241
+ # h5_group["T"][ind] = T
242
+ # h5_group["T_avg"][ind] = T_avg / (step + 1)
243
+
244
+ if thermostat:
245
+ alpha = thermo_func(E_kin)
246
+ thermo_corr += (alpha**2 - 1) * E_kin
247
+ v *= alpha
248
+
249
+ update_gaussians(step, x)
250
+
251
+ # RATTLE algorithm
252
+ if constrained_md:
253
+ x, v, E_pot, forces = rattle(x, v, forces)
254
+ # Simple Velocity-Verlet integration
255
+ else:
256
+ # E_pot, forces = energy_forces_getter(geom.coords)
257
+ E_pot, forces = gaussian_wrapper(geom.coords)
258
+ # Acceleration, convert from Hartree / (Bohr * amu) to Bohr/fs²
259
+ a = forces / masses_rep * FORCE2ACC
260
+ v += 0.5 * (a + a_prev) * dt
261
+
262
+ if remove_com_v:
263
+ v = remove_com_velocity(v.reshape(-1, 3), masses).flatten()
264
+ # v*dt = Bohr/fs * fs -> Bohr
265
+ # a*dt**2 = Bohr/fs² * fs² -> Bohr
266
+ x += v * dt + 0.5 * a * dt ** 2
267
+ a_prev = a
268
+
269
+ # Update coordinates
270
+ geom.coords = x
271
+
272
+ for name, func in term_funcs.items():
273
+ if func(x.reshape(-1, 3)):
274
+ terminate = True
275
+ terminate_key = name
276
+ break
277
+ if terminate:
278
+ log(logger, f"Termination function '{name}' evaluted to True. Breaking.")
279
+ break
280
+
281
+ if check_for_end_sign():
282
+ break
283
+
284
+ # Advance time
285
+ t_cur += dt
286
+ log(logger, "")
287
+
288
+ md_result = MDResult(
289
+ coords=np.array(xs),
290
+ t_ps=t_cur * 1e-3,
291
+ step=step,
292
+ terminated=terminate_key,
293
+ T=np.array(Ts),
294
+ E_tot=np.array(E_tots),
295
+ )
296
+
297
+ return md_result
@@ -0,0 +1,256 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.xyzloader import make_trj_str
4
+ from pysisyphus.Geometry import get_trans_rot_projector
5
+ from pysisyphus.constants import BOHR2ANG, KBAU, VELO2E
6
+
7
+
8
+ def dump_coords(atoms, coords, trj_fn):
9
+ coords = np.array(coords)
10
+ coords = coords.reshape(-1, len(atoms), 3) * BOHR2ANG
11
+ trj_str = make_trj_str(atoms, coords)
12
+
13
+ with open(trj_fn, "w") as handle:
14
+ handle.write(trj_str)
15
+
16
+
17
+ def kinetic_energy_from_velocities(masses, velocities):
18
+ """Kinetic energy for given velocities and masses.
19
+
20
+ Parameters
21
+ ----------
22
+ masses : 1d array, shape (number of atoms, )
23
+ Atomic masses in amu.
24
+ velocities : 2d array, (number of atoms, 3)
25
+ Atomic velocities in Bohr/fs.
26
+
27
+ Returns
28
+ -------
29
+ E_kin : float
30
+ Kinetic energy in Hartree.
31
+ """
32
+ return np.sum(masses[:,None] / 2 * velocities**2) * VELO2E
33
+
34
+
35
+ def kinetic_energy_for_temperature(atom_number, T, fixed_dof=0):
36
+ """Kinetic energy for given temperature and number of atoms.
37
+
38
+ Each atom has three degrees of freedom (1/2 * 3 == 3/2).
39
+
40
+ Parameters
41
+ ----------
42
+ atom_number : int
43
+ Number of atoms. Each atom has three degrees of freedom.
44
+ T : float
45
+ Temperature in Kelvin.
46
+ fixed_dof : int, optional, default=0
47
+ Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
48
+ velocity is removed.
49
+
50
+ Returns
51
+ -------
52
+ E_kin : float
53
+ Kinetic energy in Hartree.
54
+ """
55
+ return (3*atom_number - fixed_dof) / 2 * T * KBAU
56
+
57
+
58
+ def temperature_for_kinetic_energy(atom_number, E_kin, fixed_dof=0):
59
+ """Temperature for given kinetic energy and atom number.
60
+
61
+ Each atom has three degrees of freedom (1/2 * 3 == 3/2).
62
+
63
+ Parameters
64
+ ----------
65
+ atom_number : int
66
+ Number of atoms. Each atom has three degrees of freedom.
67
+ E_kin : float
68
+ Kinetic energy in Hartree.
69
+ fixed_dof : int, optional, default=0
70
+ Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
71
+ velocity is removed.
72
+
73
+ Returns
74
+ -------
75
+ Temperature : float
76
+ Temperature in Kelvin.
77
+ """
78
+ return 2 * E_kin / ((3*atom_number - fixed_dof) * KBAU)
79
+
80
+
81
+ def remove_com_velocity(v, masses, keep_norm=True):
82
+ """Remove center-of-mass velocity.
83
+
84
+ Returned units vary with the given input units.
85
+
86
+ Parameters
87
+ ----------
88
+ v : np.array, 2d, shape (number of atoms, 3)
89
+ Velocities.
90
+ masses : np.array, 1d, shape (number of atoms, )
91
+ Atomic masses.
92
+ keep_norm : bool, default=True
93
+ Whether to rescale v to its original norm, after removal of v_com.
94
+
95
+ Returns
96
+ -------
97
+ v : np.array
98
+ Velocities without center-of-mass velocity.
99
+ """
100
+ org_norm = np.linalg.norm(v)
101
+ v_com = (v * masses[:,None] / np.sum(masses)).sum(axis=0)
102
+ v -= v_com
103
+ if keep_norm:
104
+ v /= np.linalg.norm(v) / org_norm
105
+ return v
106
+
107
+
108
+ def scale_velocities_to_temperatue(masses, v, T_desired, fixed_dof=0):
109
+ """Scale velocities to a given temperature.
110
+
111
+ Parameters
112
+ ----------
113
+ masses : np.array, 1d, shape (number of atoms, )
114
+ Atomic masses in amu.
115
+ v : np.array, 2d, shape (number of atoms, 3)
116
+ (Unscaled) velocities in Bohr/fs.
117
+ T_desired : float
118
+ Desired temperature in Kelvin.
119
+ fixed_dof : int, optional, default=0
120
+ Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
121
+ velocity is removed.
122
+
123
+ Returns
124
+ -------
125
+ v : np.array, 2d, shape (number of atoms, 3)
126
+ Scaled velocities in Bohr/fs.
127
+ """
128
+
129
+ E_ref = kinetic_energy_for_temperature(len(masses), T_desired,
130
+ fixed_dof=fixed_dof) # in Hartree
131
+ E_cur = kinetic_energy_from_velocities(masses, v) # in Hartree
132
+ scale = (E_ref / E_cur)**0.5
133
+ v *= scale
134
+ # E_now = kinetic_energy_from_velocities(masses, v)
135
+ # np.testing.assert_allclose(E_now, E_ref)
136
+ return v
137
+
138
+
139
+ def scale_velocities_to_energy(masses, v, E_desired):
140
+ """Scale velocities to a given temperature.
141
+
142
+ Parameters
143
+ ----------
144
+ masses : np.array, 1d, shape (number of atoms, )
145
+ Atomic masses in amu.
146
+ v : np.array, 2d, shape (number of atoms, 3)
147
+ (Unscaled) velocities in Bohr/fs.
148
+ E_desired : float
149
+ Desired kinetic energy in Hartree.
150
+
151
+ Returns
152
+ -------
153
+ v : np.array, 2d, shape (number of atoms, 3)
154
+ Scaled velocities in Bohr/fs.
155
+ """
156
+
157
+ E_cur = kinetic_energy_from_velocities(masses, v) # in Hartree
158
+ scale = (E_desired / E_cur)**0.5
159
+ v *= scale
160
+ return v
161
+
162
+
163
+ def unscaled_velocity_distribution(masses, T, seed=None):
164
+ """
165
+ ρ ∝ exp(- v² * m / (2 * kT))
166
+ ln(ρ) ∝ - 1/2 * v² * m / kT
167
+ v² ∝ -2 * ln(ρ) * kT / m
168
+ v ∝ ±(-2 * ln(ρ) * kT / m)**0.5
169
+ v ∝ ±(-2 * k)**0.5 * (ln(ρ) * T / m)**0.5
170
+
171
+ The first term of the RHS is constant. As we later scale the
172
+ velocities we neglect it. Don't use these velocities unscaled!
173
+
174
+ v ∝ ±(ln(ρ) * T / m)**0.5
175
+ """
176
+
177
+ if seed is not None:
178
+ np.random.seed(seed)
179
+
180
+ ps = np.random.standard_normal((len(masses), 3))
181
+ v = ps * np.sqrt(T / masses[:,None])
182
+ return v
183
+
184
+
185
+ def get_mb_velocities(masses, cart_coords, T, remove_com_v=True, remove_rot_v=True,
186
+ seed=None):
187
+ """Initial velocities from Maxwell-Boltzmann distribution.
188
+
189
+ Parameters
190
+ ----------
191
+ masses : np.array, 1d, shape (number of atoms, )
192
+ Atomic masses in amu.
193
+ cart_coords : iterable, 1d, shape (3 * number of atoms, )
194
+ Atomic cartesian coordinates. Needed for removal of rotation.
195
+ T : float
196
+ Temperature in Kelvin.
197
+ remove_com_v : bool, default=True, optional
198
+ Whether to remove center-of-mass velocity.
199
+ remove_rot_v : bool, default=True, optional
200
+ Whether to remove rotational velocity.
201
+ seed : int, default=None, optional
202
+ Seed for the random-number-generator.
203
+
204
+ Returns
205
+ -------
206
+ v : np.array, 2d, shape (number of atoms, 3)
207
+ Initial velocities in Bohr/fs.
208
+ """
209
+
210
+ masses = np.array(masses)
211
+
212
+ # Initial velocities
213
+ v = unscaled_velocity_distribution(masses, T, seed=seed)
214
+
215
+ if (len(masses) == 1) and remove_com_v:
216
+ raise Exception("Removing COM velocity with only 1 atom is a bad idea!")
217
+
218
+ fixed_dof = 0
219
+ # Remove center-of-mass velocity
220
+ if remove_com_v:
221
+ v = remove_com_velocity(v, masses)
222
+ fixed_dof += 3
223
+
224
+ if remove_rot_v:
225
+ # Right now this also removes the translational components
226
+ P = get_trans_rot_projector(cart_coords, masses, full=True)
227
+ v = P.dot(v.flatten()).reshape(-1, 3)
228
+ fixed_dof = 6
229
+
230
+ # In Bohr/fs
231
+ v = scale_velocities_to_temperatue(masses, v, T, fixed_dof=fixed_dof)
232
+
233
+ return v
234
+
235
+
236
+ def get_mb_velocities_for_geom(geom, T, remove_com_v=True, remove_rot_v=True,
237
+ seed=None):
238
+ """Initial velocities from Maxwell-Boltzmann distribution.
239
+
240
+ See 'get_mb_velocities' for explanation.
241
+ """
242
+
243
+ return get_mb_velocities(geom.masses, geom.cart_coords, T,
244
+ remove_com_v=remove_com_v,
245
+ remove_rot_v=remove_rot_v,
246
+ seed=seed,
247
+ )
248
+
249
+
250
+ def energy_forces_getter_closure(geom):
251
+ def energy_forces_getter(coords):
252
+ results = geom.get_energy_and_forces_at(coords)
253
+ energy = results["energy"]
254
+ forces = results["forces"]
255
+ return energy, forces
256
+ return energy_forces_getter
@@ -0,0 +1,105 @@
1
+ import numpy as np
2
+
3
+
4
+ def lincs_closure(geom, constraints, order=4):
5
+ """
6
+ Drop conn_nums and keep conns_ in a list of list, instead of an array.
7
+ We could do everything with
8
+ for i, conn_constr in enumerate(conns)
9
+ pass
10
+ instead of the pseudo-code way as given in the paper.
11
+ """
12
+ # Number of constraints
13
+ K = len(constraints)
14
+ # Inverse atom masses
15
+ inv_masses = 1 / geom.masses
16
+
17
+ # List of constraint sets
18
+ constraint_sets = [set(c) for c in constraints]
19
+ constraints = np.array(constraints, dtype=int)
20
+ # Indices of the atoms that make up the bond constraints
21
+ atom_1, atom_2 = constraints.T
22
+
23
+ # Original bond lengths
24
+ lengths = np.linalg.norm(geom.coords3d[atom_1] - geom.coords3d[atom_2], axis=1)
25
+
26
+ # Determine number of constraints that are connected to every constraint
27
+ conn_nums = np.zeros(K, dtype=int)
28
+ conns_ = [list() for _ in range(K)]
29
+ for i, con_1 in enumerate(constraint_sets):
30
+ for j, con_2 in enumerate(constraint_sets):
31
+ if i == j:
32
+ continue
33
+
34
+ if con_1 & con_2:
35
+ conn_nums[i] += 1
36
+ conns_[i].append(j)
37
+ # Maximum number of connected constraints
38
+ c_max = conn_nums.max()
39
+ S_diag = 1 / np.sqrt(inv_masses[atom_1] + inv_masses[atom_2])
40
+
41
+ # Array containing the indices of the connected constraints for every constraint
42
+ conns = np.zeros((K, c_max), dtype=int)
43
+ for i, c in enumerate(conns_):
44
+ conns[i, :len(c)] = c
45
+
46
+ coefs = np.zeros((K, c_max))
47
+ signs = {
48
+ True: -1,
49
+ False: 1,
50
+ }
51
+ for i, con_1 in enumerate(constraint_sets):
52
+ for j in range(c_max):
53
+ conns_ij = conns[i, j]
54
+ sign = signs[(atom_1[i] == atom_1[conns_ij]) or (atom_2[i] == atom_2[conns_ij])]
55
+ # Connected atom
56
+ c = tuple(con_1 & constraint_sets[conns_ij])
57
+ assert len(c) == 1
58
+ c = int(c[0])
59
+ coefs[i, j] = sign * inv_masses[c] * S_diag[i] * S_diag[conns_ij]
60
+
61
+ def solve(rhs, sol, new_coords3d, A, B):
62
+ w = 1
63
+ for _ in range(order):
64
+ for i, _ in enumerate(constraints):
65
+ rhs[w, i] = 0.
66
+ for j in range(conn_nums[i]):
67
+ # rhs[w, i] += A[i, j] * rhs[2-w, conns_[i][j]]
68
+ rhs[w, i] += A[i, j] * rhs[2-w, conns[i, j]]
69
+ sol[i] += rhs[w, i]
70
+ w = 2 - w
71
+
72
+ for i, (a1, a2) in enumerate(constraints):
73
+ new_coords3d[a1] -= inv_masses[a1] * S_diag[i] * sol[i] * B[i].sum()
74
+ new_coords3d[a2] += inv_masses[a2] * S_diag[i] * sol[i] * B[i].sum()
75
+
76
+ def lincs(prev_coords3d, new_coords3d):
77
+ # Calculate constraint directions
78
+ B = prev_coords3d[atom_1] - prev_coords3d[atom_2]
79
+ B /= np.linalg.norm(B, axis=1)[:, None]
80
+ print("B", B)
81
+
82
+ A = np.zeros((K, c_max))
83
+ rhs = np.zeros((2, K))
84
+ sol = np.zeros(K)
85
+
86
+ for i, (a1, a2) in enumerate(constraints):
87
+ print(i, a1, a2)
88
+ for j, k in enumerate(conns[i]):
89
+ A[i, j] = coefs[i, j] * (B[i] * B[k]).sum()
90
+
91
+ rhs[0, i] = S_diag[i] * ((B[i] * (new_coords3d[a1] - new_coords3d[a2])).sum() - lengths[i])
92
+ sol[i] = rhs[0, i]
93
+ solve(rhs, sol, new_coords3d, A, B)
94
+
95
+ # Correction for rotational lenghthening
96
+ for i, (a1, a2) in enumerate(constraints):
97
+ length_i = lengths[i]
98
+ p = (2 * length_i**2 - (-(new_coords3d[a1] - new_coords3d[a2])**2).sum())**0.5
99
+ rhs[0, i] = S_diag[i] * (length_i - p)
100
+ sol[i] = rhs[0, i]
101
+
102
+ solve(rhs, sol, new_coords3d, A, B)
103
+ # import pdb; pdb.set_trace()
104
+ return new_coords3d
105
+ return lincs