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,375 @@
|
|
|
1
|
+
# [1] https://doi.org/10.1021/acs.jctc.0c01306
|
|
2
|
+
# Single-Point Hessian Calculations for Improved Vibrational Frequencies and
|
|
3
|
+
# Rigid-Rotor-Harmonic-Oscillator Thermodynamics
|
|
4
|
+
# Spicher, Grimme
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from math import floor, ceil
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import shutil
|
|
11
|
+
from typing import Callable, Dict, Optional, Tuple
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from pysisyphus.calculators import Dimer, ExternalPotential
|
|
17
|
+
from pysisyphus.cos.ChainOfStates import ChainOfStates
|
|
18
|
+
from pysisyphus.config import T_DEFAULT, p_DEFAULT
|
|
19
|
+
from pysisyphus.Geometry import Geometry
|
|
20
|
+
from pysisyphus.helpers import do_final_hessian
|
|
21
|
+
from pysisyphus.helpers_pure import highlight_text, report_frozen_atoms
|
|
22
|
+
from pysisyphus.io import save_hessian
|
|
23
|
+
from pysisyphus.modefollow import NormalMode, geom_davidson
|
|
24
|
+
from pysisyphus.optimizers.cls_map import get_opt_cls, key_is_tsopt
|
|
25
|
+
from pysisyphus.optimizers.Optimizer import Optimizer
|
|
26
|
+
from pysisyphus.optimizers.HessianOptimizer import HessianOptimizer
|
|
27
|
+
from pysisyphus.optimizers.hessian_updates import bfgs_update
|
|
28
|
+
from pysisyphus.tsoptimizers.TSHessianOptimizer import TSHessianOptimizer
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def opt_davidson(opt, tsopt=True, res_rms_thresh=1e-4):
|
|
32
|
+
try:
|
|
33
|
+
H = opt.H
|
|
34
|
+
except AttributeError:
|
|
35
|
+
if tsopt:
|
|
36
|
+
raise Exception("Can't handle TS optimization without Hessian yet!")
|
|
37
|
+
|
|
38
|
+
# Create approximate updated Hessian
|
|
39
|
+
cart_coords = opt.cart_coords
|
|
40
|
+
cart_forces = opt.cart_forces
|
|
41
|
+
coord_diffs = np.diff(cart_coords, axis=0)
|
|
42
|
+
grad_diffs = -np.diff(cart_forces, axis=0)
|
|
43
|
+
H = np.eye(cart_coords[0].size)
|
|
44
|
+
for s, y in zip(coord_diffs, grad_diffs):
|
|
45
|
+
dH, _ = bfgs_update(H, s, y)
|
|
46
|
+
H += dH
|
|
47
|
+
|
|
48
|
+
geom = opt.geometry
|
|
49
|
+
if geom.coord_type != "cart":
|
|
50
|
+
H = geom.internal.backtransform_hessian(H)
|
|
51
|
+
|
|
52
|
+
masses_rep = geom.masses_rep
|
|
53
|
+
# Mass-weigh and project Hessian
|
|
54
|
+
H = geom.eckart_projection(geom.mass_weigh_hessian(H))
|
|
55
|
+
w, v = np.linalg.eigh(H)
|
|
56
|
+
inds = [0, 1] if tsopt else [6]
|
|
57
|
+
# Converge the lowest two modes for TS optimizations; for minimizations the lowest
|
|
58
|
+
# mode would is enough.
|
|
59
|
+
lowest = 2 if tsopt else 1
|
|
60
|
+
guess_modes = [NormalMode(l, masses_rep) for l in v[:, inds].T]
|
|
61
|
+
|
|
62
|
+
davidson_kwargs = {
|
|
63
|
+
"hessian_precon": H,
|
|
64
|
+
"guess_modes": guess_modes,
|
|
65
|
+
"lowest": lowest,
|
|
66
|
+
"res_rms_thresh": res_rms_thresh,
|
|
67
|
+
"remove_trans_rot": True,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
result = geom_davidson(geom, **davidson_kwargs)
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class OptResult:
|
|
76
|
+
opt: Optimizer
|
|
77
|
+
geom: Geometry
|
|
78
|
+
fn: Path
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def run_opt(
|
|
82
|
+
geom,
|
|
83
|
+
calc_getter,
|
|
84
|
+
opt_key,
|
|
85
|
+
opt_kwargs=None,
|
|
86
|
+
iterative=False,
|
|
87
|
+
iterative_max_cycles=5,
|
|
88
|
+
iterative_thresh=-15,
|
|
89
|
+
iterative_scale=2.00,
|
|
90
|
+
cart_hessian=None,
|
|
91
|
+
print_thermo=False,
|
|
92
|
+
title="Optimization",
|
|
93
|
+
copy_final_geom=None,
|
|
94
|
+
level=0,
|
|
95
|
+
save_hessian=False,
|
|
96
|
+
):
|
|
97
|
+
is_cos = issubclass(type(geom), ChainOfStates)
|
|
98
|
+
is_tsopt = key_is_tsopt(opt_key)
|
|
99
|
+
# Disallow iterative optimizations for COS objects
|
|
100
|
+
if opt_kwargs is None:
|
|
101
|
+
opt_kwargs = dict()
|
|
102
|
+
is_iterative = (not is_cos) and (iterative or opt_kwargs.pop("iterative", False))
|
|
103
|
+
|
|
104
|
+
if is_cos:
|
|
105
|
+
# Set calculators on all images
|
|
106
|
+
for image in geom.images:
|
|
107
|
+
image.set_calculator(calc_getter())
|
|
108
|
+
title = str(geom)
|
|
109
|
+
else:
|
|
110
|
+
geom.set_calculator(calc_getter())
|
|
111
|
+
geom.cart_hessian = cart_hessian
|
|
112
|
+
|
|
113
|
+
do_hess = opt_kwargs.pop("do_hess", False)
|
|
114
|
+
do_davidson = opt_kwargs.pop("do_davidson", False)
|
|
115
|
+
T = opt_kwargs.pop("T", T_DEFAULT)
|
|
116
|
+
p = opt_kwargs.pop("p", p_DEFAULT)
|
|
117
|
+
propagate = opt_kwargs.pop("propagate", False)
|
|
118
|
+
|
|
119
|
+
opt_cls = get_opt_cls(opt_key)
|
|
120
|
+
for i in range(iterative_max_cycles):
|
|
121
|
+
# Modify hessian_init in later cycles, te reuse the calculated Hessian
|
|
122
|
+
# from the final geometry of the previous optimization.
|
|
123
|
+
if (i > 0) and issubclass(opt_cls, HessianOptimizer):
|
|
124
|
+
opt_kwargs["hessian_init"] = "calc"
|
|
125
|
+
opt = opt_cls(geom, **opt_kwargs)
|
|
126
|
+
print(highlight_text(f"Running {title}", level=level) + "\n")
|
|
127
|
+
print(f" Input geometry: {geom.describe()}")
|
|
128
|
+
print(f" Coordinate system: {geom.coord_type}")
|
|
129
|
+
print(f" Coordinate number: {len(geom.coords)}")
|
|
130
|
+
print(f" Calculator: {geom.calculator}")
|
|
131
|
+
print(f" Charge: {geom.calculator.charge}")
|
|
132
|
+
print(f" Multiplicity: {geom.calculator.mult}")
|
|
133
|
+
print(f" Optimizer: {opt_key}\n")
|
|
134
|
+
report_frozen_atoms(geom)
|
|
135
|
+
print()
|
|
136
|
+
|
|
137
|
+
# Try to propagate chkfiles along calculators in COS optimizations
|
|
138
|
+
if propagate and is_cos:
|
|
139
|
+
print("Propagating chkfiles along COS")
|
|
140
|
+
for j, image in enumerate(geom.images):
|
|
141
|
+
image.energy
|
|
142
|
+
cur_calc = image.calculator
|
|
143
|
+
try:
|
|
144
|
+
next_calc = geom.images[j + 1].calculator
|
|
145
|
+
except IndexError:
|
|
146
|
+
pass
|
|
147
|
+
try:
|
|
148
|
+
next_calc.set_chkfiles(cur_calc.get_chkfiles())
|
|
149
|
+
except AttributeError:
|
|
150
|
+
break
|
|
151
|
+
|
|
152
|
+
opt.run()
|
|
153
|
+
|
|
154
|
+
# Only do 1 cycle in non-iterative optimizations
|
|
155
|
+
if not is_iterative:
|
|
156
|
+
break
|
|
157
|
+
|
|
158
|
+
# Determine imaginary modes for subsequent displacements
|
|
159
|
+
nus, *_, cart_displs = geom.get_normal_modes()
|
|
160
|
+
below_thresh = nus < iterative_thresh
|
|
161
|
+
# Never displace along transition vector in ts-optimizations. Just skip it.
|
|
162
|
+
if is_tsopt:
|
|
163
|
+
below_thresh[0] = False
|
|
164
|
+
imag_nus = nus[below_thresh]
|
|
165
|
+
imag_displs = cart_displs[:, below_thresh].T
|
|
166
|
+
|
|
167
|
+
if len(imag_nus) == 0:
|
|
168
|
+
print(f"Iterative optimization converged in cycle {i}.")
|
|
169
|
+
break
|
|
170
|
+
|
|
171
|
+
# h5_fn = f"hess_calc_iter_{i:02d}.h5"
|
|
172
|
+
# save_hessian(h5_fn, geom)
|
|
173
|
+
# print(f"Saved HDF5-Hessian to {h5_fn}.")
|
|
174
|
+
|
|
175
|
+
print(f"\nImaginary modes below threshold of {iterative_thresh:.2f} cm⁻¹:")
|
|
176
|
+
for j, nu in enumerate(nus[below_thresh]):
|
|
177
|
+
print(f"\t{j:02d}: {nu:8.2f} cm⁻¹")
|
|
178
|
+
sys.stdout.flush()
|
|
179
|
+
|
|
180
|
+
print(f"\nGeometry after optimization cycle {i}:\n{geom.as_xyz()}")
|
|
181
|
+
|
|
182
|
+
# Displace along imaginary modes
|
|
183
|
+
for j, (nu, imag_displ) in enumerate(zip(imag_nus, imag_displs)):
|
|
184
|
+
step = iterative_scale * imag_displ
|
|
185
|
+
new_cart_coords = geom.cart_coords + step
|
|
186
|
+
geom.cart_coords = new_cart_coords
|
|
187
|
+
|
|
188
|
+
print(f"\nDisplaced geometry for optimization cycle {i+1}:\n{geom.as_xyz()}\n")
|
|
189
|
+
|
|
190
|
+
# # ChainOfStates specific
|
|
191
|
+
# if is_cos and (not opt.stopped):
|
|
192
|
+
# hei_coords, hei_energy, hei_tangent, hei_frac_index = geom.get_splined_hei()
|
|
193
|
+
# floor_ind = floor(hei_frac_index)
|
|
194
|
+
# ceil_ind = ceil(hei_frac_index)
|
|
195
|
+
# print(
|
|
196
|
+
# f"Splined HEI is at {hei_frac_index:.2f}/{len(geom.images)-1:.2f}, "
|
|
197
|
+
# f"between image {floor_ind} and {ceil_ind} (0-based indexing)."
|
|
198
|
+
# )
|
|
199
|
+
# hei_geom = Geometry(geom.images[0].atoms, hei_coords)
|
|
200
|
+
# hei_geom.energy = hei_energy
|
|
201
|
+
# hei_fn = "splined_hei.xyz"
|
|
202
|
+
# with open(hei_fn, "w") as handle:
|
|
203
|
+
# handle.write(hei_geom.as_xyz())
|
|
204
|
+
# print(f"Wrote splined HEI to '{hei_fn}'")
|
|
205
|
+
|
|
206
|
+
if copy_final_geom and opt.is_converged:
|
|
207
|
+
copy_fn = copy_final_geom
|
|
208
|
+
shutil.copy(opt.final_fn, copy_fn)
|
|
209
|
+
print(f"Copied '{opt.final_fn}' to '{copy_fn}'.")
|
|
210
|
+
|
|
211
|
+
if do_davidson and (not opt.stopped):
|
|
212
|
+
tsopt = isinstance(opt, TSHessianOptimizer.TSHessianOptimizer) or isinstance(
|
|
213
|
+
geom.calculator, Dimer
|
|
214
|
+
)
|
|
215
|
+
type_ = "TS" if tsopt else "minimum"
|
|
216
|
+
print(highlight_text(f"Davidson after {type_} search", level=1))
|
|
217
|
+
opt_davidson(opt, tsopt=tsopt)
|
|
218
|
+
elif do_hess and (not opt.stopped):
|
|
219
|
+
print()
|
|
220
|
+
prefix = opt_kwargs.get("prefix", "")
|
|
221
|
+
out_dir = opt_kwargs.get("out_dir", None)
|
|
222
|
+
do_final_hessian(
|
|
223
|
+
geom,
|
|
224
|
+
save_hessian=save_hessian,
|
|
225
|
+
write_imag_modes=True,
|
|
226
|
+
prefix=prefix,
|
|
227
|
+
T=T,
|
|
228
|
+
p=p,
|
|
229
|
+
print_thermo=print_thermo,
|
|
230
|
+
is_ts=is_tsopt,
|
|
231
|
+
out_dir=out_dir,
|
|
232
|
+
)
|
|
233
|
+
print()
|
|
234
|
+
|
|
235
|
+
opt_result = OptResult(opt, opt.geometry, opt.final_fn)
|
|
236
|
+
return opt_result
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def get_optimal_bias(
|
|
240
|
+
ref_geom: Geometry,
|
|
241
|
+
calc_getter: Callable,
|
|
242
|
+
opt_key: str,
|
|
243
|
+
opt_kwargs: Dict,
|
|
244
|
+
k_max: float,
|
|
245
|
+
k_min: float = 0.0,
|
|
246
|
+
rmsd_target: float = 0.188973,
|
|
247
|
+
rmsd_thresh: Optional[float] = None,
|
|
248
|
+
rmsd_kwargs: Optional[Dict] = None,
|
|
249
|
+
k_thresh: float = 1e-3,
|
|
250
|
+
strict=True,
|
|
251
|
+
) -> Tuple[OptResult, float, bool]:
|
|
252
|
+
"""Driver to determine optimal bias value k for RMSD restraint.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
ref_geom
|
|
257
|
+
Reference geometry. Starting point of the optimizations and reference
|
|
258
|
+
for RMSD calculations.
|
|
259
|
+
calc_getter
|
|
260
|
+
Function that returns the actual calculator, providing the energy and
|
|
261
|
+
its derivatives.
|
|
262
|
+
opt_key
|
|
263
|
+
Determines optimizer type. See pysisyphus.optimizers.cls_map.
|
|
264
|
+
opt_kwargs
|
|
265
|
+
Optional dict of arguments passed to the optimizer.
|
|
266
|
+
k_max
|
|
267
|
+
Maximum absolute value of bias factor k. Must be a > k_min.
|
|
268
|
+
k_max
|
|
269
|
+
Minimum absolute value of bias factor k. Must be a positive number >= 0.0.
|
|
270
|
+
Defaults to 0.0.
|
|
271
|
+
rmsd_target
|
|
272
|
+
Target RMSD value in au. Defaults to 0.188973 a0 (approx. 0.1 Å).
|
|
273
|
+
rmsd_thresh
|
|
274
|
+
Allowed deviation from rmsd_target in au. If omitted, 5% of rmsd_target are used.
|
|
275
|
+
rmsd_kwargs
|
|
276
|
+
Additional keyword arguments that are passed to the RMSD class, e.g., atom_indices.
|
|
277
|
+
k_thresh:
|
|
278
|
+
When the absolute value of k_bias - k_min or k_max becomes smaller than
|
|
279
|
+
k_thresh, the bisection is aborted.
|
|
280
|
+
strict
|
|
281
|
+
If True, AssertionError is raised when an optimization did not converged.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
opt_result
|
|
286
|
+
OptimizationResult object containig the Optimizer object.
|
|
287
|
+
k_opt
|
|
288
|
+
Optimal value of k_bias.
|
|
289
|
+
valid_k
|
|
290
|
+
Whether an appropriate bias value k was found.
|
|
291
|
+
"""
|
|
292
|
+
assert rmsd_target > 0.0
|
|
293
|
+
assert k_min >= 0.0
|
|
294
|
+
assert k_max > k_min
|
|
295
|
+
assert k_thresh >= 0.0
|
|
296
|
+
if rmsd_thresh is None:
|
|
297
|
+
rmsd_thresh = 0.05 * rmsd_target
|
|
298
|
+
if rmsd_kwargs is None:
|
|
299
|
+
rmsd_kwargs = dict()
|
|
300
|
+
|
|
301
|
+
opt_counter = 0
|
|
302
|
+
|
|
303
|
+
def run_biased_opt(k):
|
|
304
|
+
nonlocal opt_counter
|
|
305
|
+
geom = ref_geom.copy()
|
|
306
|
+
|
|
307
|
+
def biased_calc_getter():
|
|
308
|
+
act_calc = calc_getter()
|
|
309
|
+
_rmsd_kwargs = {
|
|
310
|
+
"type": "rmsd",
|
|
311
|
+
"k": k,
|
|
312
|
+
}
|
|
313
|
+
_rmsd_kwargs.update(rmsd_kwargs)
|
|
314
|
+
potentials = (_rmsd_kwargs,)
|
|
315
|
+
calc = ExternalPotential(
|
|
316
|
+
calculator=act_calc, potentials=potentials, geom=ref_geom
|
|
317
|
+
)
|
|
318
|
+
return calc
|
|
319
|
+
|
|
320
|
+
sys.stdout.flush()
|
|
321
|
+
prefix = f"biased_{opt_counter:02d}"
|
|
322
|
+
prefixed_opt_kwargs = opt_kwargs.copy()
|
|
323
|
+
prefixed_opt_kwargs.update(
|
|
324
|
+
{
|
|
325
|
+
"prefix": prefix,
|
|
326
|
+
"h5_group_name": f"{prefix}_opt",
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
print(f"@@@ Running optimization {opt_counter:02d} with {k=:.6f} au.")
|
|
330
|
+
opt_result = run_opt(geom, biased_calc_getter, opt_key, prefixed_opt_kwargs)
|
|
331
|
+
if strict:
|
|
332
|
+
assert opt_result.opt.is_converged
|
|
333
|
+
|
|
334
|
+
rmsd_current = ref_geom.rmsd(geom)
|
|
335
|
+
print(
|
|
336
|
+
f"@@@ Biased optimization {opt_counter:02d} with {k=:.6f} au yielded an "
|
|
337
|
+
f"RMSD of RMSD={rmsd_current:.4f} au."
|
|
338
|
+
)
|
|
339
|
+
opt_counter += 1
|
|
340
|
+
return opt_result, rmsd_current
|
|
341
|
+
|
|
342
|
+
k_bias = 0.0
|
|
343
|
+
opt_result, rmsd_current = run_biased_opt(
|
|
344
|
+
k=k_bias
|
|
345
|
+
) # Start with unbiased optimization
|
|
346
|
+
unbiased_failed = rmsd_current > rmsd_target
|
|
347
|
+
|
|
348
|
+
k_min0 = k_min
|
|
349
|
+
k_max0 = k_max
|
|
350
|
+
|
|
351
|
+
def k_is_valid(k):
|
|
352
|
+
"""Return whether k is too close to either k_min0 or k_max0."""
|
|
353
|
+
return all([abs(k_bias - k) >= k_thresh for k in (k_min0, k_max0)])
|
|
354
|
+
|
|
355
|
+
valid_k = True
|
|
356
|
+
|
|
357
|
+
# Only run the loop when the initial unbiased optimization failed. This way
|
|
358
|
+
# we don't have to check for an early return before the loop, but can keep
|
|
359
|
+
# one return statement at the end of the function.
|
|
360
|
+
while unbiased_failed and abs(rmsd_current - rmsd_target) > rmsd_thresh:
|
|
361
|
+
k_bias = -0.5 * (k_min + k_max)
|
|
362
|
+
if not (valid_k := k_is_valid(k_bias)):
|
|
363
|
+
break
|
|
364
|
+
# Biased geometry optimization
|
|
365
|
+
opt_result, rmsd_current = run_biased_opt(k_bias)
|
|
366
|
+
if rmsd_current < rmsd_target:
|
|
367
|
+
k_max = abs(k_bias)
|
|
368
|
+
elif rmsd_current > rmsd_target:
|
|
369
|
+
k_min = abs(k_bias)
|
|
370
|
+
print(
|
|
371
|
+
f"@@@ After biased optimization {opt_counter:02d}: {k_min=:.4f}, {k_bias=:.4f}, "
|
|
372
|
+
f"{k_max=:.4f}, {rmsd_current=:4f} au."
|
|
373
|
+
)
|
|
374
|
+
k_opt = k_bias
|
|
375
|
+
return opt_result, k_opt, valid_k
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from pysisyphus.helpers_pure import highlight_text
|
|
6
|
+
from pysisyphus.TablePrinter import TablePrinter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def run_perf(
|
|
10
|
+
geom,
|
|
11
|
+
calc_getter,
|
|
12
|
+
pals=None,
|
|
13
|
+
mems=None,
|
|
14
|
+
pal_range=None,
|
|
15
|
+
mem_range=None,
|
|
16
|
+
repeat=1,
|
|
17
|
+
kind="forces",
|
|
18
|
+
):
|
|
19
|
+
assert repeat > 0
|
|
20
|
+
assert pals or pal_range
|
|
21
|
+
assert mems or mem_range
|
|
22
|
+
|
|
23
|
+
func_names = {
|
|
24
|
+
"energy": "get_energy",
|
|
25
|
+
"forces": "get_forces",
|
|
26
|
+
"hessian": "get_hessian",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if pal_range is not None:
|
|
30
|
+
pals = range(*pal_range)
|
|
31
|
+
try:
|
|
32
|
+
pal_iter = tuple(pals)
|
|
33
|
+
except TypeError: # When 'pals' is a single integer
|
|
34
|
+
pal_iter = tuple((pals,))
|
|
35
|
+
|
|
36
|
+
if mem_range is not None:
|
|
37
|
+
mems = range(*mem_range)
|
|
38
|
+
try:
|
|
39
|
+
mem_iter = tuple(mems)
|
|
40
|
+
except TypeError: # When 'mems' is a single integer
|
|
41
|
+
mem_iter = tuple((mems,))
|
|
42
|
+
|
|
43
|
+
results = {}
|
|
44
|
+
for pal in pal_iter:
|
|
45
|
+
print(f"{pal=} and ", end="")
|
|
46
|
+
for mem in mem_iter:
|
|
47
|
+
print(f"{mem=}:")
|
|
48
|
+
for i in range(repeat):
|
|
49
|
+
print(f"\tRunning {kind} cycle {i:02d} ... ", end="")
|
|
50
|
+
calc = calc_getter()
|
|
51
|
+
calc.pal = pal
|
|
52
|
+
calc.mem = mem
|
|
53
|
+
start = time.time()
|
|
54
|
+
func = getattr(calc, func_names[kind])
|
|
55
|
+
_ = func(geom.atoms, geom.cart_coords)
|
|
56
|
+
dur = time.time() - start
|
|
57
|
+
td = timedelta(seconds=dur)
|
|
58
|
+
print(f"finished in {td} h")
|
|
59
|
+
sys.stdout.flush()
|
|
60
|
+
key = (pal, mem)
|
|
61
|
+
results.setdefault(key, list()).append(td)
|
|
62
|
+
print()
|
|
63
|
+
return results
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def print_perf_results(results):
|
|
67
|
+
pal_avgs = dict()
|
|
68
|
+
pal_min = 1_000_000_000 # Dummy value
|
|
69
|
+
for i, (key, tds) in enumerate(sorted(results.items())):
|
|
70
|
+
pal, mem = key
|
|
71
|
+
pal_min = min(pal, pal_min)
|
|
72
|
+
print(highlight_text(f"{i:03d}: pal={pal}, mem={mem} MB"))
|
|
73
|
+
for j, td in enumerate(tds):
|
|
74
|
+
print(f"Run {j:03d}: {td} h")
|
|
75
|
+
avg = sum(tds, timedelta(0)) / len(tds)
|
|
76
|
+
# pal_avgs.setdefault(pal, list()).append(avg)
|
|
77
|
+
pal_avgs[pal] = avg
|
|
78
|
+
print(f" Avg: {avg} h")
|
|
79
|
+
print()
|
|
80
|
+
|
|
81
|
+
avg_min = pal_avgs[pal_min]
|
|
82
|
+
print(f" pal_min: {pal_min} core(s)")
|
|
83
|
+
print("efficiency: speedup / (pal / pal_min)\n")
|
|
84
|
+
header = ("pal", "avg. / h", "speedup", "efficieny")
|
|
85
|
+
col_fmts = ("int", "str", "float", "float")
|
|
86
|
+
table = TablePrinter(header, col_fmts, width=20)
|
|
87
|
+
table.print_header()
|
|
88
|
+
for pal, avg in pal_avgs.items():
|
|
89
|
+
speedup = avg_min / avg
|
|
90
|
+
speedup_per_pal = speedup / (pal / pal_min)
|
|
91
|
+
table.print_row((pal, str(avg), speedup, speedup_per_pal))
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from math import log
|
|
2
|
+
|
|
3
|
+
from pysisyphus.config import p_DEFAULT, T_DEFAULT
|
|
4
|
+
from pysisyphus.constants import AU2KCALPERMOL, KBAU
|
|
5
|
+
from pysisyphus.helpers_pure import standard_state_corr
|
|
6
|
+
from pysisyphus import logger
|
|
7
|
+
from pysisyphus.io import geom_from_hessian
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def G_aq_from_h5_hessian(h5_hessian, solv_en, T=T_DEFAULT, p=p_DEFAULT):
|
|
11
|
+
geom = geom_from_hessian(h5_hessian)
|
|
12
|
+
thermo = geom.get_thermoanalysis(T=T, p=p)
|
|
13
|
+
dG_solv = solv_en - thermo.U_el
|
|
14
|
+
G_aq = float(thermo.G + dG_solv)
|
|
15
|
+
return G_aq
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def direct_cycle(
|
|
19
|
+
acid_h5,
|
|
20
|
+
base_h5,
|
|
21
|
+
acid_solv_en,
|
|
22
|
+
base_solv_en,
|
|
23
|
+
G_aq_H=None,
|
|
24
|
+
G_gas_H=-6.28,
|
|
25
|
+
dG_solv_H=-265.9,
|
|
26
|
+
T=T_DEFAULT,
|
|
27
|
+
p=p_DEFAULT,
|
|
28
|
+
):
|
|
29
|
+
|
|
30
|
+
G_aq_acid = G_aq_from_h5_hessian(acid_h5, acid_solv_en, T=T, p=p)
|
|
31
|
+
G_aq_base = G_aq_from_h5_hessian(base_h5, base_solv_en, T=T, p=p)
|
|
32
|
+
|
|
33
|
+
if G_aq_H is None:
|
|
34
|
+
G_aq_H = G_gas_H + dG_solv_H
|
|
35
|
+
G_aq_H /= AU2KCALPERMOL
|
|
36
|
+
|
|
37
|
+
dG_aq = G_aq_H + G_aq_base - G_aq_acid
|
|
38
|
+
dG_aq_corr = dG_aq + standard_state_corr(T=T, p=p)
|
|
39
|
+
|
|
40
|
+
pKa = dG_aq_corr / (KBAU * T * log(10))
|
|
41
|
+
|
|
42
|
+
logger.debug(
|
|
43
|
+
f"pKa calculation using direct cycle:\n"
|
|
44
|
+
f"\tAcid HDF5: {acid_h5}\n\tBase HDF5: {base_h5}\n"
|
|
45
|
+
f"\tT={T:.4f}, p={p:.1f} Pa\n"
|
|
46
|
+
f"\tG_aq_acid={G_aq_acid:.6f} au\n"
|
|
47
|
+
f"\tG_aq_base={G_aq_base:.6f} au\n"
|
|
48
|
+
f"\tG_aq_H={G_aq_H:.6f} au\n"
|
|
49
|
+
f"\tpKa={pKa:.6f}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return pKa
|