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,187 @@
|
|
|
1
|
+
from math import cos, sin
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.optimize import newton
|
|
5
|
+
|
|
6
|
+
from pysisyphus.irc.IRC import IRC
|
|
7
|
+
from pysisyphus.optimizers.hessian_updates import bfgs_update
|
|
8
|
+
from pysisyphus.TableFormatter import TableFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# [1] An improved algorithm for reaction path following
|
|
12
|
+
# http://aip.scitation.org/doi/pdf/10.1063/1.456010
|
|
13
|
+
# [2] Extension to internal coordinates (not implemented)
|
|
14
|
+
# https://pubs.acs.org/doi/pdf/10.1021/j100377a021
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GonzalezSchlegel(IRC):
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
geometry,
|
|
21
|
+
max_micro_cycles=20,
|
|
22
|
+
micro_step_thresh=1e-3,
|
|
23
|
+
hessian_recalc=None,
|
|
24
|
+
line_search=False,
|
|
25
|
+
**kwargs,
|
|
26
|
+
):
|
|
27
|
+
super().__init__(geometry, **kwargs)
|
|
28
|
+
|
|
29
|
+
self.max_micro_cycles = max_micro_cycles
|
|
30
|
+
self.micro_step_thresh = micro_step_thresh
|
|
31
|
+
self.hessian_recalc = hessian_recalc
|
|
32
|
+
self.line_search = line_search
|
|
33
|
+
if self.line_search:
|
|
34
|
+
print("!Line search seems faulty right now!")
|
|
35
|
+
|
|
36
|
+
self.pivot_coords = list()
|
|
37
|
+
self.eye = np.eye(self.geometry.coords.size)
|
|
38
|
+
self.micro_counter = 0
|
|
39
|
+
|
|
40
|
+
micro_header = "# |dx| |tangent|".split()
|
|
41
|
+
micro_fmts = ["d", ".2E", ".3E"]
|
|
42
|
+
self.micro_formatter = TableFormatter(micro_header, micro_fmts, 10)
|
|
43
|
+
|
|
44
|
+
def perp_component(self, vec, perp_to):
|
|
45
|
+
# Make unit vector
|
|
46
|
+
# perp_to /= np.linalg.norm(perp_to)
|
|
47
|
+
# Substract parallel component
|
|
48
|
+
return vec - perp_to.dot(vec) * perp_to / perp_to.dot(perp_to)#np.linalg.norm(perp_to)**2
|
|
49
|
+
|
|
50
|
+
def micro_step(self, counter):
|
|
51
|
+
"""Constrained optimization on a hypersphere."""
|
|
52
|
+
|
|
53
|
+
# Calculate gradient at current coordinates
|
|
54
|
+
gradient = self.mw_gradient
|
|
55
|
+
self.log(f"\tnorm(mw_grad)={np.linalg.norm(gradient):.6f}")
|
|
56
|
+
|
|
57
|
+
# Interpolation proposed in the paper (Eq. (12) - (15)).
|
|
58
|
+
# Does not seem to help.
|
|
59
|
+
if self.line_search and (counter > 0):
|
|
60
|
+
pivot_coords = self.pivot_coords[-1]
|
|
61
|
+
p_prev = self.prev_coords - pivot_coords # p"
|
|
62
|
+
p_cur = self.mw_coords - pivot_coords # p'
|
|
63
|
+
g_prev = self.prev_grad # g"
|
|
64
|
+
g_cur = self.gradient # g'
|
|
65
|
+
g_prev_p = self.perp_component(g_prev, p_prev)
|
|
66
|
+
g_cur_p = self.perp_component(g_cur, p_cur)
|
|
67
|
+
g_prev_p_norm = np.linalg.norm(g_prev_p)
|
|
68
|
+
g_cur_p_norm = np.linalg.norm(g_cur_p)
|
|
69
|
+
# Angle between p_prev and p_cur
|
|
70
|
+
theta_prime = np.arccos(
|
|
71
|
+
p_prev.dot(p_cur) / np.linalg.norm(p_prev) / np.linalg.norm(p_cur)
|
|
72
|
+
) # θ'
|
|
73
|
+
theta = g_prev_p_norm * theta_prime / (g_prev_p_norm - g_cur_p_norm) # θ
|
|
74
|
+
theta_quot = theta / theta_prime
|
|
75
|
+
cos_theta = cos(theta)
|
|
76
|
+
sin_theta = sin(theta)
|
|
77
|
+
cos_theta_prime = cos(theta_prime)
|
|
78
|
+
sin_theta_prime = sin(theta_prime)
|
|
79
|
+
sin_quot = sin_theta / sin_theta_prime
|
|
80
|
+
# Interpolated quantities
|
|
81
|
+
g_interp = g_prev * (1 - theta_quot) + g_cur * theta_quot
|
|
82
|
+
p_interp = (
|
|
83
|
+
p_prev * (cos_theta - sin_quot * cos_theta_prime) + p_cur * sin_quot
|
|
84
|
+
)
|
|
85
|
+
x_interp = pivot_coords + p_interp
|
|
86
|
+
gradient = g_interp
|
|
87
|
+
self.mw_coords = x_interp
|
|
88
|
+
self.displacement = p_interp
|
|
89
|
+
|
|
90
|
+
gradient_diff = gradient - self.prev_grad
|
|
91
|
+
coords_diff = self.mw_coords - self.prev_coords
|
|
92
|
+
# Update previous quantities.
|
|
93
|
+
self.prev_coords = self.mw_coords.copy()
|
|
94
|
+
self.prev_grad = gradient.copy()
|
|
95
|
+
|
|
96
|
+
# Recalculate Hessian
|
|
97
|
+
if (
|
|
98
|
+
self.hessian_recalc
|
|
99
|
+
# and (self.micro_counter > 0)
|
|
100
|
+
and (self.micro_counter % self.hessian_recalc == 0)
|
|
101
|
+
):
|
|
102
|
+
self.mw_hessian = self.geometry.mw_hessian
|
|
103
|
+
# Or update Hessian
|
|
104
|
+
else:
|
|
105
|
+
dH, _ = bfgs_update(self.mw_hessian, coords_diff, gradient_diff)
|
|
106
|
+
self.mw_hessian += dH
|
|
107
|
+
eigvals, eigvecs = np.linalg.eigh(self.mw_hessian)
|
|
108
|
+
|
|
109
|
+
constraint = (0.5 * self.step_length) ** 2
|
|
110
|
+
big = np.abs(eigvals) > 1e-8
|
|
111
|
+
big_eigvals = eigvals[big]
|
|
112
|
+
big_eigvecs = eigvecs[:, big]
|
|
113
|
+
grad_star = big_eigvecs.T.dot(gradient)
|
|
114
|
+
displ_star = big_eigvecs.T.dot(self.displacement)
|
|
115
|
+
|
|
116
|
+
def get_dx(lambda_):
|
|
117
|
+
"""In basis of Hessian eigenvectors."""
|
|
118
|
+
return -(grad_star - lambda_ * displ_star) / (big_eigvals - lambda_)
|
|
119
|
+
|
|
120
|
+
def on_sphere(lambda_):
|
|
121
|
+
p = displ_star + get_dx(lambda_)
|
|
122
|
+
return p.dot(p) - constraint
|
|
123
|
+
|
|
124
|
+
# Initial guess for λ.
|
|
125
|
+
# λ must be smaller then the smallest eigenvector
|
|
126
|
+
lambda_0 = big_eigvals[0]
|
|
127
|
+
lambda_0 *= 1.5 if (lambda_0 < 0) else 0.5
|
|
128
|
+
self.log(f"\tSmallest eigenvalue is {big_eigvals[0]:.4f}, λ_0={lambda_0:.4f}.")
|
|
129
|
+
# Find the root with scipy
|
|
130
|
+
lambda_ = newton(on_sphere, lambda_0, maxiter=500)
|
|
131
|
+
self.log(f"\tDetermined λ={lambda_0:.4f} from Newtons method.")
|
|
132
|
+
|
|
133
|
+
# Calculate dx from optimized lambda in basis of Hessian eigenvectors and
|
|
134
|
+
# transform back to mass-weighted Cartesians.
|
|
135
|
+
dx = big_eigvecs.dot(get_dx(lambda_))
|
|
136
|
+
self.displacement += dx
|
|
137
|
+
self.mw_coords += dx
|
|
138
|
+
|
|
139
|
+
grad_tangent_to_sphere = self.perp_component(gradient, self.displacement)
|
|
140
|
+
self.micro_counter += 1
|
|
141
|
+
|
|
142
|
+
dx_norm = np.linalg.norm(dx)
|
|
143
|
+
grad_norm = np.linalg.norm(grad_tangent_to_sphere)
|
|
144
|
+
self.log(f"\tnorm(dx)={dx_norm:.6f}")
|
|
145
|
+
self.log(f"\tgradient tangent to sphere={grad_norm:.6f}")
|
|
146
|
+
|
|
147
|
+
return dx, grad_tangent_to_sphere
|
|
148
|
+
|
|
149
|
+
def step(self):
|
|
150
|
+
grad0 = self.mw_gradient
|
|
151
|
+
grad0_norm = np.linalg.norm(grad0)
|
|
152
|
+
# For the BFGS update in the first micro step we use the original
|
|
153
|
+
# point and the initial guess to calculate gradient and
|
|
154
|
+
# coordinate differences.
|
|
155
|
+
self.prev_grad = grad0
|
|
156
|
+
self.prev_coords = self.mw_coords
|
|
157
|
+
|
|
158
|
+
# Take a step against the gradient to the pivot point x*_k+1.
|
|
159
|
+
pivot_step = 0.5 * self.step_length * -grad0 / grad0_norm
|
|
160
|
+
pivot_coords = self.mw_coords + pivot_step
|
|
161
|
+
self.pivot_coords.append(pivot_coords)
|
|
162
|
+
|
|
163
|
+
# Initial guess for x'_k+1 (full step from prev_coords, or another
|
|
164
|
+
# half step from the pivot point)
|
|
165
|
+
self.mw_coords = pivot_coords + pivot_step
|
|
166
|
+
|
|
167
|
+
# Initial displacement p' from the pivot point
|
|
168
|
+
self.displacement = pivot_step
|
|
169
|
+
|
|
170
|
+
micro_coords_ = list()
|
|
171
|
+
for i in range(self.max_micro_cycles):
|
|
172
|
+
self.log(f"Micro cycle {i:02d}")
|
|
173
|
+
try:
|
|
174
|
+
dx, _ = self.micro_step(i)
|
|
175
|
+
except RuntimeError:
|
|
176
|
+
print("Constrained search did not converge!")
|
|
177
|
+
self.converged = True
|
|
178
|
+
return
|
|
179
|
+
micro_coords_.append(self.mw_coords)
|
|
180
|
+
if np.linalg.norm(dx) <= self.micro_step_thresh:
|
|
181
|
+
break
|
|
182
|
+
else:
|
|
183
|
+
self.logger.warning("Max micro cycles exceeded!")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def postprocess(self):
|
|
187
|
+
self.pivot_coords = np.array(self.pivot_coords)
|
pysisyphus/irc/IMKMod.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.irc.IRC import IRC
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# [1] http://pubs.acs.org/doi/pdf/10.1021/ja00295a002
|
|
7
|
+
# [2] https://math.stackexchange.com/questions/1882772/curve-fitting-with-derivatives
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class IMKMod(IRC):
|
|
11
|
+
|
|
12
|
+
def __init__(self, geometry, corr_first=True, corr_first_size=0.5,
|
|
13
|
+
corr_first_energy=True, corr_bisec_size=0.0025,
|
|
14
|
+
corr_bisec_energy=True, **kwargs):
|
|
15
|
+
super().__init__(geometry, **kwargs)
|
|
16
|
+
|
|
17
|
+
# Correction of pivot point
|
|
18
|
+
self.corr_first = bool(corr_first)
|
|
19
|
+
self.corr_first_size = float(corr_first_size)
|
|
20
|
+
self.corr_first_energy = bool(corr_first_energy)
|
|
21
|
+
# Correction along bisector
|
|
22
|
+
self.corr_bisec_size = corr_bisec_size
|
|
23
|
+
self.corr_bisec_energy = corr_bisec_energy
|
|
24
|
+
|
|
25
|
+
self.corr_bisec_thresh = 2*self.corr_bisec_size
|
|
26
|
+
|
|
27
|
+
def fit_parabola(self, x, y):
|
|
28
|
+
y_str = np.array2string(np.array(y), precision=6)
|
|
29
|
+
self.log(f"Fitting parabola with x={x} and y={y_str}")
|
|
30
|
+
fit = np.polyfit(x, y, deg=2)
|
|
31
|
+
parabola = np.poly1d(fit)
|
|
32
|
+
minimum = parabola.deriv().r
|
|
33
|
+
# We are only looking for a real minimum
|
|
34
|
+
real_minimum = (minimum[minimum.imag==0].real)[0]
|
|
35
|
+
self.log(f"Found minimum of fitted parabola at x={real_minimum:.4f}")
|
|
36
|
+
|
|
37
|
+
return real_minimum
|
|
38
|
+
|
|
39
|
+
def fit_grad_and_energies(self, energy0, grad0, energy1, direction):
|
|
40
|
+
grad0_proj = grad0.dot(direction/np.linalg.norm(direction))
|
|
41
|
+
# f (x) = ax² + bx + c
|
|
42
|
+
# f'(x) = 2ax + b
|
|
43
|
+
#
|
|
44
|
+
# Assuming energy0 and grad0 are calculated at x=0
|
|
45
|
+
# and
|
|
46
|
+
# energy is calculated at x=1
|
|
47
|
+
c = energy0
|
|
48
|
+
b = grad0_proj
|
|
49
|
+
a = energy1 - b - c
|
|
50
|
+
coeffs = (a, b, c)
|
|
51
|
+
poly = np.poly1d(coeffs)
|
|
52
|
+
minimum = poly.deriv().r
|
|
53
|
+
# We are only looking for a real minimum
|
|
54
|
+
real_minimum = (minimum[minimum.imag==0].real)[0]
|
|
55
|
+
self.log(f"Found minimum of fitted parabola at x={real_minimum:.4f}")
|
|
56
|
+
|
|
57
|
+
return real_minimum
|
|
58
|
+
|
|
59
|
+
def step(self):
|
|
60
|
+
# Get gradient at Q0
|
|
61
|
+
mw_coords_0 = self.mw_coords.copy()
|
|
62
|
+
grad_0 = self.mw_gradient
|
|
63
|
+
energy_0 = self.energy
|
|
64
|
+
self.log(f"Current point:\n\tenergy_0={energy_0:.6f} au")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
##############
|
|
68
|
+
# PIVOT STEP #
|
|
69
|
+
##############
|
|
70
|
+
|
|
71
|
+
grad_0_norm = np.linalg.norm(grad_0)
|
|
72
|
+
dir_0 = -grad_0 / grad_0_norm
|
|
73
|
+
# Step direction is against the gradient to the pivot point Q1.
|
|
74
|
+
step = self.step_length * dir_0
|
|
75
|
+
mw_coords_1 = self.mw_coords + step
|
|
76
|
+
self.log(f"Took initial step of length {self.step_length:.6f} to pivot point")
|
|
77
|
+
self.mw_coords = mw_coords_1
|
|
78
|
+
energy_1 = self.energy
|
|
79
|
+
|
|
80
|
+
#########################
|
|
81
|
+
# PIVOT STEP CORRECTION #
|
|
82
|
+
#########################
|
|
83
|
+
|
|
84
|
+
self.log(f"Pivot point\n\tenergy_1={energy_1:.6f} au")
|
|
85
|
+
energy_diff = energy_1 - energy_0
|
|
86
|
+
if energy_diff > 0:
|
|
87
|
+
self.log(f"Energy increased at pivot point ΔE={energy_diff:.6f}")
|
|
88
|
+
correct_first_step = self.corr_first and (energy_diff > 0)
|
|
89
|
+
# Fit using energy at q0, energy at q1, and energy at half step between
|
|
90
|
+
# q0 and q1
|
|
91
|
+
corr_min = None
|
|
92
|
+
if correct_first_step and self.corr_first_energy:
|
|
93
|
+
self.log("Computing correction for pivot point from energy_0, "
|
|
94
|
+
"energy_1, and additional energy calculation.")
|
|
95
|
+
corr_step = self.corr_first_size*step
|
|
96
|
+
mw_coords_1_corr = mw_coords_0 + corr_step
|
|
97
|
+
self.mw_coords = mw_coords_1_corr
|
|
98
|
+
energy_1_corr = self.energy
|
|
99
|
+
x_corr = np.array((0, self.corr_first_size, 1))
|
|
100
|
+
y_corr = (energy_0, energy_1_corr, energy_1)
|
|
101
|
+
corr_min = self.fit_parabola(x_corr, y_corr)
|
|
102
|
+
# Fit using energy & gradient at q0, and energy at q1
|
|
103
|
+
elif correct_first_step:
|
|
104
|
+
self.log("Computing correction for pivot point from energy_0, "
|
|
105
|
+
"grad_0 and energy_1, along dir_0")
|
|
106
|
+
|
|
107
|
+
corr_min = self.fit_grad_and_energies(energy_0, grad_0, energy_1, dir_0)
|
|
108
|
+
else:
|
|
109
|
+
self.log("Skipping correction of pivot step")
|
|
110
|
+
|
|
111
|
+
if corr_min:
|
|
112
|
+
step_corr = corr_min * self.step_length * dir_0
|
|
113
|
+
mw_coords_1 = mw_coords_0 + step_corr
|
|
114
|
+
self.mw_coords = mw_coords_1
|
|
115
|
+
|
|
116
|
+
# Get gradient at Q1
|
|
117
|
+
self.log("Calculation of gradient at pivot point")
|
|
118
|
+
grad_1 = self.mw_gradient
|
|
119
|
+
energy_1 = self.energy
|
|
120
|
+
grad_1_norm = np.linalg.norm(grad_1)
|
|
121
|
+
dir_1 = -grad_1 / grad_1_norm
|
|
122
|
+
|
|
123
|
+
##############
|
|
124
|
+
# BISECTOR D #
|
|
125
|
+
##############
|
|
126
|
+
|
|
127
|
+
# Determine bisector d and normalized bisector vector D.
|
|
128
|
+
# d = grad_0/grad_0_norm - grad_1/grad_1_norm
|
|
129
|
+
d = -dir_0 + dir_1
|
|
130
|
+
D = d / np.linalg.norm(d)
|
|
131
|
+
self.log("Determined bisector D")
|
|
132
|
+
|
|
133
|
+
##########################
|
|
134
|
+
# MINIMUM SEARCH ALONG D #
|
|
135
|
+
##########################
|
|
136
|
+
|
|
137
|
+
# Take a step along D
|
|
138
|
+
step_2 = self.corr_bisec_size * D
|
|
139
|
+
mw_coords_2 = mw_coords_1 + step_2
|
|
140
|
+
self.mw_coords = mw_coords_2
|
|
141
|
+
energy_2 = self.energy
|
|
142
|
+
self.log(f"1st step along D\n\tenergy_2={energy_2:.6f} au")
|
|
143
|
+
|
|
144
|
+
if self.corr_bisec_energy:
|
|
145
|
+
if energy_2 > energy_1:
|
|
146
|
+
factor = 0.5
|
|
147
|
+
else:
|
|
148
|
+
factor = 2
|
|
149
|
+
step_3 = self.corr_bisec_size * factor * D
|
|
150
|
+
mw_coords_3 = mw_coords_1 + step_3
|
|
151
|
+
self.mw_coords = mw_coords_3
|
|
152
|
+
energy_3 = self.energy
|
|
153
|
+
self.log(f"2nd step along D\n\tenergy_3={energy_3:.6f} au")
|
|
154
|
+
x = np.array((0, 1, factor))
|
|
155
|
+
y = (energy_1, energy_2, energy_3)
|
|
156
|
+
corr_min = self.fit_parabola(x, y)
|
|
157
|
+
else:
|
|
158
|
+
self.log("Minimum search along D, by fitting energy_1, "
|
|
159
|
+
"grad_1 and energy_2.")
|
|
160
|
+
corr_min = self.fit_grad_and_energies(energy_1, grad_1, energy_2, D)
|
|
161
|
+
|
|
162
|
+
step_corr = self.corr_bisec_size * corr_min * D
|
|
163
|
+
mw_coords_4 = mw_coords_1 + step_corr
|
|
164
|
+
self.mw_coords = mw_coords_4
|