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,59 @@
1
+ # [1] Transition-State Optimization Methods using Internal Coordinates
2
+ # https://macsphere.mcmaster.ca/handle/11375/15450?mode=full
3
+ # Rabi, 2014, Phd Thesis
4
+
5
+ import numpy as np
6
+
7
+ from pysisyphus.intcoords.Primitive import Primitive
8
+ from pysisyphus.intcoords.derivatives import (
9
+ q_rd1,
10
+ dq_rd1,
11
+ d2q_rd1,
12
+ q_rd2,
13
+ dq_rd2,
14
+ d2q_rd2,
15
+ )
16
+
17
+
18
+ class RobustTorsion1(Primitive):
19
+ @staticmethod
20
+ def _weight(atoms, coords3d, indices, f_damping):
21
+ return 1.0
22
+
23
+ @staticmethod
24
+ def _calculate(coords3d, indices, gradient=False):
25
+ args = coords3d[indices].flatten()
26
+ val = q_rd1(*args)
27
+
28
+ if gradient:
29
+ row = np.zeros_like(coords3d)
30
+ grad = dq_rd1(*args).reshape(-1, 3)
31
+ row[indices] = grad
32
+ return val, row.flatten()
33
+ return val
34
+
35
+ @staticmethod
36
+ def _jacobian(coords3d, indices):
37
+ return d2q_rd1(*coords3d[indices].flatten())
38
+
39
+
40
+ class RobustTorsion2(Primitive):
41
+ @staticmethod
42
+ def _weight(atoms, coords3d, indices, f_damping):
43
+ return 1.0
44
+
45
+ @staticmethod
46
+ def _calculate(coords3d, indices, gradient=False):
47
+ args = coords3d[indices].flatten()
48
+ val = q_rd2(*args)
49
+
50
+ if gradient:
51
+ row = np.zeros_like(coords3d)
52
+ grad = dq_rd2(*args).reshape(-1, 3)
53
+ row[indices] = grad
54
+ return val, row.flatten()
55
+ return val
56
+
57
+ @staticmethod
58
+ def _jacobian(coords3d, indices):
59
+ return d2q_rd2(*coords3d[indices].flatten())
@@ -0,0 +1,147 @@
1
+ # [1] http://dx.doi.org/10.1063/1.4952956
2
+ # Lee-Ping Wang, 2016
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.intcoords.Primitive import Primitive
7
+ from pysisyphus.linalg import eigvec_grad, rot_quaternion
8
+
9
+
10
+ def compare_to_geometric(c3d, ref_c3d, dR, dF, dqdx, dvdx, atol=1e-14):
11
+ from geometric.rotate import get_R_der, get_F_der, get_q_der, get_expmap_der
12
+
13
+ dR_ref = get_R_der(c3d, ref_c3d)
14
+ np.testing.assert_allclose(dR, dR_ref)
15
+ dF_ref = get_F_der(c3d, ref_c3d)
16
+ np.testing.assert_allclose(dF.reshape(-1, 3, 4, 4), dF_ref)
17
+ dq_ref = get_q_der(c3d, ref_c3d)
18
+ np.testing.assert_allclose(dqdx.T.flatten(), dq_ref.flatten(), atol=atol)
19
+ dvdx_ref = get_expmap_der(c3d, ref_c3d)
20
+ np.testing.assert_allclose(dvdx.T.flatten(), dvdx_ref.flatten(), atol=atol)
21
+
22
+
23
+ class Rotation(Primitive):
24
+ """See (II. Theory) in [1], Eq. (3) - (14)"""
25
+
26
+ index = None
27
+
28
+ def __init__(self, indices, *args, ref_coords3d, **kwargs):
29
+ kwargs["cache"] = False
30
+ kwargs["calc_kwargs"] = ("index", "ref_coords3d")
31
+ super().__init__(indices, *args, **kwargs)
32
+
33
+ self.ref_coords3d = ref_coords3d.reshape(-1, 3).copy()
34
+
35
+ @staticmethod
36
+ def _weight(atoms, coords3d, indices, f_damping):
37
+ return 1
38
+
39
+ @staticmethod
40
+ def _calculate(coords3d, indices, gradient=False, index=0, ref_coords3d=None):
41
+ w, v_, c3d, ref_c3d = rot_quaternion(coords3d[indices], ref_coords3d[indices])
42
+
43
+ quat = v_[:, -1]
44
+ # Eigenvector sign is ambigous. Force first item to be positive,
45
+ # similar to geomeTRIC code.
46
+ if quat[0] < 0.0:
47
+ quat *= -1
48
+
49
+ # Eq. (8) in [1].
50
+ # v = 2 * q_i * (cos⁻¹(q_0) / sqrt(1 - q_0 ** 2)
51
+ #
52
+ # As q_0 approaches 1, the denominator becomes very small, and dividing
53
+ # by this small number results in numerical instability.
54
+ #
55
+ # According to wolframalpha v(q_0) limit approaches 2 for q_0 = 1.
56
+ #
57
+ # input: limit of (2 * arccos(x) / sqrt(1-x**2))
58
+ # output: lim v(x) for x -> 1 becomes 2.
59
+ q0 = quat[0]
60
+ if abs(q0 - 1.0) <= 1e-8:
61
+ prefac = 2 - 2 / 3 * (q0 - 1)
62
+ dvdq0 = -2 / 3
63
+ else:
64
+ arccos_q0 = np.arccos(q0)
65
+ diff = 1 - q0 ** 2
66
+ prefac = 2 * arccos_q0 / np.sqrt(diff)
67
+ dvdq0 = 2 * q0 * arccos_q0 / diff ** 1.5 - 2 / diff
68
+
69
+ # Exponential map
70
+ v = prefac * quat[1:]
71
+
72
+ if gradient:
73
+ # Gradient of correlation matrix
74
+ y1, y2, y3 = ref_c3d.T
75
+ dR = np.zeros((*c3d.shape, 3, 3))
76
+ dR[:, 0, 0, 0] = y1
77
+ dR[:, 0, 0, 1] = y2
78
+ dR[:, 0, 0, 2] = y3
79
+ #
80
+ dR[:, 1, 1, 0] = y1
81
+ dR[:, 1, 1, 1] = y2
82
+ dR[:, 1, 1, 2] = y3
83
+ #
84
+ dR[:, 2, 2, 0] = y1
85
+ dR[:, 2, 2, 1] = y2
86
+ dR[:, 2, 2, 2] = y3
87
+ dR11, dR12, dR13, dR21, dR22, dR23, dR31, dR32, dR33 = dR.reshape(-1, 9).T
88
+
89
+ # Gradient of F matrix. Construct full matrix, as we have to do a dot
90
+ # product later on.
91
+ dF = np.zeros((ref_c3d.size, 4, 4))
92
+ dF[:, 0, 0] = dR11 + dR22 + dR33
93
+ dF[:, 0, 1] = dR23 - dR32
94
+ dF[:, 0, 2] = dR31 - dR13
95
+ dF[:, 0, 3] = dR12 - dR21
96
+ #
97
+ dF[:, 1, 0] = dF[:, 0, 1]
98
+ dF[:, 1, 1] = dR11 - dR22 - dR33
99
+ dF[:, 1, 2] = dR12 + dR21
100
+ dF[:, 1, 3] = dR13 + dR31
101
+ #
102
+ dF[:, 2, 0] = dF[:, 0, 2]
103
+ dF[:, 2, 1] = dF[:, 1, 2]
104
+ dF[:, 2, 2] = -dR11 + dR22 - dR33
105
+ dF[:, 2, 3] = dR23 + dR32
106
+ #
107
+ dF[:, 3, 0] = dF[:, 0, 3]
108
+ dF[:, 3, 1] = dF[:, 1, 3]
109
+ dF[:, 3, 2] = dF[:, 2, 3]
110
+ dF[:, 3, 3] = -dR11 - dR22 + dR33
111
+
112
+ # Quaternion gradient
113
+ dqdx = eigvec_grad(w, v_, ind=-1, mat_grad=dF)
114
+
115
+ dvdq = np.zeros((3, 4))
116
+ dvdq[:, 0] = dvdq0 * quat[1:]
117
+ dvdq[:, 1:] = np.diag((prefac, prefac, prefac))
118
+
119
+ # Gradient of exponential map from chain rule.
120
+ # See bottom-left on 214108-3 in [1], after Eq. (11).
121
+ dvdx = np.einsum("ji,ik->jk", dvdq, dqdx)
122
+
123
+ # compare_to_geometric(c3d, ref_c3d, dR, dF, dqdx, dvdx)
124
+ row = np.zeros_like(coords3d)
125
+ if index is None:
126
+ return v, dvdx.reshape(3, -1)
127
+ row[indices] = dvdx[index].reshape(-1, 3)
128
+ return v[index], row.flatten()
129
+ return v[index]
130
+
131
+ @staticmethod
132
+ def _jacobian(coords3d, indices, index=0, ref_coords3d=None):
133
+ """Not implemented!"""
134
+ size = len(indices) * 3
135
+ return np.zeros(size * size)
136
+
137
+
138
+ class RotationA(Rotation):
139
+ index = 0
140
+
141
+
142
+ class RotationB(Rotation):
143
+ index = 1
144
+
145
+
146
+ class RotationC(Rotation):
147
+ index = 2
@@ -0,0 +1,31 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.intcoords.Primitive import Primitive
4
+ from pysisyphus.intcoords.derivatives import d2q_b
5
+ from pysisyphus.linalg import norm3
6
+
7
+
8
+ class Stretch(Primitive):
9
+
10
+ @staticmethod
11
+ def _weight(atoms, coords3d, indices, f_damping):
12
+ return Stretch.rho(atoms, coords3d, indices)
13
+
14
+ @staticmethod
15
+ def _calculate(coords3d, indices, gradient=False):
16
+ n, m = indices
17
+ bond = coords3d[m] - coords3d[n]
18
+ bond_length = norm3(bond)
19
+ if gradient:
20
+ bond_normed = bond / bond_length
21
+ row = np.zeros_like(coords3d)
22
+ # 1 / -1 correspond to the sign factor [1] Eq. 18
23
+ row[m,:] = bond_normed
24
+ row[n,:] = -bond_normed
25
+ row = row.flatten()
26
+ return bond_length, row
27
+ return bond_length
28
+
29
+ @staticmethod
30
+ def _jacobian(coords3d, indices):
31
+ return d2q_b(*coords3d[indices].flatten())
@@ -0,0 +1,101 @@
1
+ from math import sin
2
+
3
+ import numpy as np
4
+
5
+ from pysisyphus.intcoords.Primitive import Primitive
6
+ from pysisyphus.intcoords import Bend
7
+ from pysisyphus.intcoords.derivatives import d2q_d2
8
+ from pysisyphus.linalg import cross3, norm3
9
+
10
+
11
+ class Torsion(Primitive):
12
+ @staticmethod
13
+ def _weight(atoms, coords3d, indices, f_damping):
14
+ m, o, p, n = indices
15
+ rho_mo = Torsion.rho(atoms, coords3d, (m, o))
16
+ rho_op = Torsion.rho(atoms, coords3d, (o, p))
17
+ rho_pn = Torsion.rho(atoms, coords3d, (p, n))
18
+ rad_mop = Bend._calculate(coords3d, (m, o, p))
19
+ rad_opn = Bend._calculate(coords3d, (o, p, n))
20
+ return (
21
+ (rho_mo * rho_op * rho_pn) ** (1 / 3)
22
+ * (f_damping + (1 - f_damping) * sin(rad_mop))
23
+ * (f_damping + (1 - f_damping) * sin(rad_opn))
24
+ )
25
+
26
+ @staticmethod
27
+ def _calculate(coords3d, indices, gradient=False):
28
+ m, o, p, n = indices
29
+ u_dash = coords3d[m] - coords3d[o]
30
+ v_dash = coords3d[n] - coords3d[p]
31
+ w_dash = coords3d[p] - coords3d[o]
32
+ u_norm = norm3(u_dash)
33
+ v_norm = norm3(v_dash)
34
+ w_norm = norm3(w_dash)
35
+ u = u_dash / u_norm
36
+ v = v_dash / v_norm
37
+ w = w_dash / w_norm
38
+ phi_u = np.arccos(u.dot(w))
39
+ phi_v = np.arccos(-w.dot(v))
40
+ uxw = cross3(u, w)
41
+ vxw = cross3(v, w)
42
+ cos_dihed = uxw.dot(vxw) / (np.sin(phi_u) * np.sin(phi_v))
43
+ # Restrict cos_dihed to the allowed interval for arccos [-1, 1]
44
+ cos_dihed = min(1, max(cos_dihed, -1))
45
+
46
+ dihedral_rad = np.arccos(cos_dihed)
47
+
48
+ # Arccos only returns values between 0 and π, but dihedrals can
49
+ # also be negative. This is corrected now.
50
+ #
51
+ # (v ⨯ w) · u will be < 0 when both vectors point in different directions.
52
+ #
53
+ # M ---> N
54
+ # ^ ^
55
+ # \ /
56
+ # u v positive dihedral, M rotates into N clockwise
57
+ # \ / (v ⨯ w) · u > 0, keep positive sign
58
+ # OwP
59
+ # w points downward, into the screen plane.
60
+ # The vector resulting from the cross-product is easily
61
+ # visualized with your right hand.
62
+ #
63
+ # M
64
+ # \
65
+ # | u
66
+ # | \
67
+ # | OwP negative dihedral, M rotates into N counter-clockwise
68
+ # v / (v ⨯ w) · u < 0, invert dihedral sign
69
+ # v
70
+ # /
71
+ # N
72
+ #
73
+ if (dihedral_rad != np.pi) and (vxw.dot(u) < 0):
74
+ dihedral_rad *= -1
75
+
76
+ if gradient:
77
+ row = np.zeros_like(coords3d)
78
+ # | m | n | o | p |
79
+ # ------------------------------------------
80
+ # sign_factor(amo) | 1 | 0 | -1 | 0 | 1st term
81
+ # sign_factor(apn) | 0 | -1 | 0 | 1 | 2nd term
82
+ # sign_factor(aop) | 0 | 0 | 1 | -1 | 3rd term
83
+ # sign_factor(apo) | 0 | 0 | -1 | 1 | 4th term
84
+ sin2_u = np.sin(phi_u) ** 2
85
+ sin2_v = np.sin(phi_v) ** 2
86
+ first_term = uxw / (u_norm * sin2_u)
87
+ second_term = vxw / (v_norm * sin2_v)
88
+ third_term = uxw * np.cos(phi_u) / (w_norm * sin2_u)
89
+ fourth_term = -vxw * np.cos(phi_v) / (w_norm * sin2_v)
90
+ row[m, :] = first_term
91
+ row[n, :] = -second_term
92
+ row[o, :] = -first_term + third_term - fourth_term
93
+ row[p, :] = second_term - third_term + fourth_term
94
+ row = row.flatten()
95
+ return dihedral_rad, row
96
+ return dihedral_rad
97
+
98
+ @staticmethod
99
+ def _jacobian(coords3d, indices):
100
+ sign = np.sign(Torsion._calculate(coords3d, indices))
101
+ return sign * d2q_d2(*coords3d[indices].flatten())
@@ -0,0 +1,25 @@
1
+ # See
2
+ # https://en.wikipedia.org/wiki/Dihedral_angle#In_polymer_physics
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.intcoords import Torsion
7
+ from pysisyphus.intcoords.derivatives import q_d2, dq_d2, d2q_d2
8
+
9
+
10
+ class Torsion2(Torsion):
11
+ @staticmethod
12
+ def _calculate(coords3d, indices, gradient=False):
13
+ args = coords3d[indices].flatten()
14
+ val = q_d2(*args)
15
+
16
+ if gradient:
17
+ row = np.zeros_like(coords3d)
18
+ grad = dq_d2(*args).reshape(-1, 3)
19
+ row[indices] = grad
20
+ return val, row.flatten()
21
+ return val
22
+
23
+ @staticmethod
24
+ def _jacobian(coords3d, indices):
25
+ return d2q_d2(*coords3d[indices].flatten())
@@ -0,0 +1,45 @@
1
+ # [1] http://dx.doi.org/10.1063/1.4952956
2
+ # Lee-Ping Wang, 2016
3
+
4
+ import numpy as np
5
+
6
+ from pysisyphus.intcoords.Primitive import Primitive
7
+
8
+
9
+ class Translation(Primitive):
10
+ """See (II. Theory) in [1], Eq. (2)"""
11
+
12
+ def __init__(self, *args, **kwargs):
13
+ kwargs["calc_kwargs"] = ("cart_axis",)
14
+ super().__init__(*args, **kwargs)
15
+
16
+ @staticmethod
17
+ def _weight(atoms, coords3d, indices, f_damping):
18
+ return 1
19
+
20
+ @staticmethod
21
+ def _calculate(coords3d, indices, gradient=False, cart_axis=0):
22
+ value = coords3d[indices, cart_axis].mean()
23
+ if gradient:
24
+ row = np.zeros_like(coords3d)
25
+ row[indices, cart_axis] = 1 / len(indices)
26
+ row = row.flatten()
27
+ return value, row
28
+ return value
29
+
30
+ @staticmethod
31
+ def _jacobian(coords3d, indices, cart_axis):
32
+ size = len(indices) * 3
33
+ return np.zeros(size * size)
34
+
35
+
36
+ class TranslationX(Translation):
37
+ cart_axis = 0
38
+
39
+
40
+ class TranslationY(Translation):
41
+ cart_axis = 1
42
+
43
+
44
+ class TranslationZ(Translation):
45
+ cart_axis = 2
@@ -0,0 +1,61 @@
1
+ __all__ = [
2
+ "PrimitiveNotDefinedException",
3
+ "Bend",
4
+ "Bend2",
5
+ "CartesianX",
6
+ "CartesianY",
7
+ "CartesianZ",
8
+ "DummyImproper",
9
+ "DummyTorsion",
10
+ "DistanceFunction",
11
+ "LinearBend",
12
+ "LinearDisplacement",
13
+ "OutOfPlane",
14
+ "Stretch",
15
+ "Torsion",
16
+ "Torsion2",
17
+ "RobustTorsion1",
18
+ "RobustTorsion2",
19
+ "RotationA",
20
+ "RotationB",
21
+ "RotationC",
22
+ "TranslationX",
23
+ "TranslationY",
24
+ "TranslationZ",
25
+ "DLC",
26
+ "HDLC",
27
+ "CartesianCoords",
28
+ "MWCartesianCoords",
29
+ "RedundantCoords",
30
+ "TRIC",
31
+ "TMTRIC",
32
+ "HybridRedundantCoords",
33
+ ]
34
+
35
+ from pysisyphus.intcoords.exceptions import PrimitiveNotDefinedException
36
+ from pysisyphus.intcoords.Bend import Bend
37
+ from pysisyphus.intcoords.Bend2 import Bend2
38
+ from pysisyphus.intcoords.BondedFragment import BondedFragment
39
+ from pysisyphus.intcoords.Cartesian import CartesianX, CartesianY, CartesianZ
40
+ from pysisyphus.intcoords.DistanceFunction import DistanceFunction
41
+ from pysisyphus.intcoords.DummyImproper import DummyImproper
42
+ from pysisyphus.intcoords.DummyTorsion import DummyTorsion
43
+ from pysisyphus.intcoords.CartesianCoords import CartesianCoords, MWCartesianCoords
44
+ from pysisyphus.intcoords.LinearBend import LinearBend
45
+ from pysisyphus.intcoords.LinearDisplacement import LinearDisplacement
46
+ from pysisyphus.intcoords.OutOfPlane import OutOfPlane
47
+ from pysisyphus.intcoords.Rotation import RotationA, RotationB, RotationC
48
+ from pysisyphus.intcoords.RobustTorsion import RobustTorsion1, RobustTorsion2
49
+ from pysisyphus.intcoords.Stretch import Stretch
50
+ from pysisyphus.intcoords.Torsion import Torsion
51
+ from pysisyphus.intcoords.Torsion2 import Torsion2
52
+ from pysisyphus.intcoords.Translation import TranslationX, TranslationY, TranslationZ
53
+ from pysisyphus.intcoords.RedundantCoords import (
54
+ RedundantCoords,
55
+ TRIC,
56
+ TMTRIC,
57
+ HybridRedundantCoords,
58
+ )
59
+
60
+ # DLC inherits from RedundantCoords, so we import it after RedundantCoords
61
+ from pysisyphus.intcoords.DLC import DLC, HDLC
@@ -0,0 +1,126 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from pysisyphus.Geometry import Geometry
6
+ from pysisyphus.helpers_pure import log
7
+ from pysisyphus.intcoords.setup import get_bond_sets
8
+ from pysisyphus.intcoords import RedundantCoords
9
+ from pysisyphus.intcoords.PrimTypes import PrimTypes
10
+
11
+
12
+ logger = logging.getLogger("internal_coords")
13
+
14
+
15
+ def augment_bonds(geom, root=0, proj=False):
16
+ assert geom.coord_type != "cart"
17
+ log(logger, "Trying to augment bonds.")
18
+
19
+ hessian = geom.cart_hessian
20
+ try:
21
+ energy = geom.energy
22
+ except AttributeError:
23
+ energy = None
24
+
25
+ func = find_missing_bonds_by_projection if proj else find_missing_strong_bonds
26
+
27
+ missing_bonds = func(geom, hessian, root=root)
28
+
29
+ if missing_bonds:
30
+ aux_bond_pt = PrimTypes.AUX_BOND
31
+ missing_aux_bonds = [(aux_bond_pt, *mbond) for mbond in missing_bonds]
32
+ print("\t@Missing bonds:", missing_bonds)
33
+ new_geom = Geometry(geom.atoms, geom.cart_coords,
34
+ coord_type=geom.coord_type,
35
+ coord_kwargs={"define_prims": missing_aux_bonds,},
36
+ )
37
+ new_geom.set_calculator(geom.calculator)
38
+ new_geom.energy = energy
39
+ new_geom.cart_hessian = hessian
40
+ return new_geom
41
+ else:
42
+ return geom
43
+
44
+
45
+ def find_missing_strong_bonds(geom, hessian, bond_factor=1.7, thresh=0.3,
46
+ root=0):
47
+ # Define only bonds
48
+ red = RedundantCoords(geom.atoms, geom.cart_coords,
49
+ bond_factor=bond_factor, bonds_only=True)
50
+ cur_bonds = set([frozenset(b) for b in geom.internal.bond_atom_indices])
51
+
52
+ # Transform cartesian hessian to bond hessian
53
+ bond_hess = red.transform_hessian(hessian)
54
+ # Determine transisiton vector
55
+ eigvals, eigvecs = np.linalg.eigh(bond_hess)
56
+ # There are probably no bonds missing if there are no negative eigenvalues
57
+ if sum(eigvals < 0) == 0:
58
+ return list()
59
+
60
+ trans_vec = eigvecs[:, root]
61
+ # Find bonds that strongly contribute to the selected transition vector
62
+ strong = np.abs(trans_vec) > thresh
63
+ strong_bonds = np.array(red.bond_atom_indices)[strong]
64
+ strong_bonds = set([frozenset(b) for b in strong_bonds])
65
+
66
+ # Check which strong bonds are missing from the currently defiend bonds
67
+ missing_bonds = strong_bonds - cur_bonds
68
+ missing_bonds = [tuple(_) for _ in missing_bonds]
69
+ return missing_bonds
70
+
71
+
72
+ def find_missing_bonds_by_projection(geom, hessian, bond_factor=2.0, bond_thresh=0.35,
73
+ concerted_thresh=0.35, root=0):
74
+
75
+ def array2set(arr):
76
+ return set([tuple(_) for _ in arr])
77
+
78
+ bonds_present = array2set(geom.internal.bond_atom_indices)
79
+ eigvals, eigvecs = np.linalg.eigh(hessian)
80
+
81
+ # There are probably no bonds missing if there are no negative eigenvalues
82
+ if sum(eigvals < 0) == 0:
83
+ return list()
84
+
85
+ trans_vec = eigvecs[:, root]
86
+
87
+ c3d = geom.coords3d
88
+ bond_vec_empty = np.zeros_like(c3d)
89
+ unique_bonds = array2set(get_bond_sets(geom.atoms, c3d, bond_factor=bond_factor))
90
+ unique_bonds -= bonds_present
91
+ unique_bonds = np.array(list(unique_bonds))
92
+
93
+ bond_vecs = list()
94
+ concerted_vecs = list()
95
+ for m, k in unique_bonds:
96
+ displ = c3d[k] - c3d[m]
97
+ displ /= np.linalg.norm(displ)
98
+
99
+ # Bond
100
+ bond = bond_vec_empty.copy()
101
+ bond[k] = displ
102
+ bond[m] = -displ
103
+ bond_vecs.append(bond)
104
+
105
+ # Concerted movement
106
+ conc = bond_vec_empty.copy()
107
+ conc[k] = displ
108
+ conc[m] = displ
109
+ concerted_vecs.append(conc)
110
+
111
+ def reshape(arr):
112
+ return np.array(arr).reshape(-1, trans_vec.size)
113
+ bond_vecs = reshape(bond_vecs)
114
+ concerted_vecs = reshape(concerted_vecs)
115
+
116
+ def overlaps(arr):
117
+ return np.abs(arr.dot(trans_vec))
118
+ bond_ovlps = overlaps(bond_vecs)
119
+ concerted_ovlps = overlaps(concerted_vecs)
120
+
121
+ unique_bonds = np.array(unique_bonds)
122
+ missing_bonds = unique_bonds[bond_ovlps > bond_thresh]
123
+ missing_concerted = unique_bonds[concerted_ovlps > concerted_thresh]
124
+
125
+ missing_inds = array2set(missing_bonds) | array2set(missing_concerted)
126
+ return missing_inds