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.
- hessian_ff/__init__.py +50 -0
- hessian_ff/analytical_hessian.py +609 -0
- hessian_ff/constants.py +46 -0
- hessian_ff/forcefield.py +339 -0
- hessian_ff/loaders.py +608 -0
- hessian_ff/native/Makefile +8 -0
- hessian_ff/native/__init__.py +28 -0
- hessian_ff/native/analytical_hessian.py +88 -0
- hessian_ff/native/analytical_hessian_ext.cpp +258 -0
- hessian_ff/native/bonded.py +82 -0
- hessian_ff/native/bonded_ext.cpp +640 -0
- hessian_ff/native/loader.py +349 -0
- hessian_ff/native/nonbonded.py +118 -0
- hessian_ff/native/nonbonded_ext.cpp +1150 -0
- hessian_ff/prmtop_parmed.py +23 -0
- hessian_ff/system.py +107 -0
- hessian_ff/terms/__init__.py +14 -0
- hessian_ff/terms/angle.py +73 -0
- hessian_ff/terms/bond.py +44 -0
- hessian_ff/terms/cmap.py +406 -0
- hessian_ff/terms/dihedral.py +141 -0
- hessian_ff/terms/nonbonded.py +209 -0
- hessian_ff/tests/__init__.py +0 -0
- hessian_ff/tests/conftest.py +75 -0
- hessian_ff/tests/data/small/complex.parm7 +1346 -0
- hessian_ff/tests/data/small/complex.pdb +125 -0
- hessian_ff/tests/data/small/complex.rst7 +63 -0
- hessian_ff/tests/test_coords_input.py +44 -0
- hessian_ff/tests/test_energy_force.py +49 -0
- hessian_ff/tests/test_hessian.py +137 -0
- hessian_ff/tests/test_smoke.py +18 -0
- hessian_ff/tests/test_validation.py +40 -0
- hessian_ff/workflows.py +889 -0
- mlmm/__init__.py +36 -0
- mlmm/__main__.py +7 -0
- mlmm/_version.py +34 -0
- mlmm/add_elem_info.py +374 -0
- mlmm/advanced_help.py +91 -0
- mlmm/align_freeze_atoms.py +601 -0
- mlmm/all.py +3535 -0
- mlmm/bond_changes.py +231 -0
- mlmm/bool_compat.py +223 -0
- mlmm/cli.py +574 -0
- mlmm/cli_utils.py +166 -0
- mlmm/default_group.py +337 -0
- mlmm/defaults.py +467 -0
- mlmm/define_layer.py +526 -0
- mlmm/dft.py +1041 -0
- mlmm/energy_diagram.py +253 -0
- mlmm/extract.py +2213 -0
- mlmm/fix_altloc.py +464 -0
- mlmm/freq.py +1406 -0
- mlmm/harmonic_constraints.py +140 -0
- mlmm/hessian_cache.py +44 -0
- mlmm/hessian_calc.py +174 -0
- mlmm/irc.py +638 -0
- mlmm/mlmm_calc.py +2262 -0
- mlmm/mm_parm.py +945 -0
- mlmm/oniom_export.py +1983 -0
- mlmm/oniom_import.py +457 -0
- mlmm/opt.py +1742 -0
- mlmm/path_opt.py +1353 -0
- mlmm/path_search.py +2299 -0
- mlmm/preflight.py +88 -0
- mlmm/py.typed +1 -0
- mlmm/pysis_runner.py +45 -0
- mlmm/scan.py +1047 -0
- mlmm/scan2d.py +1226 -0
- mlmm/scan3d.py +1265 -0
- mlmm/scan_common.py +184 -0
- mlmm/summary_log.py +736 -0
- mlmm/trj2fig.py +448 -0
- mlmm/tsopt.py +2871 -0
- mlmm/utils.py +2309 -0
- mlmm/xtb_embedcharge_correction.py +475 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/METADATA +1159 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/RECORD +372 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/WHEEL +5 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/entry_points.txt +2 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/licenses/LICENSE +674 -0
- mlmm_toolkit-0.2.2.dev0.dist-info/top_level.txt +4 -0
- pysisyphus/Geometry.py +1667 -0
- pysisyphus/LICENSE +674 -0
- pysisyphus/TableFormatter.py +63 -0
- pysisyphus/TablePrinter.py +74 -0
- pysisyphus/__init__.py +12 -0
- pysisyphus/calculators/AFIR.py +452 -0
- pysisyphus/calculators/AnaPot.py +20 -0
- pysisyphus/calculators/AnaPot2.py +48 -0
- pysisyphus/calculators/AnaPot3.py +12 -0
- pysisyphus/calculators/AnaPot4.py +20 -0
- pysisyphus/calculators/AnaPotBase.py +337 -0
- pysisyphus/calculators/AnaPotCBM.py +25 -0
- pysisyphus/calculators/AtomAtomTransTorque.py +154 -0
- pysisyphus/calculators/CFOUR.py +250 -0
- pysisyphus/calculators/Calculator.py +844 -0
- pysisyphus/calculators/CerjanMiller.py +24 -0
- pysisyphus/calculators/Composite.py +123 -0
- pysisyphus/calculators/ConicalIntersection.py +171 -0
- pysisyphus/calculators/DFTBp.py +430 -0
- pysisyphus/calculators/DFTD3.py +66 -0
- pysisyphus/calculators/DFTD4.py +84 -0
- pysisyphus/calculators/Dalton.py +61 -0
- pysisyphus/calculators/Dimer.py +681 -0
- pysisyphus/calculators/Dummy.py +20 -0
- pysisyphus/calculators/EGO.py +76 -0
- pysisyphus/calculators/EnergyMin.py +224 -0
- pysisyphus/calculators/ExternalPotential.py +264 -0
- pysisyphus/calculators/FakeASE.py +35 -0
- pysisyphus/calculators/FourWellAnaPot.py +28 -0
- pysisyphus/calculators/FreeEndNEBPot.py +39 -0
- pysisyphus/calculators/Gaussian09.py +18 -0
- pysisyphus/calculators/Gaussian16.py +726 -0
- pysisyphus/calculators/HardSphere.py +159 -0
- pysisyphus/calculators/IDPPCalculator.py +49 -0
- pysisyphus/calculators/IPIClient.py +133 -0
- pysisyphus/calculators/IPIServer.py +234 -0
- pysisyphus/calculators/LEPSBase.py +24 -0
- pysisyphus/calculators/LEPSExpr.py +139 -0
- pysisyphus/calculators/LennardJones.py +80 -0
- pysisyphus/calculators/MOPAC.py +219 -0
- pysisyphus/calculators/MullerBrownSympyPot.py +51 -0
- pysisyphus/calculators/MultiCalc.py +85 -0
- pysisyphus/calculators/NFK.py +45 -0
- pysisyphus/calculators/OBabel.py +87 -0
- pysisyphus/calculators/ONIOMv2.py +1129 -0
- pysisyphus/calculators/ORCA.py +893 -0
- pysisyphus/calculators/ORCA5.py +6 -0
- pysisyphus/calculators/OpenMM.py +88 -0
- pysisyphus/calculators/OpenMolcas.py +281 -0
- pysisyphus/calculators/OverlapCalculator.py +908 -0
- pysisyphus/calculators/Psi4.py +218 -0
- pysisyphus/calculators/PyPsi4.py +37 -0
- pysisyphus/calculators/PySCF.py +341 -0
- pysisyphus/calculators/PyXTB.py +73 -0
- pysisyphus/calculators/QCEngine.py +106 -0
- pysisyphus/calculators/Rastrigin.py +22 -0
- pysisyphus/calculators/Remote.py +76 -0
- pysisyphus/calculators/Rosenbrock.py +15 -0
- pysisyphus/calculators/SocketCalc.py +97 -0
- pysisyphus/calculators/TIP3P.py +111 -0
- pysisyphus/calculators/TransTorque.py +161 -0
- pysisyphus/calculators/Turbomole.py +965 -0
- pysisyphus/calculators/VRIPot.py +37 -0
- pysisyphus/calculators/WFOWrapper.py +333 -0
- pysisyphus/calculators/WFOWrapper2.py +341 -0
- pysisyphus/calculators/XTB.py +418 -0
- pysisyphus/calculators/__init__.py +81 -0
- pysisyphus/calculators/cosmo_data.py +139 -0
- pysisyphus/calculators/parser.py +150 -0
- pysisyphus/color.py +19 -0
- pysisyphus/config.py +133 -0
- pysisyphus/constants.py +65 -0
- pysisyphus/cos/AdaptiveNEB.py +230 -0
- pysisyphus/cos/ChainOfStates.py +725 -0
- pysisyphus/cos/FreeEndNEB.py +25 -0
- pysisyphus/cos/FreezingString.py +103 -0
- pysisyphus/cos/GrowingChainOfStates.py +71 -0
- pysisyphus/cos/GrowingNT.py +309 -0
- pysisyphus/cos/GrowingString.py +508 -0
- pysisyphus/cos/NEB.py +189 -0
- pysisyphus/cos/SimpleZTS.py +64 -0
- pysisyphus/cos/__init__.py +22 -0
- pysisyphus/cos/stiffness.py +199 -0
- pysisyphus/drivers/__init__.py +17 -0
- pysisyphus/drivers/afir.py +855 -0
- pysisyphus/drivers/barriers.py +271 -0
- pysisyphus/drivers/birkholz.py +138 -0
- pysisyphus/drivers/cluster.py +318 -0
- pysisyphus/drivers/diabatization.py +133 -0
- pysisyphus/drivers/merge.py +368 -0
- pysisyphus/drivers/merge_mol2.py +322 -0
- pysisyphus/drivers/opt.py +375 -0
- pysisyphus/drivers/perf.py +91 -0
- pysisyphus/drivers/pka.py +52 -0
- pysisyphus/drivers/precon_pos_rot.py +669 -0
- pysisyphus/drivers/rates.py +480 -0
- pysisyphus/drivers/replace.py +219 -0
- pysisyphus/drivers/scan.py +212 -0
- pysisyphus/drivers/spectrum.py +166 -0
- pysisyphus/drivers/thermo.py +31 -0
- pysisyphus/dynamics/Gaussian.py +103 -0
- pysisyphus/dynamics/__init__.py +20 -0
- pysisyphus/dynamics/colvars.py +136 -0
- pysisyphus/dynamics/driver.py +297 -0
- pysisyphus/dynamics/helpers.py +256 -0
- pysisyphus/dynamics/lincs.py +105 -0
- pysisyphus/dynamics/mdp.py +364 -0
- pysisyphus/dynamics/rattle.py +121 -0
- pysisyphus/dynamics/thermostats.py +128 -0
- pysisyphus/dynamics/wigner.py +266 -0
- pysisyphus/elem_data.py +3473 -0
- pysisyphus/exceptions.py +2 -0
- pysisyphus/filtertrj.py +69 -0
- pysisyphus/helpers.py +623 -0
- pysisyphus/helpers_pure.py +649 -0
- pysisyphus/init_logging.py +50 -0
- pysisyphus/intcoords/Bend.py +69 -0
- pysisyphus/intcoords/Bend2.py +25 -0
- pysisyphus/intcoords/BondedFragment.py +32 -0
- pysisyphus/intcoords/Cartesian.py +41 -0
- pysisyphus/intcoords/CartesianCoords.py +140 -0
- pysisyphus/intcoords/Coords.py +56 -0
- pysisyphus/intcoords/DLC.py +197 -0
- pysisyphus/intcoords/DistanceFunction.py +34 -0
- pysisyphus/intcoords/DummyImproper.py +70 -0
- pysisyphus/intcoords/DummyTorsion.py +72 -0
- pysisyphus/intcoords/LinearBend.py +105 -0
- pysisyphus/intcoords/LinearDisplacement.py +80 -0
- pysisyphus/intcoords/OutOfPlane.py +59 -0
- pysisyphus/intcoords/PrimTypes.py +286 -0
- pysisyphus/intcoords/Primitive.py +137 -0
- pysisyphus/intcoords/RedundantCoords.py +659 -0
- pysisyphus/intcoords/RobustTorsion.py +59 -0
- pysisyphus/intcoords/Rotation.py +147 -0
- pysisyphus/intcoords/Stretch.py +31 -0
- pysisyphus/intcoords/Torsion.py +101 -0
- pysisyphus/intcoords/Torsion2.py +25 -0
- pysisyphus/intcoords/Translation.py +45 -0
- pysisyphus/intcoords/__init__.py +61 -0
- pysisyphus/intcoords/augment_bonds.py +126 -0
- pysisyphus/intcoords/derivatives.py +10512 -0
- pysisyphus/intcoords/eval.py +80 -0
- pysisyphus/intcoords/exceptions.py +37 -0
- pysisyphus/intcoords/findiffs.py +48 -0
- pysisyphus/intcoords/generate_derivatives.py +414 -0
- pysisyphus/intcoords/helpers.py +235 -0
- pysisyphus/intcoords/logging_conf.py +10 -0
- pysisyphus/intcoords/mp_derivatives.py +10836 -0
- pysisyphus/intcoords/setup.py +962 -0
- pysisyphus/intcoords/setup_fast.py +176 -0
- pysisyphus/intcoords/update.py +272 -0
- pysisyphus/intcoords/valid.py +89 -0
- pysisyphus/interpolate/Geodesic.py +93 -0
- pysisyphus/interpolate/IDPP.py +55 -0
- pysisyphus/interpolate/Interpolator.py +116 -0
- pysisyphus/interpolate/LST.py +70 -0
- pysisyphus/interpolate/Redund.py +152 -0
- pysisyphus/interpolate/__init__.py +9 -0
- pysisyphus/interpolate/helpers.py +34 -0
- pysisyphus/io/__init__.py +22 -0
- pysisyphus/io/aomix.py +178 -0
- pysisyphus/io/cjson.py +24 -0
- pysisyphus/io/crd.py +101 -0
- pysisyphus/io/cube.py +220 -0
- pysisyphus/io/fchk.py +184 -0
- pysisyphus/io/hdf5.py +49 -0
- pysisyphus/io/hessian.py +72 -0
- pysisyphus/io/mol2.py +146 -0
- pysisyphus/io/molden.py +293 -0
- pysisyphus/io/orca.py +189 -0
- pysisyphus/io/pdb.py +269 -0
- pysisyphus/io/psf.py +79 -0
- pysisyphus/io/pubchem.py +31 -0
- pysisyphus/io/qcschema.py +34 -0
- pysisyphus/io/sdf.py +29 -0
- pysisyphus/io/xyz.py +61 -0
- pysisyphus/io/zmat.py +175 -0
- pysisyphus/irc/DWI.py +108 -0
- pysisyphus/irc/DampedVelocityVerlet.py +134 -0
- pysisyphus/irc/Euler.py +22 -0
- pysisyphus/irc/EulerPC.py +345 -0
- pysisyphus/irc/GonzalezSchlegel.py +187 -0
- pysisyphus/irc/IMKMod.py +164 -0
- pysisyphus/irc/IRC.py +878 -0
- pysisyphus/irc/IRCDummy.py +10 -0
- pysisyphus/irc/Instanton.py +307 -0
- pysisyphus/irc/LQA.py +53 -0
- pysisyphus/irc/ModeKill.py +136 -0
- pysisyphus/irc/ParamPlot.py +53 -0
- pysisyphus/irc/RK4.py +36 -0
- pysisyphus/irc/__init__.py +31 -0
- pysisyphus/irc/initial_displ.py +219 -0
- pysisyphus/linalg.py +411 -0
- pysisyphus/line_searches/Backtracking.py +88 -0
- pysisyphus/line_searches/HagerZhang.py +184 -0
- pysisyphus/line_searches/LineSearch.py +232 -0
- pysisyphus/line_searches/StrongWolfe.py +108 -0
- pysisyphus/line_searches/__init__.py +9 -0
- pysisyphus/line_searches/interpol.py +15 -0
- pysisyphus/modefollow/NormalMode.py +40 -0
- pysisyphus/modefollow/__init__.py +10 -0
- pysisyphus/modefollow/davidson.py +199 -0
- pysisyphus/modefollow/lanczos.py +95 -0
- pysisyphus/optimizers/BFGS.py +99 -0
- pysisyphus/optimizers/BacktrackingOptimizer.py +113 -0
- pysisyphus/optimizers/ConjugateGradient.py +98 -0
- pysisyphus/optimizers/CubicNewton.py +75 -0
- pysisyphus/optimizers/FIRE.py +113 -0
- pysisyphus/optimizers/HessianOptimizer.py +1176 -0
- pysisyphus/optimizers/LBFGS.py +228 -0
- pysisyphus/optimizers/LayerOpt.py +411 -0
- pysisyphus/optimizers/MicroOptimizer.py +169 -0
- pysisyphus/optimizers/NCOptimizer.py +90 -0
- pysisyphus/optimizers/Optimizer.py +1084 -0
- pysisyphus/optimizers/PreconLBFGS.py +260 -0
- pysisyphus/optimizers/PreconSteepestDescent.py +7 -0
- pysisyphus/optimizers/QuickMin.py +74 -0
- pysisyphus/optimizers/RFOptimizer.py +181 -0
- pysisyphus/optimizers/RSA.py +99 -0
- pysisyphus/optimizers/StabilizedQNMethod.py +248 -0
- pysisyphus/optimizers/SteepestDescent.py +23 -0
- pysisyphus/optimizers/StringOptimizer.py +173 -0
- pysisyphus/optimizers/__init__.py +41 -0
- pysisyphus/optimizers/closures.py +301 -0
- pysisyphus/optimizers/cls_map.py +58 -0
- pysisyphus/optimizers/exceptions.py +6 -0
- pysisyphus/optimizers/gdiis.py +280 -0
- pysisyphus/optimizers/guess_hessians.py +311 -0
- pysisyphus/optimizers/hessian_updates.py +355 -0
- pysisyphus/optimizers/poly_fit.py +285 -0
- pysisyphus/optimizers/precon.py +153 -0
- pysisyphus/optimizers/restrict_step.py +24 -0
- pysisyphus/pack.py +172 -0
- pysisyphus/peakdetect.py +948 -0
- pysisyphus/plot.py +1031 -0
- pysisyphus/run.py +2106 -0
- pysisyphus/socket_helper.py +74 -0
- pysisyphus/stocastic/FragmentKick.py +132 -0
- pysisyphus/stocastic/Kick.py +81 -0
- pysisyphus/stocastic/Pipeline.py +303 -0
- pysisyphus/stocastic/__init__.py +21 -0
- pysisyphus/stocastic/align.py +127 -0
- pysisyphus/testing.py +96 -0
- pysisyphus/thermo.py +156 -0
- pysisyphus/trj.py +824 -0
- pysisyphus/tsoptimizers/RSIRFOptimizer.py +56 -0
- pysisyphus/tsoptimizers/RSPRFOptimizer.py +182 -0
- pysisyphus/tsoptimizers/TRIM.py +59 -0
- pysisyphus/tsoptimizers/TSHessianOptimizer.py +463 -0
- pysisyphus/tsoptimizers/__init__.py +23 -0
- pysisyphus/wavefunction/Basis.py +239 -0
- pysisyphus/wavefunction/DIIS.py +76 -0
- pysisyphus/wavefunction/__init__.py +25 -0
- pysisyphus/wavefunction/build_ext.py +42 -0
- pysisyphus/wavefunction/cart2sph.py +190 -0
- pysisyphus/wavefunction/diabatization.py +304 -0
- pysisyphus/wavefunction/excited_states.py +435 -0
- pysisyphus/wavefunction/gen_ints.py +1811 -0
- pysisyphus/wavefunction/helpers.py +104 -0
- pysisyphus/wavefunction/ints/__init__.py +0 -0
- pysisyphus/wavefunction/ints/boys.py +193 -0
- pysisyphus/wavefunction/ints/boys_table_N_64_xasym_27.1_step_0.01.npy +0 -0
- pysisyphus/wavefunction/ints/cart_gto3d.py +176 -0
- pysisyphus/wavefunction/ints/coulomb3d.py +25928 -0
- pysisyphus/wavefunction/ints/diag_quadrupole3d.py +10036 -0
- pysisyphus/wavefunction/ints/dipole3d.py +8762 -0
- pysisyphus/wavefunction/ints/int2c2e3d.py +7198 -0
- pysisyphus/wavefunction/ints/int3c2e3d_sph.py +65040 -0
- pysisyphus/wavefunction/ints/kinetic3d.py +8240 -0
- pysisyphus/wavefunction/ints/ovlp3d.py +3777 -0
- pysisyphus/wavefunction/ints/quadrupole3d.py +15054 -0
- pysisyphus/wavefunction/ints/self_ovlp3d.py +198 -0
- pysisyphus/wavefunction/localization.py +458 -0
- pysisyphus/wavefunction/multipole.py +159 -0
- pysisyphus/wavefunction/normalization.py +36 -0
- pysisyphus/wavefunction/pop_analysis.py +134 -0
- pysisyphus/wavefunction/shells.py +1171 -0
- pysisyphus/wavefunction/wavefunction.py +504 -0
- pysisyphus/wrapper/__init__.py +11 -0
- pysisyphus/wrapper/exceptions.py +2 -0
- pysisyphus/wrapper/jmol.py +120 -0
- pysisyphus/wrapper/mwfn.py +169 -0
- pysisyphus/wrapper/packmol.py +71 -0
- pysisyphus/xyzloader.py +168 -0
- pysisyphus/yaml_mods.py +45 -0
- thermoanalysis/LICENSE +674 -0
- thermoanalysis/QCData.py +244 -0
- thermoanalysis/__init__.py +0 -0
- thermoanalysis/config.py +3 -0
- thermoanalysis/constants.py +20 -0
- thermoanalysis/thermo.py +1011 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# [1] https://doi.org/10.1063/1.3463717
|
|
2
|
+
# Comparisons of classical and Wigner sampling of transition state
|
|
3
|
+
# energy levels for quasiclassical trajectory chemical dynamics simulations
|
|
4
|
+
# Sun, Hase, 2010
|
|
5
|
+
# [2] https://doi.org/10.1002/qua.25049
|
|
6
|
+
# Effects of different initial condition samplings on photodynamics and
|
|
7
|
+
# spectrum of pyrrole
|
|
8
|
+
# Barbatti, Sen, 2015
|
|
9
|
+
# [3] https://doi.org/10.1063/1.453761
|
|
10
|
+
# The Morse oscillator in position space, momentum space, and phase space
|
|
11
|
+
# Dahl, Springborg, 1988
|
|
12
|
+
#
|
|
13
|
+
# An interesting paper also seems to be (but i never read it ...)
|
|
14
|
+
#
|
|
15
|
+
# [4] https://doi.org/10.1063/5.0039592
|
|
16
|
+
# Sampling initial positions and momenta for nuclear trajectories
|
|
17
|
+
# from quantum mechanical distributions
|
|
18
|
+
# Yao, Hase, Granucci, Persico
|
|
19
|
+
# [5] https://doi.org/10.1039/C8CP03273D
|
|
20
|
+
# Finite-temperature Wigner phase-space sampling and temperature effects on the
|
|
21
|
+
# excited-state dynamics of 2-nitronaphthalene.
|
|
22
|
+
# Zobel, Nogueira, Gonzalez
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import functools
|
|
26
|
+
from math import exp, pi
|
|
27
|
+
from typing import Callable, Optional
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
import matplotlib.pyplot as plt
|
|
31
|
+
import numpy as np
|
|
32
|
+
from numpy.typing import NDArray
|
|
33
|
+
from numpy.polynomial.laguerre import Laguerre
|
|
34
|
+
|
|
35
|
+
from pysisyphus.constants import AMU2AU, AU2EV, AU2SEC, C, KB, PLANCK
|
|
36
|
+
from pysisyphus.helpers_pure import eigval_to_wavenumber
|
|
37
|
+
from pysisyphus.io import geom_from_hessian
|
|
38
|
+
from pysisyphus.Geometry import Geometry, get_trans_rot_projector
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# From cm⁻¹ to angular frequency in atomic units
|
|
42
|
+
# cm⁻¹ * 100 -> m⁻¹
|
|
43
|
+
# m⁻¹ * C -> s⁻¹
|
|
44
|
+
NU2ANGFREQAU = 2 * pi * 100 * C * AU2SEC
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_vib_state(wavenumber: float, temperature: Optional[float] = None) -> int:
|
|
48
|
+
"""Return random vibrational state n for given wavenumber and temperature."""
|
|
49
|
+
if temperature is None:
|
|
50
|
+
return 0 # Ground state
|
|
51
|
+
|
|
52
|
+
freq = wavenumber * 100 * C # from cm⁻¹ to s⁻¹
|
|
53
|
+
vib_en_J = PLANCK * freq # Energy in J
|
|
54
|
+
quot = vib_en_J / (KB * temperature)
|
|
55
|
+
Z = np.exp(-quot / 2) / (1 - np.exp(-quot)) # Partition function
|
|
56
|
+
_1overZ = 1 / Z
|
|
57
|
+
# TODO: check for sensible values?
|
|
58
|
+
|
|
59
|
+
def get_p(n):
|
|
60
|
+
"""Probability of vibrational state with quantum number n.
|
|
61
|
+
|
|
62
|
+
Given by a Boltzmann distribution:
|
|
63
|
+
|
|
64
|
+
exp(-e_n / kT)
|
|
65
|
+
p_n = ----------------------------
|
|
66
|
+
sum_{n = 0}^N exp(-e_n / kT)
|
|
67
|
+
|
|
68
|
+
for a harmonic oscillator e_n = h * freq * (n + 1/2)
|
|
69
|
+
|
|
70
|
+
See also https://chemistry.stackexchange.com/a/61120.
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
return np.exp(-quot * (n + 0.5)) * _1overZ
|
|
74
|
+
|
|
75
|
+
# Determine sensible maximum vibrational state n.
|
|
76
|
+
n = 0
|
|
77
|
+
probabilities = list()
|
|
78
|
+
probability_sum = 0.0
|
|
79
|
+
# 1.0 may never be reached, so we stop earlier.
|
|
80
|
+
thresh = 0.999999
|
|
81
|
+
while True:
|
|
82
|
+
p = get_p(n)
|
|
83
|
+
probabilities.append(p)
|
|
84
|
+
probability_sum += p
|
|
85
|
+
if probability_sum >= thresh:
|
|
86
|
+
break
|
|
87
|
+
n += 1
|
|
88
|
+
|
|
89
|
+
# Generate random number that is smaller than the current sum.
|
|
90
|
+
while True:
|
|
91
|
+
# Sample from the possible interval
|
|
92
|
+
random_state = np.random.random() * thresh
|
|
93
|
+
if random_state < probability_sum:
|
|
94
|
+
break
|
|
95
|
+
|
|
96
|
+
cumsum = np.cumsum(probabilities)
|
|
97
|
+
for n, cs in enumerate(cumsum):
|
|
98
|
+
if cs >= random_state:
|
|
99
|
+
break
|
|
100
|
+
return n
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def normal_mode_reduced_masses(masses_rep, normal_modes):
|
|
104
|
+
return 1 / (np.square(normal_modes) / masses_rep[:, None]).sum(axis=0)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@functools.singledispatch
|
|
108
|
+
def get_wigner_sampler(
|
|
109
|
+
coords3d: NDArray[float],
|
|
110
|
+
masses: NDArray[float],
|
|
111
|
+
hessian: NDArray[float],
|
|
112
|
+
temperature: Optional[float] = None,
|
|
113
|
+
nu_thresh: float = 20.0,
|
|
114
|
+
stddevs: float = 6.0,
|
|
115
|
+
) -> Callable:
|
|
116
|
+
assert coords3d.shape == (len(masses), 3)
|
|
117
|
+
assert hessian.shape == (coords3d.size, coords3d.size)
|
|
118
|
+
|
|
119
|
+
# Projector to remove translation & rotation
|
|
120
|
+
Proj = get_trans_rot_projector(coords3d, masses, full=True)
|
|
121
|
+
masses_rep = np.repeat(masses, 3)
|
|
122
|
+
PM = Proj @ np.diag(1 / np.sqrt(masses_rep))
|
|
123
|
+
|
|
124
|
+
# Diagonalize projected, mass-weighted Hessian.
|
|
125
|
+
w, v = np.linalg.eigh(PM @ hessian @ PM.T)
|
|
126
|
+
nus = eigval_to_wavenumber(w)
|
|
127
|
+
|
|
128
|
+
# TODO: dectect if system is linear and don't hardcode dropping of first 6 modes.
|
|
129
|
+
# small_nu_mask = np.abs(nus) < nu_thresh
|
|
130
|
+
small_nu_mask = np.zeros_like(nus, dtype=bool)
|
|
131
|
+
small_nu_mask[:6] = True
|
|
132
|
+
# w = w[~small_nu_mask]
|
|
133
|
+
v = v[:, ~small_nu_mask]
|
|
134
|
+
nus = nus[~small_nu_mask]
|
|
135
|
+
# Square root of angular frequencies in atomic units. Required to convert the
|
|
136
|
+
# dimensionless Q and P values into atomic units.
|
|
137
|
+
ang_freqs_au_sqrt = np.sqrt(nus * NU2ANGFREQAU)
|
|
138
|
+
|
|
139
|
+
assert (nus >= nu_thresh).all(), "Imaginary wavenumbers are not yet handled!"
|
|
140
|
+
nnus = len(nus) # Number of non-zero wavenumbers
|
|
141
|
+
|
|
142
|
+
span = 2 * stddevs
|
|
143
|
+
# Pre-calculate some of the Laguerre polynomials
|
|
144
|
+
# We use some shortcuts for n == 0 and n == 1
|
|
145
|
+
laguerres = {
|
|
146
|
+
0: lambda _: 1.0,
|
|
147
|
+
1: lambda x: 1.0 - x,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
def get_laguerre(n):
|
|
151
|
+
lag_coeffs = np.zeros(n + 1)
|
|
152
|
+
lag_coeffs[n] = 1.0
|
|
153
|
+
return Laguerre(lag_coeffs)
|
|
154
|
+
|
|
155
|
+
for i in range(2, 11):
|
|
156
|
+
laguerres[i] = get_laguerre(i)
|
|
157
|
+
|
|
158
|
+
mm_sqrt_au = np.sqrt(masses_rep * AMU2AU)
|
|
159
|
+
M_inv_au = np.diag(1 / mm_sqrt_au)
|
|
160
|
+
|
|
161
|
+
def sampler():
|
|
162
|
+
Qs = np.zeros(nnus)
|
|
163
|
+
Ps = np.zeros(nnus)
|
|
164
|
+
for i in range(nnus):
|
|
165
|
+
n = get_vib_state(nus[i], temperature)
|
|
166
|
+
try:
|
|
167
|
+
lag = laguerres[n]
|
|
168
|
+
except KeyError:
|
|
169
|
+
lag = get_laguerre(n)
|
|
170
|
+
laguerres[n] = lag
|
|
171
|
+
# According to eq. (31) in [3], the absolute value of the Wigner function is
|
|
172
|
+
# bound between 0 and 1/π (see also Figure 3 in [3]). By omitting 1/π in the
|
|
173
|
+
# Wigner function (eq. (28) in [3]) its absolute value will be between 0 and 1.
|
|
174
|
+
# This saves us some multiplications/division as with 1/π it would also be sensible
|
|
175
|
+
# to map 'ref' from [0, 1) to [0, 1/π)].
|
|
176
|
+
prefact = (-1) ** n
|
|
177
|
+
while True:
|
|
178
|
+
q, p, ref = np.random.random_sample(3)
|
|
179
|
+
# Map q and p from [0, 1) onto chosen interval [-stddevs, stddevs)
|
|
180
|
+
q = q * span - stddevs
|
|
181
|
+
p = p * span - stddevs
|
|
182
|
+
r2 = q**2 + p**2
|
|
183
|
+
# Wigner function. Eq. (2) in [2] or (28) in [3]. Both equations
|
|
184
|
+
# differ in the presence or absence of a n! term. Here and in [3]
|
|
185
|
+
# the n! is absorbed into the Laguerre polynomial.
|
|
186
|
+
p_wig = prefact * exp(-r2) * lag(2 * r2)
|
|
187
|
+
# We don't use p and q that correspond to a negative value of the
|
|
188
|
+
# Wigner function. See the SI of [5] for a discussion.
|
|
189
|
+
if 0.0 < p_wig >= ref:
|
|
190
|
+
break
|
|
191
|
+
Qs[i] = q
|
|
192
|
+
Ps[i] = p
|
|
193
|
+
|
|
194
|
+
# The actual displacements/momenta depend on the vibrational frequencies.
|
|
195
|
+
# Now we the dimensionless units to atomic units. See eq. (5) in [1].
|
|
196
|
+
Qs /= ang_freqs_au_sqrt
|
|
197
|
+
Ps *= ang_freqs_au_sqrt
|
|
198
|
+
|
|
199
|
+
# Convert to Cartesian coordinates
|
|
200
|
+
displ = M_inv_au @ v @ Qs
|
|
201
|
+
velocities = M_inv_au @ v @ Ps
|
|
202
|
+
|
|
203
|
+
# The COM remains unaffected, as we displace along vibrations,
|
|
204
|
+
# not translations.
|
|
205
|
+
displ_coords3d = coords3d.copy() + displ.reshape(-1, 3)
|
|
206
|
+
|
|
207
|
+
# Remove rotation & translation from velocities at new coordinates.
|
|
208
|
+
P = get_trans_rot_projector(displ_coords3d, masses, full=True)
|
|
209
|
+
velocities = P.dot(velocities)
|
|
210
|
+
return displ_coords3d, velocities.reshape(-1, 3)
|
|
211
|
+
|
|
212
|
+
return sampler
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@get_wigner_sampler.register
|
|
216
|
+
def _(geom: Geometry, **kwargs):
|
|
217
|
+
return get_wigner_sampler(geom.coords3d, geom.masses, geom.hessian, **kwargs)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@get_wigner_sampler.register
|
|
221
|
+
def _(h5_fn: str, **kwargs):
|
|
222
|
+
geom = geom_from_hessian(h5_fn)
|
|
223
|
+
return get_wigner_sampler(geom)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def parse_args(args):
|
|
227
|
+
parser = argparse.ArgumentParser()
|
|
228
|
+
parser.add_argument("h5_fn", type=str, help="Filename of pysisyphus HDF5 Hessian.")
|
|
229
|
+
parser.add_argument("-n", type=int, default=100, help="Number of samples.")
|
|
230
|
+
parser.add_argument("-T", type=float, default=None, help="Temperature in K.")
|
|
231
|
+
parser.add_argument("--plotekin", action="store_true", help="Plot kinetic energy.")
|
|
232
|
+
return parser.parse_args(args)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def run():
|
|
236
|
+
args = parse_args(sys.argv[1:])
|
|
237
|
+
|
|
238
|
+
h5_fn = args.h5_fn
|
|
239
|
+
n = args.n
|
|
240
|
+
temperature = args.T
|
|
241
|
+
plotekin = args.plotekin
|
|
242
|
+
|
|
243
|
+
geom = geom_from_hessian(h5_fn)
|
|
244
|
+
|
|
245
|
+
sampler = get_wigner_sampler(geom, temperature=temperature)
|
|
246
|
+
xyzs = list()
|
|
247
|
+
velocities = np.zeros((n, len(geom.atoms), 3))
|
|
248
|
+
for i in range(n):
|
|
249
|
+
c3d, velocities[i] = sampler()
|
|
250
|
+
xyzs.append(geom.as_xyz(cart_coords=c3d))
|
|
251
|
+
|
|
252
|
+
trj_fn = f"samples_{n}_trj.xyz"
|
|
253
|
+
with open(trj_fn, "w") as handle:
|
|
254
|
+
handle.write("\n".join(xyzs))
|
|
255
|
+
|
|
256
|
+
if plotekin:
|
|
257
|
+
half_masses_au = geom.masses * AMU2AU / 2
|
|
258
|
+
|
|
259
|
+
def E_kin(v_au):
|
|
260
|
+
return (half_masses_au[:, None] * (v_au**2)).sum()
|
|
261
|
+
|
|
262
|
+
E_kins = np.array([E_kin(v) for v in velocities])
|
|
263
|
+
E_kins_eV = E_kins * AU2EV
|
|
264
|
+
_, ax = plt.subplots()
|
|
265
|
+
ax.hist(E_kins_eV, bins=100)
|
|
266
|
+
plt.show()
|