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,116 @@
1
+ import numpy as np
2
+
3
+ from pysisyphus.Geometry import Geometry
4
+ from pysisyphus.helpers import align_geoms
5
+ from pysisyphus.xyzloader import write_geoms_to_trj
6
+
7
+
8
+ class Interpolator:
9
+ def __init__(
10
+ self,
11
+ geoms,
12
+ between,
13
+ extrapolate=0,
14
+ extrapolate_before=0,
15
+ extrapolate_after=0,
16
+ extrapolate_damp=1.0,
17
+ align=False,
18
+ ):
19
+ self.geoms = geoms
20
+ self.between = between
21
+ self.extrapolate = extrapolate
22
+ self.extrapolate_before = (
23
+ extrapolate_before if extrapolate_before else self.extrapolate
24
+ )
25
+ self.extrapolate_after = (
26
+ extrapolate_after if extrapolate_after else self.extrapolate
27
+ )
28
+ self.extrapolate_damp = extrapolate_damp
29
+ one_atom_geom = any([len(geom.atoms) == 1 for geom in geoms])
30
+ # Don't try to align one atom species
31
+ self.align = align and not one_atom_geom
32
+
33
+ assert len(geoms) >= 2, "Need at least two geometries to interpolate!"
34
+
35
+ # Check for consistent atom ordering
36
+ for i, geom in enumerate(self.geoms[:-1]):
37
+ next_geom = self.geoms[i + 1]
38
+ atoms = geom.atoms
39
+ next_atoms = next_geom.atoms
40
+ assert len(atoms) == len(
41
+ next_atoms
42
+ ), f"Geometries {i} and {i+1} have a different number of atoms!"
43
+ assert (
44
+ atoms == next_atoms
45
+ ), f"Different atom ordering in geometries {i} and {i+1}!"
46
+
47
+ self.atoms = self.geoms[0].atoms
48
+ if self.align:
49
+ align_geoms(geoms)
50
+ self.all_geoms = None
51
+
52
+ def interpolate_all(self):
53
+ all_geoms = list()
54
+
55
+ if self.extrapolate_before:
56
+ print("Extrapolating before")
57
+ geoms_extrapol_before = self.interpolate(
58
+ self.geoms[0],
59
+ self.geoms[1],
60
+ interpolate_only=self.extrapolate_before,
61
+ extrapolate=True,
62
+ )
63
+ all_geoms += geoms_extrapol_before[::-1]
64
+
65
+ print("Interpolating between")
66
+ # Interpolate between all pairs of geometries
67
+ for i, initial_geom in enumerate(self.geoms[:-1]):
68
+ final_geom = self.geoms[i + 1]
69
+ interpolated_geoms = self.interpolate(initial_geom, final_geom)
70
+ assert len(interpolated_geoms) == self.between, (
71
+ "Something is wrong with the number of interpolated "
72
+ "geometries. Maybe you accidentally also return the "
73
+ "initial and final geometry?"
74
+ )
75
+ all_geoms.append(self.geoms[i])
76
+ all_geoms.extend(interpolated_geoms)
77
+ # As we only added the i-th geometry and the new interpolated
78
+ # geometries of every geometry pair we also have to add the last
79
+ # ((i+1)-th) geometry at the end.
80
+ all_geoms.append(self.geoms[-1])
81
+
82
+ print("Extrapolate between")
83
+ if self.extrapolate_after:
84
+ geoms_extrapol_after = self.interpolate(
85
+ self.geoms[-1],
86
+ self.geoms[-2],
87
+ interpolate_only=self.extrapolate_after,
88
+ extrapolate=True,
89
+ )
90
+ all_geoms += geoms_extrapol_after
91
+
92
+ self.all_geoms = all_geoms
93
+ if self.align:
94
+ align_geoms(self.all_geoms)
95
+ return all_geoms
96
+
97
+ def interpolate(
98
+ self, initial_geom, final_geom, interpolate_only=0, extrapolate=False
99
+ ):
100
+ initial_coords = initial_geom.coords
101
+
102
+ # Linear interpolation
103
+ step = (final_geom.coords - initial_geom.coords) / (self.between + 1)
104
+ if extrapolate:
105
+ step *= -1
106
+ step *= self.extrapolate_damp
107
+ # When we extrapolate we probably want a number of geometries that is
108
+ # different from self.between
109
+ interpolations = interpolate_only if interpolate_only else self.between
110
+ # initial + i*step
111
+ i_array = np.arange(1, interpolations + 1)
112
+ new_coords = initial_coords + i_array[:, None] * step
113
+ return [Geometry(self.atoms, nc) for nc in new_coords]
114
+
115
+ def all_geoms_to_trj(self, trj_fn):
116
+ write_geoms_to_trj(self.all_geoms, trj_fn)
@@ -0,0 +1,70 @@
1
+ import numpy as np
2
+ from scipy.spatial.distance import pdist
3
+ from scipy.optimize import minimize
4
+
5
+ from pysisyphus.Geometry import Geometry
6
+ from pysisyphus.interpolate.Interpolator import Interpolator
7
+
8
+
9
+ # [1] https://www.sciencedirect.com/science/article/pii/S0927025603001113
10
+ # [2] https://pubs.acs.org/doi/pdf/10.1021/ct200654u
11
+
12
+
13
+ class LST(Interpolator):
14
+ def __init__(self, *args, align=True, gtol=1e-4, silent=False, **kwargs):
15
+ super().__init__(*args, align=align, **kwargs)
16
+
17
+ self.gtol = float(gtol)
18
+ self.silent = silent
19
+
20
+ def cost_function(self, wa_c, f, rab, wab):
21
+ wa_c = wa_c.reshape(-1, 3)
22
+ rab_c = pdist(wa_c)
23
+
24
+ rab_i = rab(f)
25
+ wa_i = wab(f)
26
+
27
+ first_term = np.sum(((rab_i - rab_c) ** 2) / (rab_i**4))
28
+ second_term = 1e-6 * np.sum((wa_i - wa_c) ** 2)
29
+ return first_term + second_term
30
+
31
+ def interpolate(self, initial_geom, final_geom, **kwargs):
32
+ coords3d = np.array((initial_geom.coords3d, final_geom.coords3d))
33
+ # Calculate the condensed distances matrices
34
+ pdists = [pdist(c3d) for c3d in coords3d]
35
+
36
+ def rab_(f, pdist_r, pdist_p):
37
+ """Difference in internuclear distances."""
38
+ return (1 - f) * pdist_r + f * pdist_p
39
+
40
+ rab = lambda f: rab_(f, pdists[0], pdists[1])
41
+
42
+ def wab_(f, coords_r, coords_p):
43
+ """Difference in actual cartesian coordinates."""
44
+ return (1 - f) * coords_r + f * coords_p
45
+
46
+ wab = lambda f: wab_(f, coords3d[0], coords3d[1])
47
+
48
+ interpolated_geoms = list()
49
+ minimize_kwargs = {
50
+ "method": "L-BFGS-B",
51
+ "options": {
52
+ "gtol": self.gtol,
53
+ },
54
+ }
55
+ # We only have to interpolate between the two provided geometries.
56
+ # So we consider the total number of geometries (self.between + 2)
57
+ # to get the correct spacing, but we neglect the first and the last
58
+ # number (0 and 1), as they correspond to the two already known geometries.
59
+ for i, f in enumerate(np.linspace(0, 1, self.between + 2)[1:-1], 1):
60
+ x0_flat = wab(f)
61
+ res = minimize(
62
+ self.cost_function,
63
+ x0=x0_flat.flatten(),
64
+ args=(f, rab, wab),
65
+ **minimize_kwargs,
66
+ )
67
+ if not self.silent:
68
+ print(f"{i:03d}/{self.between:03d}: f={f:.04f}, success: {res.success}")
69
+ interpolated_geoms.append(Geometry(self.atoms, res.x))
70
+ return interpolated_geoms
@@ -0,0 +1,152 @@
1
+ import sys
2
+
3
+ import numpy as np
4
+
5
+ from pysisyphus.Geometry import Geometry
6
+ from pysisyphus.interpolate.Interpolator import Interpolator
7
+ from pysisyphus.intcoords.exceptions import (
8
+ DifferentPrimitivesException,
9
+ RebuiltInternalsException,
10
+ )
11
+ from pysisyphus.intcoords.helpers import get_tangent, form_coordinate_union
12
+ from pysisyphus.xyzloader import write_geoms_to_trj
13
+
14
+
15
+ class Redund(Interpolator):
16
+ def __init__(self, *args, align=True, rebuild_geoms=True, **kwargs):
17
+ super().__init__(*args, align=align, **kwargs)
18
+
19
+ self.rebuild_geoms = rebuild_geoms
20
+ if self.rebuild_geoms:
21
+ self.geoms = [
22
+ Geometry(geom.atoms, geom.cart_coords, coord_type="redund")
23
+ for geom in self.geoms
24
+ ]
25
+
26
+ def dump_progress(self, geoms, out_fn="redund_interpol_fail_trj.xyz"):
27
+ write_geoms_to_trj(geoms, out_fn)
28
+ print(f"Dumped interpolation progress to '{out_fn}'.")
29
+
30
+ def interpolate(
31
+ self,
32
+ initial_geom,
33
+ final_geom,
34
+ interpolate_only=0,
35
+ extrapolate=False,
36
+ typed_prims=None,
37
+ ):
38
+ print(f"No. of primitives at initial structure: {initial_geom.coords.size}")
39
+ print(f"No. of primitives at final structure: {final_geom.coords.size}")
40
+
41
+ if typed_prims is None:
42
+ typed_prims = form_coordinate_union(initial_geom, final_geom)
43
+ print(f"Union of primitives: {len(typed_prims)}")
44
+ else:
45
+ print(f"Using supplied primitive internals ({len(typed_prims)}).")
46
+
47
+ # Recreate geometries with consistent set of internal coordinates
48
+ geom1 = Geometry(
49
+ initial_geom.atoms,
50
+ initial_geom.cart_coords,
51
+ coord_type="redund",
52
+ coord_kwargs={
53
+ "typed_prims": typed_prims,
54
+ "recalc_B": True,
55
+ },
56
+ )
57
+ geom2 = Geometry(
58
+ final_geom.atoms,
59
+ final_geom.cart_coords,
60
+ coord_type="redund",
61
+ coord_kwargs={
62
+ "typed_prims": typed_prims,
63
+ "recalc_B": True,
64
+ },
65
+ )
66
+
67
+ dihedral_indices = geom1.internal.dihedral_indices
68
+ initial_tangent = get_tangent(geom1.coords, geom2.coords, dihedral_indices)
69
+ initial_diff = np.linalg.norm(initial_tangent)
70
+ approx_step_size = initial_diff / (self.between + 1)
71
+ final_prims = geom2.internal.prim_coords
72
+
73
+ geoms = [
74
+ geom1,
75
+ ]
76
+
77
+ def restart(new_geom):
78
+ interpolate_kwargs = {
79
+ "initial_geom": initial_geom,
80
+ "final_geom": final_geom,
81
+ "extrapolate": extrapolate,
82
+ "interpolate_only": interpolate_only,
83
+ }
84
+ return self.restart_interpolate(geoms, new_geom, interpolate_kwargs)
85
+
86
+ # initial_geom, final_geom, geoms, new_geom)
87
+
88
+ interpolations = interpolate_only if interpolate_only else self.between
89
+ ip_ex = "Extrapolating" if extrapolate else "Interpolating"
90
+ for i in range(interpolations):
91
+ print(f"{ip_ex} {i+1:03d}/{interpolations:03d}")
92
+ new_geom = geoms[-1].copy()
93
+ # Try to use the target primtive internals (final_prims) to calculate
94
+ # a tangent at the current, new geometry. As some primitives may be
95
+ # invalid at 'new_geom', DifferentPrimitivesException may be raised.
96
+ try:
97
+ prim_tangent = get_tangent(
98
+ new_geom.coords, final_prims, dihedral_indices
99
+ )
100
+ # If this is raised we update our target primitives and try to continue
101
+ # with them.
102
+ except DifferentPrimitivesException:
103
+ # return self.restart_interpolate(initial_geom, final_geom, new_geom)
104
+ return restart(new_geom)
105
+ if extrapolate:
106
+ prim_tangent *= -1
107
+ approx_step_size *= self.extrapolate_damp
108
+
109
+ step = self.step_along_tangent(new_geom, prim_tangent, approx_step_size)
110
+ try:
111
+ new_coords = new_geom.coords + step
112
+ # Will be raised when the sizes of both vectors differ
113
+ except ValueError:
114
+ # return self.restart_interpolate(initial_geom, final_geom, new_geom)
115
+ return restart(new_geom)
116
+
117
+ # The current primitives may also break down when a step along the
118
+ # tangent is taken.
119
+ try:
120
+ new_geom.coords = new_coords
121
+ except RebuiltInternalsException:
122
+ # return self.restart_interpolate(initial_geom, final_geom, new_geom)
123
+ return restart(new_geom)
124
+
125
+ geoms.append(new_geom)
126
+ sys.stdout.flush()
127
+
128
+ print()
129
+ return geoms[1:]
130
+
131
+ # def restart_interpolate(self, initial_geom, final_geom, geoms, new_geom):
132
+ def restart_interpolate(self, geoms, new_geom, interpolate_kwargs):
133
+ new_typed_prims = new_geom.internal.typed_prims
134
+ print(
135
+ f"Encountered breakdown of current primitive internals.\n"
136
+ "Restarting interpolation with reduced number of internals."
137
+ )
138
+ self.dump_progress(geoms, out_fn=f"redund_interpol_fail_trj.xyz")
139
+ print()
140
+ # Recursive call with reduced set of primitive internals
141
+ return self.interpolate(**interpolate_kwargs, typed_prims=new_typed_prims)
142
+
143
+ def step_along_tangent(self, geom, prim_tangent, step_size):
144
+ # Form active set
145
+ B = geom.internal.B_prim
146
+ G = B.dot(B.T)
147
+ eigvals, eigvectors = np.linalg.eigh(G)
148
+ U = eigvectors[:, np.abs(eigvals) > 1e-6]
149
+ reduced_tangent = (np.einsum("i,ij->j", prim_tangent, U) * U).sum(axis=1)
150
+ reduced_tangent /= np.linalg.norm(reduced_tangent)
151
+ step = step_size * reduced_tangent
152
+ return step
@@ -0,0 +1,9 @@
1
+ __all__ = [
2
+ "Interpolator",
3
+ "IDPP",
4
+ "LST",
5
+ "Redund",
6
+ "Geodesic"
7
+ ]
8
+
9
+ from pysisyphus.interpolate.helpers import interpolate, interpolate_all
@@ -0,0 +1,34 @@
1
+ from pysisyphus.interpolate import IDPP, LST, Interpolator, Redund, Geodesic
2
+
3
+
4
+ INTERPOLATE = {
5
+ "idpp": IDPP.IDPP,
6
+ "lst": LST.LST,
7
+ "redund": Redund.Redund,
8
+ "linear": Interpolator.Interpolator,
9
+ "geodesic": Geodesic.Geodesic,
10
+ }
11
+
12
+
13
+ def interpolate(initial_geom, final_geom, between, kind="linear",
14
+ only_between=False, align=False, interpol_kwargs=None):
15
+ if interpol_kwargs is None:
16
+ interpol_kwargs = {}
17
+ """ only_between: return only the interpolated images."""
18
+ interpolate_class = INTERPOLATE[kind]
19
+ interpolator = interpolate_class((initial_geom, final_geom), between,
20
+ align=align, **interpol_kwargs)
21
+ if only_between:
22
+ return interpolator.interpolate(initial_geom, final_geom)
23
+ else:
24
+ return interpolator.interpolate_all()
25
+
26
+
27
+ def interpolate_all(geoms, between, kind="linear", align=False, **interpol_kwargs):
28
+ if (between == 0) or (kind is None):
29
+ return geoms
30
+
31
+ interpolate_class = INTERPOLATE[kind]
32
+ interpolator = interpolate_class(geoms, between, align=align, **interpol_kwargs)
33
+
34
+ return interpolator.interpolate_all()
@@ -0,0 +1,22 @@
1
+ __all__ = [
2
+ "geom_from_cjson",
3
+ "geom_from_crd",
4
+ "geom_from_hessian",
5
+ "geom_from_mol2",
6
+ "geom_from_pdb",
7
+ "geom_from_zmat",
8
+ "geom_from_qcschema",
9
+ "geoms_from_xyz",
10
+ "save_hessian",
11
+ "save_third_deriv",
12
+ ]
13
+
14
+
15
+ from pysisyphus.io.cjson import geom_from_cjson
16
+ from pysisyphus.io.crd import geom_from_crd, geom_to_crd_str
17
+ from pysisyphus.io.hessian import save_hessian, save_third_deriv, geom_from_hessian
18
+ from pysisyphus.io.mol2 import geom_from_mol2
19
+ from pysisyphus.io.pdb import geom_from_pdb
20
+ from pysisyphus.io.qcschema import geom_from_qcschema
21
+ from pysisyphus.io.xyz import geoms_from_xyz, geoms_from_inline_xyz, parse_xyz
22
+ from pysisyphus.io.zmat import geom_from_zmat, geom_from_zmat_fn
pysisyphus/io/aomix.py ADDED
@@ -0,0 +1,178 @@
1
+ import numpy as np
2
+ import pyparsing as pp
3
+
4
+ from pysisyphus.elem_data import ATOMIC_NUMBERS, nuc_charges_for_atoms
5
+ from pysisyphus.helpers_pure import file_or_str
6
+ from pysisyphus.wavefunction import get_l, Shell, AOMixShells, Wavefunction
7
+ from pysisyphus.wavefunction.helpers import BFType
8
+
9
+ AOMIX_EXTS = ".in"
10
+
11
+
12
+ @file_or_str(*AOMIX_EXTS)
13
+ def parse_aomix(text):
14
+ real = pp.common.real
15
+ sreal = pp.common.sci_real
16
+ int_ = pp.common.integer
17
+ header = pp.CaselessLiteral("[AOMix Format]")
18
+ title = pp.CaselessKeyword("[Title]")
19
+ energy = pp.Suppress(pp.CaselessLiteral("[SCF Energy / Hartree]")) + sreal
20
+ xyz = pp.Group(sreal + sreal + sreal)
21
+ atom_line = pp.Group(
22
+ pp.Word(pp.alphas).set_results_name("atom")
23
+ + int_.set_results_name("id")
24
+ + int_.set_results_name("atom_num")
25
+ + xyz.set_results_name("xyz")
26
+ )
27
+ atoms = (
28
+ pp.Suppress(pp.CaselessLiteral("[Atoms]"))
29
+ + pp.Optional(pp.CaselessLiteral("AU")).set_results_name("unit")
30
+ + pp.OneOrMore(atom_line).set_results_name("atom_lines")
31
+ )
32
+ prim_gto = pp.Group(sreal + sreal)
33
+ contr_gto = pp.Group(
34
+ pp.Word(pp.alphas).set_results_name("l")
35
+ + int_.set_results_name("contr_depth")
36
+ + real
37
+ + pp.OneOrMore(prim_gto).set_results_name("prim_gtos")
38
+ )
39
+ center_contr_gto = pp.Group(
40
+ int_.set_results_name("center")
41
+ + int_
42
+ + pp.OneOrMore(contr_gto).set_results_name("contr_gtos")
43
+ )
44
+ gtos = pp.CaselessLiteral("[GTO]") + pp.OneOrMore(
45
+ center_contr_gto
46
+ ).set_results_name("center_gtos")
47
+ ao_label = pp.Word(pp.alphanums)
48
+ mo_line = pp.Suppress(int_ + int_ + pp.Word(pp.alphas) + int_ + ao_label) + sreal
49
+ sym_label = int_ + pp.one_of(("a", "b"), caseless=True)
50
+ mo = pp.Group(
51
+ pp.CaselessLiteral("Sym=")
52
+ + sym_label.set_results_name("sym_label")
53
+ + pp.CaselessLiteral("Ene=")
54
+ + sreal.set_results_name("ene")
55
+ + pp.CaselessLiteral("Spin=")
56
+ + pp.one_of(("Alpha", "Beta"), caseless=True).set_results_name("spin")
57
+ + pp.CaselessLiteral("Occup=")
58
+ + sreal.set_results_name("occup")
59
+ + pp.Group(pp.OneOrMore(mo_line)).set_results_name("coeffs")
60
+ )
61
+ mos = pp.CaselessLiteral("[MO]") + pp.OneOrMore(mo).set_results_name("mos")
62
+
63
+ parser = (
64
+ header
65
+ + pp.Optional(title).set_results_name("title")
66
+ + pp.Optional(energy).set_results_name("energy")
67
+ + atoms
68
+ + gtos
69
+ + mos
70
+ )
71
+ result = parser.parseString(text)
72
+ as_dict = result.asDict()
73
+
74
+ return as_dict
75
+
76
+
77
+ def shells_from_aomix_dict(aomix_dict):
78
+ atom_lines = aomix_dict["atom_lines"]
79
+ center_gtos = aomix_dict["center_gtos"]
80
+ _shells = list()
81
+ for atom_line, cgtos in zip(atom_lines, center_gtos):
82
+ atomic_num = ATOMIC_NUMBERS[atom_line["atom"].lower()]
83
+ center_ind = cgtos["center"]
84
+ assert atom_line["id"] == center_ind
85
+ center_ind -= 1 # Start from 0 internally
86
+ center = np.array(atom_line["xyz"])
87
+ for cgto in cgtos["contr_gtos"]:
88
+ exps, coeffs = zip(*cgto["prim_gtos"])
89
+ exps = np.array(exps)
90
+ coeffs = np.array(coeffs)
91
+ L = get_l(cgto["l"])
92
+ shell = Shell(
93
+ L=L,
94
+ atomic_num=atomic_num,
95
+ center=center,
96
+ coeffs=coeffs,
97
+ exps=exps,
98
+ center_ind=center_ind,
99
+ )
100
+ _shells.append(shell)
101
+ shells = AOMixShells(_shells)
102
+ return shells
103
+
104
+
105
+ def wavefunction_from_aomix_dict(aomix_dict, **wf_kwargs):
106
+ shells = shells_from_aomix_dict(aomix_dict)
107
+
108
+ atoms = list()
109
+ coords3d = list()
110
+ for atom_line in aomix_dict["atom_lines"]:
111
+ atoms.append(atom_line["atom"].lower())
112
+ coords3d.append(atom_line["xyz"])
113
+ atoms = tuple(atoms)
114
+ coords = np.array(coords3d).flatten()
115
+
116
+ occ_a = 0
117
+ occ_b = 0
118
+ unrestricted = False
119
+ C_a = list()
120
+ C_b = list()
121
+ for mo in aomix_dict["mos"]:
122
+ spin = mo["spin"].lower()
123
+ occup = mo["occup"]
124
+ coeffs = mo["coeffs"]
125
+ if spin == "alpha":
126
+ occ_a += occup
127
+ C_a.append(coeffs)
128
+ elif spin == "beta":
129
+ occ_b += occup
130
+ C_b.append(coeffs)
131
+ else:
132
+ raise Exception(f"Unknown {spin=}!")
133
+
134
+ if not unrestricted:
135
+ unrestricted = spin == "beta"
136
+ occ_a = int(occ_a)
137
+ occ_b = int(occ_b)
138
+ if not unrestricted:
139
+ C_b = C_a.copy()
140
+ occ_a = occ_b = occ_a // 2
141
+ mult = 1
142
+ else:
143
+ mult = (occ_a - occ_b) + 1
144
+
145
+ nuc_charge = nuc_charges_for_atoms(atoms).sum()
146
+ charge = nuc_charge - occ_a - occ_b
147
+ C = np.array((np.transpose(C_a), np.transpose(C_b)))
148
+ _wf_kwargs = {
149
+ "atoms": atoms,
150
+ "coords": coords,
151
+ "charge": charge,
152
+ "mult": mult,
153
+ "unrestricted": unrestricted,
154
+ "occ": (occ_a, occ_b),
155
+ "C": C,
156
+ "bf_type": BFType.CARTESIAN,
157
+ "shells": shells,
158
+ **wf_kwargs,
159
+ }
160
+
161
+ _wf_kwargs.update(wf_kwargs)
162
+ return Wavefunction(**_wf_kwargs)
163
+
164
+
165
+ @file_or_str(*AOMIX_EXTS)
166
+ def shells_from_aomix(text):
167
+ aomix_dict = parse_aomix(text)
168
+ return shells_from_aomix_dict(aomix_dict)
169
+
170
+
171
+ @file_or_str(*AOMIX_EXTS)
172
+ def wavefunction_from_aomix(text, **wf_kwargs):
173
+ from time import time
174
+ start = time()
175
+ aomix_dict = parse_aomix(text)
176
+ dur = time() - start
177
+ print("dur", dur)
178
+ return wavefunction_from_aomix_dict(aomix_dict, **wf_kwargs)
pysisyphus/io/cjson.py ADDED
@@ -0,0 +1,24 @@
1
+ import json
2
+
3
+ import numpy as np
4
+
5
+ from pysisyphus.constants import ANG2BOHR
6
+ from pysisyphus.Geometry import Geometry
7
+ from pysisyphus.elem_data import INV_ATOMIC_NUMBERS
8
+
9
+
10
+ def parse_cjson(fn):
11
+ with open(fn) as handle:
12
+ cml = json.load(handle)
13
+ atms = cml["atoms"]
14
+ coords = np.array(atms["coords"]["3d"], dtype=float) * ANG2BOHR
15
+ atom_nums = atms["elements"]["number"]
16
+ atoms = tuple([INV_ATOMIC_NUMBERS[num].capitalize() for num in atom_nums])
17
+
18
+ return atoms, coords.flatten()
19
+
20
+
21
+ def geom_from_cjson(fn, **kwargs):
22
+ atoms, coords = parse_cjson(fn)
23
+ geom = Geometry(atoms, coords.flatten(), **kwargs)
24
+ return geom