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,212 @@
|
|
|
1
|
+
import h5py
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from pysisyphus.drivers.opt import run_opt
|
|
5
|
+
from pysisyphus.helpers_pure import highlight_text
|
|
6
|
+
from pysisyphus.optimizers.RFOptimizer import RFOptimizer
|
|
7
|
+
from pysisyphus.TablePrinter import TablePrinter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def relaxed_scan(
|
|
11
|
+
geom,
|
|
12
|
+
calc_getter,
|
|
13
|
+
constrain_prims,
|
|
14
|
+
target_values,
|
|
15
|
+
title,
|
|
16
|
+
max_cycles=25,
|
|
17
|
+
trust_radius=0.5,
|
|
18
|
+
thresh=1e-2,
|
|
19
|
+
dump=True,
|
|
20
|
+
):
|
|
21
|
+
"""Relaxed scan, allowing fixing of multiple primitive internals."""
|
|
22
|
+
|
|
23
|
+
# Constrain desired primitives
|
|
24
|
+
copy_kwargs = {
|
|
25
|
+
"coord_type": "redund",
|
|
26
|
+
"coord_kwargs": {"constrain_prims": constrain_prims},
|
|
27
|
+
}
|
|
28
|
+
scan_geom = geom.copy(**copy_kwargs)
|
|
29
|
+
calc = calc_getter()
|
|
30
|
+
scan_geom.set_calculator(calc)
|
|
31
|
+
|
|
32
|
+
lengths_ = [len(inds) for prim_type, *inds in constrain_prims]
|
|
33
|
+
if all([True for l in lengths_ if l == 2]):
|
|
34
|
+
unit = "au"
|
|
35
|
+
elif all([True for l in lengths_ if l in (3, 4)]):
|
|
36
|
+
unit = "rad"
|
|
37
|
+
else:
|
|
38
|
+
unit = "au (rad)"
|
|
39
|
+
|
|
40
|
+
typed_prims = scan_geom.internal.typed_prims
|
|
41
|
+
constr_inds = [typed_prims.index(cp) for cp in constrain_prims]
|
|
42
|
+
constr_fmt = lambda arr: f"({np.array2string(arr, precision=4)}) {unit}"
|
|
43
|
+
|
|
44
|
+
def print_constraints():
|
|
45
|
+
print(f"Desired constraints: {constr_fmt(target_values)}")
|
|
46
|
+
print(f" Actual constraints: {constr_fmt(scan_geom.coords[constr_inds])}")
|
|
47
|
+
|
|
48
|
+
trj = ""
|
|
49
|
+
scan_cart_coords = [scan_geom.cart_coords.copy()]
|
|
50
|
+
scan_energies = [scan_geom.energy]
|
|
51
|
+
actual_values = [scan_geom.coords[constr_inds]]
|
|
52
|
+
|
|
53
|
+
for i in range(max_cycles):
|
|
54
|
+
print(highlight_text(f"Step {i}", level=1))
|
|
55
|
+
cur_diff = target_values - scan_geom.coords[constr_inds]
|
|
56
|
+
step = cur_diff
|
|
57
|
+
step_norm = np.linalg.norm(step)
|
|
58
|
+
print_constraints()
|
|
59
|
+
print(f" Difference: {step_norm:.6f} {unit}\n")
|
|
60
|
+
if step_norm <= thresh:
|
|
61
|
+
print(
|
|
62
|
+
f"Relaxed scan converged! Norm of proposed step <= {thresh:.4f} {unit}"
|
|
63
|
+
)
|
|
64
|
+
break
|
|
65
|
+
if step_norm > trust_radius:
|
|
66
|
+
step = trust_radius * step / step_norm
|
|
67
|
+
new_coords = scan_geom.coords.copy()
|
|
68
|
+
new_coords[constr_inds] += step
|
|
69
|
+
scan_geom.set_coords(new_coords, update_constraints=True)
|
|
70
|
+
|
|
71
|
+
prefix = f"{title}_step_{i}"
|
|
72
|
+
opt_kwargs = {
|
|
73
|
+
"prefix": prefix,
|
|
74
|
+
"h5_group_name": prefix,
|
|
75
|
+
"dump": dump,
|
|
76
|
+
}
|
|
77
|
+
opt = RFOptimizer(scan_geom, **opt_kwargs)
|
|
78
|
+
opt.run()
|
|
79
|
+
|
|
80
|
+
scan_cart_coords.append(scan_geom.cart_coords.copy())
|
|
81
|
+
scan_energies.append(scan_geom.energy)
|
|
82
|
+
actual_values.append(scan_geom.coords[constr_inds])
|
|
83
|
+
trj += scan_geom.as_xyz() + "\n"
|
|
84
|
+
|
|
85
|
+
scan_cart_coords = np.array(scan_cart_coords)
|
|
86
|
+
scan_energies = np.array(scan_energies)
|
|
87
|
+
actual_values = np.array(actual_values)
|
|
88
|
+
|
|
89
|
+
if dump:
|
|
90
|
+
trj_fn = f"{title}_scan_trj.xyz"
|
|
91
|
+
with open(trj_fn, "w") as handle:
|
|
92
|
+
handle.write(trj)
|
|
93
|
+
print(f"Dumped optimized geometries to '{trj_fn}'.")
|
|
94
|
+
|
|
95
|
+
group_name = f"scan_{title}"
|
|
96
|
+
# with h5py.File("scan.h5", "a") as handle:
|
|
97
|
+
# try:
|
|
98
|
+
# del handle[group_name]
|
|
99
|
+
# except KeyError:
|
|
100
|
+
# pass
|
|
101
|
+
# group = handle.create_group(group_name)
|
|
102
|
+
# group.create_dataset("energies", data=scan_energies)
|
|
103
|
+
# group.create_dataset("cart_coords", data=scan_cart_coords)
|
|
104
|
+
# group.create_dataset("target_values", data=target_values)
|
|
105
|
+
# group.create_dataset("actual_values", data=actual_values)
|
|
106
|
+
# dt = h5py.vlen_dtype(np.dtype("int32"))
|
|
107
|
+
# cp = np.array([(pt.value, *ind) for pt, *ind in constrain_prims])
|
|
108
|
+
# cp_dataset = group.create_dataset(
|
|
109
|
+
# "constrain_prims", (len(target_values),), dtype=dt
|
|
110
|
+
# )
|
|
111
|
+
# cp_dataset[:] = cp
|
|
112
|
+
return scan_geom, scan_cart_coords, scan_energies
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def relaxed_1d_scan(
|
|
116
|
+
geom,
|
|
117
|
+
calc_getter,
|
|
118
|
+
constrain_prims,
|
|
119
|
+
start,
|
|
120
|
+
step_size,
|
|
121
|
+
steps,
|
|
122
|
+
opt_key,
|
|
123
|
+
opt_kwargs,
|
|
124
|
+
pref=None,
|
|
125
|
+
callback=None,
|
|
126
|
+
):
|
|
127
|
+
assert geom.coord_type == "redund", "'coord_type: redund' is required!"
|
|
128
|
+
if pref is None:
|
|
129
|
+
pref = ""
|
|
130
|
+
else:
|
|
131
|
+
pref = f"{pref}_"
|
|
132
|
+
|
|
133
|
+
constr_prim = constrain_prims[0]
|
|
134
|
+
copy_kwargs = {
|
|
135
|
+
"coord_type": "redund",
|
|
136
|
+
"coord_kwargs": {
|
|
137
|
+
"constrain_prims": constrain_prims,
|
|
138
|
+
"recalc_B": True,
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
constr_geom = geom.copy(**copy_kwargs)
|
|
142
|
+
constr_ind = constr_geom.internal.get_index_of_typed_prim(constrain_prims[0])
|
|
143
|
+
calc = calc_getter()
|
|
144
|
+
# Always return same calculator, so orbitals can be reused etc.
|
|
145
|
+
def _calc_getter():
|
|
146
|
+
return calc
|
|
147
|
+
|
|
148
|
+
# Drop PrimType at index 0
|
|
149
|
+
unit = "au" if len(constr_prim[1:]) == 2 else "rad"
|
|
150
|
+
|
|
151
|
+
org_val = constr_geom.coords[constr_ind]
|
|
152
|
+
cur_val = start
|
|
153
|
+
end_val = start + step_size * steps
|
|
154
|
+
target_scan_vals = np.linspace(cur_val, end_val, steps + 1)
|
|
155
|
+
print(
|
|
156
|
+
f" Coordinate: {constr_prim}\n"
|
|
157
|
+
f"Original value: {org_val:.4f} {unit}\n"
|
|
158
|
+
f" Initial value: {cur_val:.4f} {unit}\n"
|
|
159
|
+
f" Final value: {end_val:.4f} {unit}\n"
|
|
160
|
+
f" Steps: {steps}+1\n"
|
|
161
|
+
f" Step size: {step_size:.4f} {unit}\n"
|
|
162
|
+
)
|
|
163
|
+
scan_vals = list()
|
|
164
|
+
scan_geoms = list()
|
|
165
|
+
scan_energies = list()
|
|
166
|
+
scan_xyzs = list()
|
|
167
|
+
|
|
168
|
+
for cycle, cur_val in enumerate(target_scan_vals):
|
|
169
|
+
opt_kwargs_ = opt_kwargs.copy()
|
|
170
|
+
name = f"{pref}relaxed_scan_{cycle:04d}"
|
|
171
|
+
opt_kwargs_["prefix"] = name
|
|
172
|
+
opt_kwargs_["h5_group_name"] = name
|
|
173
|
+
# Keep a copy
|
|
174
|
+
scan_geoms.append(constr_geom.copy())
|
|
175
|
+
|
|
176
|
+
# Update constrained coordinate
|
|
177
|
+
new_coords = constr_geom.coords
|
|
178
|
+
new_coords[constr_ind] = cur_val
|
|
179
|
+
constr_geom.set_coords(new_coords, update_constraints=True)
|
|
180
|
+
|
|
181
|
+
title = f"{pref}Step {cycle:02d}, coord={cur_val:.4f} {unit}"
|
|
182
|
+
opt_result = run_opt(
|
|
183
|
+
constr_geom, _calc_getter, opt_key, opt_kwargs_, title=title, level=1
|
|
184
|
+
)
|
|
185
|
+
if callback is not None:
|
|
186
|
+
callback(opt_result)
|
|
187
|
+
scan_xyzs.append(constr_geom.as_xyz())
|
|
188
|
+
scan_vals.append(constr_geom.coords[constr_ind])
|
|
189
|
+
scan_energies.append(constr_geom.energy)
|
|
190
|
+
|
|
191
|
+
if not opt_result.opt.is_converged:
|
|
192
|
+
print(f"Step {cycle} did not converge. Breaking!")
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
with open(f"{pref}relaxed_scan_trj.xyz", "w") as handle:
|
|
196
|
+
handle.write("\n".join(scan_xyzs))
|
|
197
|
+
|
|
198
|
+
scan_data = np.stack((scan_vals, scan_energies), axis=1)
|
|
199
|
+
np.savetxt(f"{pref}relaxed_scan.dat", scan_data)
|
|
200
|
+
scan_vals, scan_energies = scan_data.T
|
|
201
|
+
|
|
202
|
+
print(highlight_text(f"Scan summary", level=1))
|
|
203
|
+
col_fmts = "int float float float float".split()
|
|
204
|
+
header = ("Step", f"Target / {unit}", f"Actual / {unit}", f"Δ / {unit}", "E / au")
|
|
205
|
+
table = TablePrinter(header, col_fmts, width=14)
|
|
206
|
+
table.print_header()
|
|
207
|
+
for step, (target, act, en) in enumerate(
|
|
208
|
+
zip(target_scan_vals, scan_vals, scan_energies)
|
|
209
|
+
):
|
|
210
|
+
delta = target - act
|
|
211
|
+
table.print_row((step, target, act, delta, en))
|
|
212
|
+
return scan_geoms, scan_vals, scan_energies
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# [1] https://gaussian.com/uvvisplot/
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Tuple
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
from pysisyphus.constants import AU2J, C, M_E, NA, PLANCK, AU2EV
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Computation of prefactor from Gaussian whitepaper
|
|
15
|
+
Q_E_ESU = 4.803204e-10 # Crazy unit, cm**1.5 g**0.5 s⁻¹
|
|
16
|
+
C_CM = C * 100 # Speed of light in cm/s
|
|
17
|
+
M_E_G = M_E * 1000 # Electron mass in gram
|
|
18
|
+
NM2CM = 1e7 # Nanometer to centimeter
|
|
19
|
+
PREFACTOR = ( # Prefactor in eq. (5) of [1]
|
|
20
|
+
np.sqrt(np.pi) * NA * Q_E_ESU**2 / (1e3 * np.log(10) * C_CM**2 * M_E_G)
|
|
21
|
+
) / NM2CM
|
|
22
|
+
_04EV = 0.4 / AU2EV # in Hartree
|
|
23
|
+
# Factor used in converting energy in Hartree to wavelength
|
|
24
|
+
_AU2NM = PLANCK * C * 1e9 / AU2J
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclasses.dataclass
|
|
28
|
+
class Spectrum:
|
|
29
|
+
exc_ens: NDArray[float]
|
|
30
|
+
exc_ens_nm: NDArray[float]
|
|
31
|
+
fosc: NDArray[float]
|
|
32
|
+
nm: NDArray[float]
|
|
33
|
+
epsilon: NDArray[float]
|
|
34
|
+
|
|
35
|
+
def plot(self, **kwargs):
|
|
36
|
+
plot_spectrum(self.nm, self.epsilon, self.exc_ens_nm, self.fosc, **kwargs)
|
|
37
|
+
|
|
38
|
+
def save(self, fn):
|
|
39
|
+
act_fn = Path(fn).with_suffix(".npz")
|
|
40
|
+
data = dataclasses.asdict(self)
|
|
41
|
+
np.savez(act_fn, **data)
|
|
42
|
+
return act_fn
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def load(fn):
|
|
46
|
+
handle = np.load(fn)
|
|
47
|
+
kwargs = {key: handle[key] for key in handle.files}
|
|
48
|
+
return Spectrum(**kwargs)
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def from_orca(wf_fn, cis_fn, log_fn, **kwargs):
|
|
52
|
+
from pysisyphus.calculators.ORCA import get_exc_ens_fosc
|
|
53
|
+
|
|
54
|
+
exc_ens, fosc = get_exc_ens_fosc(wf_fn, cis_fn, log_fn)
|
|
55
|
+
return spectrum_from_ens_fosc(exc_ens, fosc, **kwargs)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def au2nm(au):
|
|
59
|
+
return _AU2NM / au
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_grid(resolution, exc_ens, padding, min_, max_):
|
|
63
|
+
from_ = min(min_, int(exc_ens.min() - padding))
|
|
64
|
+
to_ = max(max_, int(exc_ens.max() + padding))
|
|
65
|
+
return np.arange(from_, to_ + resolution, step=resolution)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def homogeneous_broadening(
|
|
69
|
+
exc_ens: NDArray[float],
|
|
70
|
+
osc_strengths: NDArray[float],
|
|
71
|
+
resolution: float = 0.5,
|
|
72
|
+
stddev: float = _04EV,
|
|
73
|
+
from_to=None,
|
|
74
|
+
) -> Tuple[NDArray[float], NDArray[float]]:
|
|
75
|
+
"""Homogeneous broadening of stick spectra as outlined in Gaussian
|
|
76
|
+
whitepaper [1].
|
|
77
|
+
|
|
78
|
+
σ = 0.0147 au corresponds to about 0.4 eV. The function yields molar
|
|
79
|
+
extinction coefficients in l mol cm⁻¹."""
|
|
80
|
+
exc_ens_nm = au2nm(exc_ens)
|
|
81
|
+
if from_to is None:
|
|
82
|
+
from_to = np.array((exc_ens_nm[0], exc_ens_nm[-1]))
|
|
83
|
+
nm = get_grid(resolution, from_to, padding=100, min_=300, max_=900)
|
|
84
|
+
stddev_nm = au2nm(stddev)
|
|
85
|
+
|
|
86
|
+
quot = stddev_nm * (1 / nm[None, :] - (1 / exc_ens_nm[:, None]))
|
|
87
|
+
exp_ = np.exp(-(quot**2))
|
|
88
|
+
epsilon = PREFACTOR * osc_strengths[:, None] * stddev_nm * exp_
|
|
89
|
+
epsilon = epsilon.sum(axis=0)
|
|
90
|
+
return nm, epsilon
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def spectrum_from_ens_fosc(exc_ens, fosc, **kwargs):
|
|
94
|
+
exc_ens_nm = au2nm(exc_ens)
|
|
95
|
+
nm, epsilon = homogeneous_broadening(exc_ens, fosc, **kwargs)
|
|
96
|
+
spectrum = Spectrum(
|
|
97
|
+
exc_ens=exc_ens,
|
|
98
|
+
exc_ens_nm=exc_ens_nm,
|
|
99
|
+
fosc=fosc,
|
|
100
|
+
nm=nm,
|
|
101
|
+
epsilon=epsilon,
|
|
102
|
+
)
|
|
103
|
+
return spectrum
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def homogeneous_broadening_eV(
|
|
107
|
+
exc_ens: NDArray[float],
|
|
108
|
+
osc_strengths: NDArray[float],
|
|
109
|
+
resolution: float = 0.05,
|
|
110
|
+
stddev: float = 0.4,
|
|
111
|
+
from_to=None,
|
|
112
|
+
) -> NDArray[float]:
|
|
113
|
+
"""
|
|
114
|
+
Homogeneous broadening of stick spectra as outlined in eq. (5) and (6)
|
|
115
|
+
of https://doi.org/10.1063/1.4948471.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
exc_ens
|
|
120
|
+
Excitation energies in Hartree.
|
|
121
|
+
osc_strengths
|
|
122
|
+
Unitless oscillator strengths.
|
|
123
|
+
resolution
|
|
124
|
+
Resolution of broadened spectra in eV.
|
|
125
|
+
stddev
|
|
126
|
+
Standard deviation, sigma in eq. (6).
|
|
127
|
+
from_to
|
|
128
|
+
Limits for abscissa of spectrum in eV.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
eV
|
|
133
|
+
Spectral grid in eV.
|
|
134
|
+
epsilon
|
|
135
|
+
Molar extinction coefficient.
|
|
136
|
+
"""
|
|
137
|
+
exc_ens_eV = exc_ens * AU2EV
|
|
138
|
+
if from_to is None:
|
|
139
|
+
from_to = np.array((exc_ens_eV[0], exc_ens_eV[-1]))
|
|
140
|
+
eV = get_grid(resolution, from_to, padding=2, min_=0, max_=5)
|
|
141
|
+
epsilon = (osc_strengths / (3.7922e33 * 4 * 2.926e-39 * np.sqrt(np.pi) * stddev))[
|
|
142
|
+
None, :
|
|
143
|
+
] * np.exp(-(((eV[None, :] - exc_ens_eV) / stddev) ** 2))
|
|
144
|
+
epsilon = epsilon.sum(axis=0)
|
|
145
|
+
return eV, epsilon
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def plot_spectrum(nm, epsilon, exc_ens_nm=None, fosc=None, show=False):
|
|
149
|
+
fig, ax = plt.subplots()
|
|
150
|
+
ax.plot(nm, epsilon)
|
|
151
|
+
ax.set_ylabel(r"$\epsilon$")
|
|
152
|
+
ax.set_xlabel(r"$\lambda$ / nm")
|
|
153
|
+
axs = [
|
|
154
|
+
ax,
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
if (exc_ens_nm is not None) and (fosc is not None):
|
|
158
|
+
ax2 = ax.twinx()
|
|
159
|
+
ax2.stem(exc_ens_nm, fosc, "r", markerfmt=" ", basefmt=" ")
|
|
160
|
+
ax2.set_ylabel("fosc")
|
|
161
|
+
axs.append(ax2)
|
|
162
|
+
fig.tight_layout()
|
|
163
|
+
if show:
|
|
164
|
+
plt.show()
|
|
165
|
+
|
|
166
|
+
return fig, axs
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pysisyphus.config import p_DEFAULT, T_DEFAULT
|
|
5
|
+
from pysisyphus.thermo import get_thermoanalysis_from_hess_h5, print_thermoanalysis
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_args(args):
|
|
9
|
+
parser = argparse.ArgumentParser()
|
|
10
|
+
parser.add_argument("hess_h5", help="HDF5 Hessian file from pysisyphus.")
|
|
11
|
+
parser.add_argument("-T", default=T_DEFAULT, type=float, help="Temperature")
|
|
12
|
+
parser.add_argument("-p", default=p_DEFAULT, type=float, help="Pressure")
|
|
13
|
+
parser.add_argument("--pg", default="c1", help="Point group.")
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"--calorie",
|
|
16
|
+
action="store_true",
|
|
17
|
+
help="Output in kcal mol⁻¹ instead of kJ mol⁻¹.",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return parser.parse_args(args)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def run_thermo():
|
|
24
|
+
args = parse_args(sys.argv[1:])
|
|
25
|
+
hess_h5 = args.hess_h5
|
|
26
|
+
T = args.T
|
|
27
|
+
p = args.p
|
|
28
|
+
point_group = args.pg
|
|
29
|
+
unit = "calorie" if args.calorie else "joule"
|
|
30
|
+
thermo = get_thermoanalysis_from_hess_h5(hess_h5, T=T, p=p, point_group=point_group)
|
|
31
|
+
print_thermoanalysis(thermo, unit=unit)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DummyColvar:
|
|
5
|
+
def eval(self, x):
|
|
6
|
+
assert np.isscalar(
|
|
7
|
+
x
|
|
8
|
+
), f"DummyColvar can only be used for scalar inputs, but got {x}!"
|
|
9
|
+
return x, 1
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Gaussian:
|
|
13
|
+
def __init__(self, w=1, s=1, x0=None, colvar=None, dump_name=None):
|
|
14
|
+
"""
|
|
15
|
+
See:
|
|
16
|
+
https://doi.org/10.1016/j.cpc.2018.02.017
|
|
17
|
+
|
|
18
|
+
V(f(x)) = w * exp(-(f(x) - f0)**2 / (2*s**2))
|
|
19
|
+
|
|
20
|
+
F(x) = -dV/dx = -dV/df * df/dx
|
|
21
|
+
|
|
22
|
+
See also:
|
|
23
|
+
https://doi.org/10.1103/PhysRevLett.90.238302
|
|
24
|
+
"""
|
|
25
|
+
# Gaussian height w and standard deviation s are read-only properties.
|
|
26
|
+
# This way they can't be accidentally altered, which would invalidate the
|
|
27
|
+
# values precomputed below.
|
|
28
|
+
self._w = w
|
|
29
|
+
self._s = s
|
|
30
|
+
if x0 is None:
|
|
31
|
+
x0 = np.array(())
|
|
32
|
+
self.x0 = np.ravel(x0)
|
|
33
|
+
|
|
34
|
+
# Collective variable
|
|
35
|
+
if colvar is None:
|
|
36
|
+
colvar = DummyColvar()
|
|
37
|
+
self.colvar = colvar
|
|
38
|
+
self.dump_name = dump_name
|
|
39
|
+
if self.dump_name:
|
|
40
|
+
self.dump_fn = (
|
|
41
|
+
dump_name
|
|
42
|
+
if self.dump_name.endswith(".gau")
|
|
43
|
+
else f"{self.dump_name}.gau"
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
self.dump_fn = None
|
|
47
|
+
|
|
48
|
+
# Reset file and write header
|
|
49
|
+
if self.dump_fn:
|
|
50
|
+
with open(self.dump_fn, "w") as handle:
|
|
51
|
+
handle.write(f"# {dump_name}\n# step s w center\n")
|
|
52
|
+
|
|
53
|
+
# Store some values, to avoid recalculation
|
|
54
|
+
self.s2 = self.s ** 2
|
|
55
|
+
self.one_over_2s2 = 1 / (2 * self.s2)
|
|
56
|
+
self.minus_w_over_s2 = -self.w / self.s2
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def w(self):
|
|
60
|
+
return self._w
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def s(self):
|
|
64
|
+
return self._s
|
|
65
|
+
|
|
66
|
+
def calculate(self, coords, x0=None, gradient=False):
|
|
67
|
+
"""Return potential and gradient for Gaussian(s) centered at x0."""
|
|
68
|
+
|
|
69
|
+
if x0 is None:
|
|
70
|
+
x0 = self.x0
|
|
71
|
+
x, cr_grad = self.colvar.eval(coords)
|
|
72
|
+
# TODO: allow colvar to supply a callback, that overrides the difference
|
|
73
|
+
# below. This will be needed to support periodic colvars, like torsion.
|
|
74
|
+
# There we can't just calculate the naive difference.
|
|
75
|
+
diff = x - np.atleast_1d(x0)
|
|
76
|
+
exp_ = np.exp(-(diff ** 2) * self.one_over_2s2)
|
|
77
|
+
to_return = self.w * exp_.sum()
|
|
78
|
+
|
|
79
|
+
if gradient:
|
|
80
|
+
try:
|
|
81
|
+
grad = np.einsum("i,i,ijk->jk", diff, exp_, cr_grad[None, :, :])
|
|
82
|
+
except TypeError:
|
|
83
|
+
grad = diff * exp_ * cr_grad
|
|
84
|
+
|
|
85
|
+
# Finalize & append gradient
|
|
86
|
+
grad *= self.minus_w_over_s2
|
|
87
|
+
to_return = to_return, grad
|
|
88
|
+
return to_return
|
|
89
|
+
|
|
90
|
+
def value(self, coords, x0=None):
|
|
91
|
+
return self.calculate(coords, x0)
|
|
92
|
+
|
|
93
|
+
def gradient(self, coords, x0=None):
|
|
94
|
+
_, grad = self.calculate(coords, x0, gradient=True)
|
|
95
|
+
return grad
|
|
96
|
+
|
|
97
|
+
def eval(self, coords, x0=None):
|
|
98
|
+
return self.calculate(coords, x0, gradient=True)
|
|
99
|
+
|
|
100
|
+
def dump(self, step, s, w, center):
|
|
101
|
+
line = f"{step:08d} {s:.12f} {w:.12f} {center:.12f}\n"
|
|
102
|
+
with open(self.dump_fn, "a") as handle:
|
|
103
|
+
handle.write(line)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from pysisyphus.dynamics.colvars import get_colvar
|
|
4
|
+
from pysisyphus.dynamics.Gaussian import Gaussian
|
|
5
|
+
from pysisyphus.dynamics.helpers import get_mb_velocities_for_geom
|
|
6
|
+
from pysisyphus.dynamics.mdp import mdp
|
|
7
|
+
from pysisyphus.dynamics.rattle import rattle_closure
|
|
8
|
+
from pysisyphus.dynamics.driver import md
|
|
9
|
+
from pysisyphus.dynamics.wigner import get_wigner_sampler
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("dynamics")
|
|
13
|
+
logger.setLevel(logging.DEBUG)
|
|
14
|
+
# delay = True prevents creation of empty logfiles
|
|
15
|
+
handler = logging.FileHandler("dynamics.log", mode="w", delay=True)
|
|
16
|
+
# fmt_str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
17
|
+
fmt_str = "%(asctime)s - %(message)s"
|
|
18
|
+
formatter = logging.Formatter(fmt_str)
|
|
19
|
+
handler.setFormatter(formatter)
|
|
20
|
+
logger.addHandler(handler)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import types
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import autograd
|
|
6
|
+
import autograd.numpy as anp
|
|
7
|
+
|
|
8
|
+
from pysisyphus.intcoords.derivatives import dq_b, dq_a
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Colvar(metaclass=abc.ABCMeta):
|
|
12
|
+
def __init__(self, force_agrad=False):
|
|
13
|
+
try:
|
|
14
|
+
getattr(self, "_gradient")
|
|
15
|
+
except AttributeError:
|
|
16
|
+
force_agrad = True
|
|
17
|
+
|
|
18
|
+
# Set autograd gradient method, if no _gradient is not implemented
|
|
19
|
+
# a autograd is forced.
|
|
20
|
+
if force_agrad:
|
|
21
|
+
grad_func = autograd.grad(self.value)
|
|
22
|
+
|
|
23
|
+
def wrapped(self, c3d):
|
|
24
|
+
return grad_func(c3d)
|
|
25
|
+
|
|
26
|
+
self._gradient = types.MethodType(wrapped, self)
|
|
27
|
+
# Store a flag to indicate use of autograd
|
|
28
|
+
self.agrad = force_agrad
|
|
29
|
+
|
|
30
|
+
@abc.abstractmethod
|
|
31
|
+
def value(self, c3d):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def gradient(self, c3d):
|
|
35
|
+
return self._gradient(c3d)
|
|
36
|
+
|
|
37
|
+
def eval(self, coords):
|
|
38
|
+
c3d = coords.reshape(-1, 3)
|
|
39
|
+
return self.value(c3d), self.gradient(c3d)
|
|
40
|
+
|
|
41
|
+
def _wilson_gradient(self, func, c3d):
|
|
42
|
+
"""Gradient of primitive internal w.r.t. Cartesians."""
|
|
43
|
+
grad = np.zeros_like(c3d)
|
|
44
|
+
grad[self.indices] = func(*c3d[self.indices].flatten()).reshape(-1, 3)
|
|
45
|
+
return grad
|
|
46
|
+
|
|
47
|
+
def __str__(self):
|
|
48
|
+
if hasattr(self, "indices"):
|
|
49
|
+
str_ = f"{self.__class__.__name__}({self.indices})"
|
|
50
|
+
else:
|
|
51
|
+
str_ = super().__str__()
|
|
52
|
+
return str_
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CVDistance(Colvar):
|
|
56
|
+
def __init__(self, indices, **kwargs):
|
|
57
|
+
self.indices = list(indices)
|
|
58
|
+
self.i, self.j = self.indices
|
|
59
|
+
super().__init__(**kwargs)
|
|
60
|
+
|
|
61
|
+
def value(self, c3d):
|
|
62
|
+
return anp.linalg.norm(c3d[self.i] - c3d[self.j])
|
|
63
|
+
|
|
64
|
+
def _gradient(self, c3d): # lgtm [py/attribute-shadows-method]
|
|
65
|
+
return self._wilson_gradient(dq_b, c3d)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class CVBend(Colvar):
|
|
69
|
+
def __init__(self, indices, **kwargs):
|
|
70
|
+
self.indices = list(indices)
|
|
71
|
+
# Bonded like
|
|
72
|
+
# i---j <- central atom
|
|
73
|
+
# |
|
|
74
|
+
# k
|
|
75
|
+
self.i, self.j, self.k = self.indices
|
|
76
|
+
super().__init__(**kwargs)
|
|
77
|
+
|
|
78
|
+
def value(self, c3d):
|
|
79
|
+
u_dash = c3d[self.i] - c3d[self.j]
|
|
80
|
+
v_dash = c3d[self.k] - c3d[self.j]
|
|
81
|
+
u_norm = anp.linalg.norm(u_dash)
|
|
82
|
+
v_norm = anp.linalg.norm(v_dash)
|
|
83
|
+
u = u_dash / u_norm
|
|
84
|
+
v = v_dash / v_norm
|
|
85
|
+
rad = anp.arccos(anp.dot(u, v))
|
|
86
|
+
return rad
|
|
87
|
+
|
|
88
|
+
def _gradient(self, c3d): # lgtm [py/attribute-shadows-method]
|
|
89
|
+
return self._wilson_gradient(dq_a, c3d)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class CVTorsion(Colvar):
|
|
93
|
+
def __init__(self, indices, **kwargs):
|
|
94
|
+
self.indices = list(indices)
|
|
95
|
+
# Bonded like
|
|
96
|
+
# i--u--j
|
|
97
|
+
# |
|
|
98
|
+
# w
|
|
99
|
+
# |
|
|
100
|
+
# k--v--l
|
|
101
|
+
self.i, self.j, self.k, self.l = self.indices
|
|
102
|
+
super().__init__(**kwargs)
|
|
103
|
+
|
|
104
|
+
def value(self, c3d):
|
|
105
|
+
u_dash = c3d[self.i] - c3d[self.j]
|
|
106
|
+
v_dash = c3d[self.l] - c3d[self.k]
|
|
107
|
+
w_dash = c3d[self.k] - c3d[self.j]
|
|
108
|
+
u_norm = anp.linalg.norm(u_dash)
|
|
109
|
+
v_norm = anp.linalg.norm(v_dash)
|
|
110
|
+
w_norm = anp.linalg.norm(w_dash)
|
|
111
|
+
u = u_dash / u_norm
|
|
112
|
+
v = v_dash / v_norm
|
|
113
|
+
w = w_dash / w_norm
|
|
114
|
+
phi_u = anp.arccos(anp.dot(u, w))
|
|
115
|
+
phi_v = anp.arccos(-anp.dot(w, v))
|
|
116
|
+
uxw = anp.cross(u, w)
|
|
117
|
+
vxw = anp.cross(v, w)
|
|
118
|
+
cos_dihed = anp.dot(uxw, vxw)/(anp.sin(phi_u)*anp.sin(phi_v))
|
|
119
|
+
# Restrict cos_dihed to the allowed interval for arccos [-1, 1]
|
|
120
|
+
cos_dihed = min(1, max(cos_dihed, -1))
|
|
121
|
+
|
|
122
|
+
rad = anp.arccos(cos_dihed)
|
|
123
|
+
if (rad != np.pi) and (anp.dot(vxw, u) < 0):
|
|
124
|
+
rad *= -1
|
|
125
|
+
return rad
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
COLVARS = {
|
|
129
|
+
"distance": CVDistance,
|
|
130
|
+
"bend": CVBend,
|
|
131
|
+
"torsion": CVTorsion,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_colvar(key, kwargs):
|
|
136
|
+
return COLVARS[key](**kwargs)
|