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,150 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pyparsing as pp
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def to_float(s, loc, toks):
|
|
10
|
+
match = toks[0].replace("D", "E")
|
|
11
|
+
return float(match)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def make_float_class(**kwargs):
|
|
15
|
+
return pp.Word(pp.nums + ".-DE+", **kwargs).setParseAction(to_float)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def parse_turbo_gradient(path):
|
|
19
|
+
results = {}
|
|
20
|
+
gradient_fn = glob.glob(os.path.join(path, "gradient"))
|
|
21
|
+
if not gradient_fn:
|
|
22
|
+
raise Exception("gradient file not found!")
|
|
23
|
+
assert len(gradient_fn) == 1
|
|
24
|
+
gradient_fn = gradient_fn[0]
|
|
25
|
+
with open(gradient_fn) as handle:
|
|
26
|
+
text = handle.read()
|
|
27
|
+
|
|
28
|
+
float_ = make_float_class()
|
|
29
|
+
cycle = pp.Word(pp.nums).setResultsName("cycle")
|
|
30
|
+
scf_energy = float_.setResultsName("scf_energy")
|
|
31
|
+
grad_norm = float_.setResultsName("grad_norm")
|
|
32
|
+
float_line = float_ + float_ + float_
|
|
33
|
+
coord_line = pp.Group(float_line + pp.Word(pp.alphas))
|
|
34
|
+
grad_line = pp.Group(float_line)
|
|
35
|
+
cart_grads = pp.Literal("cartesian gradients")
|
|
36
|
+
energy_type = pp.Or(
|
|
37
|
+
(
|
|
38
|
+
pp.Literal("SCF energy"),
|
|
39
|
+
pp.Literal("ex. state energy"),
|
|
40
|
+
pp.Literal("CC2 energy"),
|
|
41
|
+
pp.Literal("ADC(2) energy"),
|
|
42
|
+
pp.Literal("MP2 energy"),
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
parser = (
|
|
47
|
+
pp.Or((pp.Literal("$grad"), pp.Literal("$gradient")))
|
|
48
|
+
+ pp.Optional(cart_grads)
|
|
49
|
+
+ pp.Literal("cycle =")
|
|
50
|
+
+ cycle
|
|
51
|
+
+ energy_type
|
|
52
|
+
+ pp.Literal("=")
|
|
53
|
+
+ scf_energy
|
|
54
|
+
+ pp.Literal("|dE/dxyz| =")
|
|
55
|
+
+ grad_norm
|
|
56
|
+
+ pp.OneOrMore(coord_line).setResultsName("coords")
|
|
57
|
+
+ pp.OneOrMore(grad_line).setResultsName("grad")
|
|
58
|
+
+ pp.Literal("$end")
|
|
59
|
+
)
|
|
60
|
+
parsed = parser.parseString(text)
|
|
61
|
+
gradient = np.array(parsed["grad"].asList()).flatten()
|
|
62
|
+
|
|
63
|
+
results["energy"] = parsed["scf_energy"]
|
|
64
|
+
results["forces"] = -gradient
|
|
65
|
+
return results
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def parse_turbo_ccre0_ascii(text):
|
|
69
|
+
float_ = make_float_class()
|
|
70
|
+
float_20 = make_float_class(exact=20)
|
|
71
|
+
int_ = pp.Word(pp.nums).setParseAction(lambda s, loc, toks: int(toks[0]))
|
|
72
|
+
|
|
73
|
+
title = pp.Literal("$CCRE0-") + pp.Word(pp.nums + "-")
|
|
74
|
+
method = pp.Word(pp.alphanums + "()") + float_ + float_ + int_ + int_ + int_
|
|
75
|
+
data = pp.Group(pp.OneOrMore(float_20))
|
|
76
|
+
end = pp.Literal("$end")
|
|
77
|
+
|
|
78
|
+
parser = title + method + data.setResultsName("data") + end
|
|
79
|
+
result = parser.parseString(text)
|
|
80
|
+
data = np.array(result["data"].asList())
|
|
81
|
+
return data
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def parse_turbo_mos(text):
|
|
85
|
+
float_20 = make_float_class(exact=20)
|
|
86
|
+
int_ = pp.Word(pp.nums)
|
|
87
|
+
comment = pp.Literal("#") + pp.restOfLine
|
|
88
|
+
|
|
89
|
+
mo_num = int_
|
|
90
|
+
sym = pp.Word(pp.alphanums)
|
|
91
|
+
eigenvalue = pp.Literal("eigenvalue=") + float_20
|
|
92
|
+
nsaos = pp.Literal("nsaos=") + int_
|
|
93
|
+
mo_coeffs = pp.OneOrMore(float_20)
|
|
94
|
+
|
|
95
|
+
mo = pp.Group(
|
|
96
|
+
mo_num + sym + eigenvalue + nsaos + mo_coeffs.setResultsName("mo_coeffs")
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
parser = (
|
|
100
|
+
pp.Literal("$scfmo")
|
|
101
|
+
+ pp.Literal("scfconv=")
|
|
102
|
+
+ pp.Word(pp.nums)
|
|
103
|
+
+ pp.Literal("format(4d20.14) ")
|
|
104
|
+
+ pp.ZeroOrMore(comment)
|
|
105
|
+
+ pp.OneOrMore(mo).setResultsName("mos")
|
|
106
|
+
+ pp.Literal("$end")
|
|
107
|
+
)
|
|
108
|
+
parsed = parser.parseString(text)
|
|
109
|
+
mo_coeffs = np.array([mo.mo_coeffs.asList() for mo in parsed.mos]).T
|
|
110
|
+
|
|
111
|
+
# MOs are in columns
|
|
112
|
+
return mo_coeffs
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def parse_turbo_exstates(text):
|
|
116
|
+
"""Parse excitation energies (first blocks) from an exstates file."""
|
|
117
|
+
float_ = make_float_class()
|
|
118
|
+
exc_energies_line = (
|
|
119
|
+
pp.Literal("$excitation_energies_")
|
|
120
|
+
+ pp.Word(pp.alphanums + "()").setResultsName("model")
|
|
121
|
+
+ pp.Word("_")
|
|
122
|
+
+ pp.restOfLine
|
|
123
|
+
)
|
|
124
|
+
exc_energy = pp.Suppress(pp.Word(pp.nums)) + float_
|
|
125
|
+
exc_energies_block = pp.Group(
|
|
126
|
+
exc_energies_line + pp.Group(pp.OneOrMore(exc_energy)).setResultsName("exc_ens")
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
parser = pp.OneOrMore(exc_energies_block).setResultsName("exc_blocks")
|
|
130
|
+
result = parser.parseString(text)
|
|
131
|
+
exc_energies_by_model = [(b.model, b.exc_ens.asList()) for b in result.exc_blocks]
|
|
132
|
+
return exc_energies_by_model
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def parse_turbo_exstates_re(text):
|
|
136
|
+
results = dict()
|
|
137
|
+
exc_ens_str = "excitation_energies_"
|
|
138
|
+
model_re = re.compile(exc_ens_str + r"(\w+?)_")
|
|
139
|
+
blocks = text.strip().split("$")
|
|
140
|
+
for block in blocks:
|
|
141
|
+
if not block.startswith(exc_ens_str):
|
|
142
|
+
continue
|
|
143
|
+
model_line, *exc_lines = block.strip().split("\n")
|
|
144
|
+
mobj = model_re.search(model_line)
|
|
145
|
+
model = mobj.group(1)
|
|
146
|
+
exc_lines = [line.strip().split() for line in exc_lines]
|
|
147
|
+
assert all([len(line) == 2 for line in exc_lines])
|
|
148
|
+
exc_ens = np.array([exc_en for _, exc_en in exc_lines], dtype=float)
|
|
149
|
+
results[model] = exc_ens
|
|
150
|
+
return results
|
pysisyphus/color.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
def red(str_):
|
|
2
|
+
return f"\033[91m{str_}\033[0m"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def green(str_):
|
|
6
|
+
return f"\033[92m{str_}\033[0m"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
BOOL_COLORS = {
|
|
10
|
+
True: green,
|
|
11
|
+
False: red,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def bool_color(bool_, str_=None):
|
|
16
|
+
if str_ is None:
|
|
17
|
+
str_ = str(bool_)
|
|
18
|
+
color = BOOL_COLORS[bool_]
|
|
19
|
+
return color(str_)
|
pysisyphus/config.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import configparser
|
|
3
|
+
from io import StringIO
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
8
|
+
import tempfile
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from pysisyphus import logger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
CONFIG_DIR = Path(os.path.abspath(os.path.dirname(__file__)))
|
|
15
|
+
BASIS_LIB_DIR = Path(CONFIG_DIR / "basis_library")
|
|
16
|
+
LIB_DIR = Path(CONFIG_DIR / "geom_library")
|
|
17
|
+
WF_LIB_DIR = Path(CONFIG_DIR / "wf_library")
|
|
18
|
+
T_DEFAULT = 298.15 # Kelvin
|
|
19
|
+
p_DEFAULT = 101325 # Pascal
|
|
20
|
+
OUT_DIR_DEFAULT = str(Path(tempfile.gettempdir()) / "qm_calcs")
|
|
21
|
+
BEND_MIN_DEG = 15
|
|
22
|
+
LB_MIN_DEG = 175
|
|
23
|
+
DIHED_MAX_DEG = 175
|
|
24
|
+
L_MAX = 4
|
|
25
|
+
L_AUX_MAX = 5
|
|
26
|
+
AFIR_RMSD_THRESH = 0.25
|
|
27
|
+
DEFAULTS = {
|
|
28
|
+
# .pysisyphusrc key: command
|
|
29
|
+
"mwfn": "Multiwfn",
|
|
30
|
+
"jmol": "jmol",
|
|
31
|
+
"packmol": "packmol",
|
|
32
|
+
"formchk": "formchk",
|
|
33
|
+
"unfchk": "unfchk",
|
|
34
|
+
"rwfdump": "rwfdump",
|
|
35
|
+
# QC codes
|
|
36
|
+
"orca": "orca",
|
|
37
|
+
"orca5": "orca",
|
|
38
|
+
"gaussian16": "g16",
|
|
39
|
+
"wfoverlap": "wfoverlap.x",
|
|
40
|
+
"openmolcas": "pymolcas",
|
|
41
|
+
"gamess": "rungms",
|
|
42
|
+
"xtb": "xtb",
|
|
43
|
+
"mopac": "mopac",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# First try to read path to .pysisyphusrc from environment variable
|
|
48
|
+
try:
|
|
49
|
+
pysisrc_env = os.getenv("PYSISRC", default=None)
|
|
50
|
+
config_fn = Path(pysisrc_env).resolve()
|
|
51
|
+
print(f"Read pysisyphus configuration from '{config_fn}'")
|
|
52
|
+
# Fallback to $HOME/.pysisyphusrc
|
|
53
|
+
except TypeError:
|
|
54
|
+
config_fn = Path.home() / ".pysisyphusrc"
|
|
55
|
+
|
|
56
|
+
if not config_fn.is_file():
|
|
57
|
+
print(f"Couldn't find configuration file. Expected it at '{config_fn}'.")
|
|
58
|
+
|
|
59
|
+
Config = configparser.ConfigParser()
|
|
60
|
+
read_fns = Config.read(config_fn)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_cmd(section, key="cmd", use_defaults=True):
|
|
64
|
+
cmd = None
|
|
65
|
+
msg = f" and no default was specified for '{section}'."
|
|
66
|
+
|
|
67
|
+
# First we try to load the command from .pysisyphusrc
|
|
68
|
+
try:
|
|
69
|
+
cmd = Config[section][key]
|
|
70
|
+
msg = "."
|
|
71
|
+
# When the command is not available on .pysisyphusrc we check the defaults
|
|
72
|
+
except KeyError:
|
|
73
|
+
if use_defaults:
|
|
74
|
+
default_key = section if key == "cmd" else key
|
|
75
|
+
try:
|
|
76
|
+
default_cmd = DEFAULTS[default_key]
|
|
77
|
+
cmd = shutil.which(default_cmd)
|
|
78
|
+
# 'msg' will only be printed when 'cmd' is None, so the msg is
|
|
79
|
+
# always negative.
|
|
80
|
+
msg = f" and default cmd='{default_cmd}' was not found in $PATH."
|
|
81
|
+
except KeyError:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
if cmd is None:
|
|
85
|
+
logger.warning(
|
|
86
|
+
f"Failed to load '{key}' from [{section}] "
|
|
87
|
+
f"in ~/.pysisyphusrc{msg}"
|
|
88
|
+
)
|
|
89
|
+
cmd = None
|
|
90
|
+
return cmd
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def detect_paths():
|
|
94
|
+
config = configparser.ConfigParser()
|
|
95
|
+
|
|
96
|
+
for k, v in DEFAULTS.items():
|
|
97
|
+
print(f"{k: >16}: ... ", end="")
|
|
98
|
+
if not (path := shutil.which(v)):
|
|
99
|
+
print("not found.")
|
|
100
|
+
else:
|
|
101
|
+
path = Path(path).resolve()
|
|
102
|
+
config[k] = {"cmd": str(path)}
|
|
103
|
+
print(path)
|
|
104
|
+
|
|
105
|
+
fp = StringIO()
|
|
106
|
+
config.write(fp, space_around_delimiters=False)
|
|
107
|
+
fp.seek(0)
|
|
108
|
+
config_text = fp.read()
|
|
109
|
+
return config_text
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def parse_args(args):
|
|
113
|
+
parser = argparse.ArgumentParser()
|
|
114
|
+
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--out", "-o", help="Filename to which the detected cmds are dumped."
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return parser.parse_args(args)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def run_detect_paths():
|
|
123
|
+
args = parse_args(sys.argv[1:])
|
|
124
|
+
out = args.out
|
|
125
|
+
|
|
126
|
+
config_text = detect_paths()
|
|
127
|
+
if out:
|
|
128
|
+
print("Dumped detected cmds to '{out}'")
|
|
129
|
+
with open(out, "w") as handle:
|
|
130
|
+
handle.write(config_text)
|
|
131
|
+
else:
|
|
132
|
+
print("\nExample .pysisyphusrc:\n")
|
|
133
|
+
print(config_text)
|
pysisyphus/constants.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import scipy.constants as spc
|
|
2
|
+
|
|
3
|
+
PI = spc.pi
|
|
4
|
+
|
|
5
|
+
# Speed of light in m/s
|
|
6
|
+
C = spc.c
|
|
7
|
+
# Speed of light in atomic units
|
|
8
|
+
CAU = spc.value("inverse fine-structure constant")
|
|
9
|
+
# ħ = h / 2π in J/s
|
|
10
|
+
HBAR = spc.hbar
|
|
11
|
+
# h
|
|
12
|
+
PLANCK = spc.Planck
|
|
13
|
+
PLANCKAU = 2 * spc.pi # With ħ_au = 1 and ħ_au=h_au/2π -> h_au = 2π
|
|
14
|
+
# Conversion factor for momentum in SI to atomic units
|
|
15
|
+
P_AU = spc.value("atomic unit of momentum")
|
|
16
|
+
|
|
17
|
+
# Bohr radius in m
|
|
18
|
+
BOHR2M = spc.value("Bohr radius")
|
|
19
|
+
# Bohr -> Å conversion factor
|
|
20
|
+
BOHR2ANG = BOHR2M * 1e10
|
|
21
|
+
# Å -> Bohr conversion factor
|
|
22
|
+
ANG2BOHR = 1 / BOHR2ANG
|
|
23
|
+
# Hartree to J
|
|
24
|
+
AU2J = spc.value("Hartree energy")
|
|
25
|
+
# Hartree to kJ / mol
|
|
26
|
+
AU2KJPERMOL = AU2J / 1000 * spc.Avogadro
|
|
27
|
+
# Hartree to kcal mol⁻¹
|
|
28
|
+
AU2KCALPERMOL = AU2KJPERMOL / spc.calorie
|
|
29
|
+
# Hartree to eV
|
|
30
|
+
AU2EV = spc.value("Hartree energy in eV")
|
|
31
|
+
# Joule to eV
|
|
32
|
+
JOULE2EV = AU2EV / AU2J
|
|
33
|
+
# Wavenumber to Hartree
|
|
34
|
+
NU2AU = spc.h * C * 1e2 / AU2J
|
|
35
|
+
# eV/Å -> Hartree/Bohr
|
|
36
|
+
EVANG2AUBOHR = 1 / AU2EV / ANG2BOHR
|
|
37
|
+
# fs -> Bohr * sqrt(amu/Hartree)
|
|
38
|
+
FS2AU = 0.9682885864793366
|
|
39
|
+
# Boltzman constant, (m² kg s⁻² K⁻¹) or just (J / K)
|
|
40
|
+
KB = spc.Boltzmann
|
|
41
|
+
KBAU = KB / AU2J
|
|
42
|
+
# Ideal gas constant
|
|
43
|
+
R = spc.gas_constant
|
|
44
|
+
# Atomic unit of time to second
|
|
45
|
+
AU2SEC = spc.value("atomic unit of time")
|
|
46
|
+
# Atomic mass unit to kg
|
|
47
|
+
AMU2KG = spc.value("atomic mass constant")
|
|
48
|
+
M_E = spc.electron_mass
|
|
49
|
+
AMU2AU = AMU2KG / M_E
|
|
50
|
+
# Avogadro constant
|
|
51
|
+
NA = spc.Avogadro
|
|
52
|
+
|
|
53
|
+
##############
|
|
54
|
+
# MD related #
|
|
55
|
+
##############
|
|
56
|
+
|
|
57
|
+
# Force/amu to acceleration
|
|
58
|
+
# Hartree/(Bohr*amu) -> Bohr / fs²
|
|
59
|
+
FORCE2ACC = AU2J / (AMU2KG * BOHR2M**2 * 1e30)
|
|
60
|
+
# Velocity*amu -> Energy
|
|
61
|
+
# Bohr²/fs²*amu -> Hartree
|
|
62
|
+
# VELO2E = AMU2KG * BOHR2M**2 / (1e-30 * AU2J)
|
|
63
|
+
VELO2E = 1 / FORCE2ACC
|
|
64
|
+
# Velocity from Bohr/fs to Bohr/t_atomic_unit
|
|
65
|
+
BOHRPERFS2AU = AU2SEC * 1e15
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# [1] https://aip.scitation.org/doi/pdf/10.1063/1.1495401
|
|
2
|
+
# [2] http://dx.doi.org/10.1063/1.4962019
|
|
3
|
+
# Zhang, 2016
|
|
4
|
+
# FreeEnd Adaptive NEB
|
|
5
|
+
|
|
6
|
+
# See /scratch/projekte/biaryl/me_cn/cycloadd22/guess01/neb2
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from pysisyphus.cos.NEB import NEB
|
|
11
|
+
from pysisyphus.interpolate import interpolate
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AdaptiveNEB(NEB):
|
|
15
|
+
|
|
16
|
+
def __init__(self, images, adapt=True, adapt_fact=.25, adapt_between=1,
|
|
17
|
+
scale_fact=False, keep_hei=True, free_ends=True,
|
|
18
|
+
**kwargs):
|
|
19
|
+
"""(Free-End) Adaptive Nudged Elastic Band.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
images : list of Geometry objects
|
|
24
|
+
Images of the band.
|
|
25
|
+
adapt : bool, default True
|
|
26
|
+
Whether to adapt the image number or not. This switch is included
|
|
27
|
+
to support the FreeEndNEB class, that is just a thin wrapper around
|
|
28
|
+
this class.
|
|
29
|
+
adapt_fact : positive float
|
|
30
|
+
Factor that is used to decide wether to adapt. The inital
|
|
31
|
+
threshold is calculated by multiplying the RMS force of the
|
|
32
|
+
band with this factor. When the RMS of the force falls
|
|
33
|
+
below this threshold adaption takes place.
|
|
34
|
+
adapat_between : positive integer
|
|
35
|
+
Number of images to interpolate between the highest energy
|
|
36
|
+
image and its neighbours. The number of starting images
|
|
37
|
+
must be higher or equal then 2*adapt_between+3, as we
|
|
38
|
+
reuse/transfer the calculators from the starting images onto
|
|
39
|
+
the new ones.
|
|
40
|
+
scale_fact : bool, default False
|
|
41
|
+
Whether to increase adapt_fact in deeper levels. This may lead
|
|
42
|
+
to earlier adapation.
|
|
43
|
+
keep_hei : bool, optional
|
|
44
|
+
Whether to keep the highest energy image (usually a very good
|
|
45
|
+
idea) or to interpolate only between the neighbouring images.
|
|
46
|
+
free_ends : bool, default True
|
|
47
|
+
Whether to use modified forces on the end images.
|
|
48
|
+
"""
|
|
49
|
+
super().__init__(images, **kwargs)
|
|
50
|
+
|
|
51
|
+
self.adapt = adapt
|
|
52
|
+
self.adapt_fact = adapt_fact
|
|
53
|
+
self.adapt_between = adapt_between
|
|
54
|
+
self.scale_fact = scale_fact
|
|
55
|
+
self.keep_hei = keep_hei
|
|
56
|
+
self.free_ends = free_ends
|
|
57
|
+
|
|
58
|
+
self.adapt_thresh = None
|
|
59
|
+
self.level = 1
|
|
60
|
+
self.coords_backup = list()
|
|
61
|
+
|
|
62
|
+
@NEB.forces.getter
|
|
63
|
+
def forces(self):
|
|
64
|
+
"""See Eq. (7) in [2]."""
|
|
65
|
+
|
|
66
|
+
forces = super().forces
|
|
67
|
+
forces_size = self.images[-1].forces.size
|
|
68
|
+
|
|
69
|
+
if self.free_ends and (not self.fix_first):
|
|
70
|
+
mod_forces = self.get_perpendicular_forces(0)
|
|
71
|
+
forces[:forces_size] = mod_forces
|
|
72
|
+
|
|
73
|
+
if self.free_ends and (not self.fix_last):
|
|
74
|
+
mod_forces = self.get_perpendicular_forces(self.last_index)
|
|
75
|
+
forces[-forces_size:] = mod_forces
|
|
76
|
+
|
|
77
|
+
self._forces = forces
|
|
78
|
+
return self._forces
|
|
79
|
+
|
|
80
|
+
def update_adapt_thresh(self, forces):
|
|
81
|
+
"""Update the adaption threshold.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
forces : np.array
|
|
86
|
+
Forces of the previous optimization cycle.
|
|
87
|
+
"""
|
|
88
|
+
old_thresh = self.adapt_thresh
|
|
89
|
+
|
|
90
|
+
# Dividing by (1 / level)**1/2 scales the adapt_fact as
|
|
91
|
+
# level 1: 1. (No scaling)
|
|
92
|
+
# level 2: 1.414
|
|
93
|
+
# level 3: 1.732
|
|
94
|
+
# level 4: 2.
|
|
95
|
+
# level 5: 2.236
|
|
96
|
+
# ...
|
|
97
|
+
# This ensures that the adapt_fact increases as we recurse
|
|
98
|
+
# deeper.
|
|
99
|
+
if self.scale_fact:
|
|
100
|
+
self.adapt_thresh = (self.rms(forces) * self.adapt_fact
|
|
101
|
+
/ np.sqrt(1 / self.level)
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
self.adapt_thresh = self.rms(forces) * self.adapt_fact
|
|
105
|
+
#arr / np.sqrt(1/np.arange(1, 6))
|
|
106
|
+
self.log(f"Updating adapt_thres. Old thresh was {old_thresh:}. "
|
|
107
|
+
f"New threshold is {self.adapt_thresh:.03f}")
|
|
108
|
+
|
|
109
|
+
def adapt_this_cycle(self, forces):
|
|
110
|
+
"""Decide wether to adapt.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
forces : np.array
|
|
115
|
+
Forces of the previous optimization cycle.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
adapt : bool
|
|
120
|
+
Flag that indicates if adaption should take place in this cycle.
|
|
121
|
+
"""
|
|
122
|
+
cur_rms = self.rms(forces)
|
|
123
|
+
adapt = cur_rms <= self.adapt_thresh
|
|
124
|
+
self.log(f"Current RMS of forces is {cur_rms:03f}. Current thresh "
|
|
125
|
+
f"{self.adapt_thresh:03f}. Adapt = {adapt}")
|
|
126
|
+
return adapt
|
|
127
|
+
|
|
128
|
+
def prepare_opt_cycle(self, *args, **kwargs):
|
|
129
|
+
"""Check for adaption and adapt if needed.
|
|
130
|
+
|
|
131
|
+
See ChainOfStates.prepare_opt_cycle for a complete docstring.
|
|
132
|
+
"""
|
|
133
|
+
base_reset = super().prepare_opt_cycle(*args, **kwargs)
|
|
134
|
+
if not self.adapt:
|
|
135
|
+
return base_reset
|
|
136
|
+
|
|
137
|
+
# Transferring Calculators including WFOWrapper objects
|
|
138
|
+
# in excited state calculations may be problematic.
|
|
139
|
+
# A problem would be the interpolation between two images with
|
|
140
|
+
# different roots. What root should be taken for the interpolated
|
|
141
|
+
# image? Additionally we probably would have to shift around the
|
|
142
|
+
# iterations stored in the WFOWrapper.
|
|
143
|
+
img0 = self.images[0]
|
|
144
|
+
if hasattr(img0, "track") and (img0.track == True):
|
|
145
|
+
raise Exception(
|
|
146
|
+
"track = True and interpolating new images "
|
|
147
|
+
"may give problems with excited state tracking, so this "
|
|
148
|
+
"is disabled for now."
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Initialize adapt_thresh
|
|
152
|
+
if not self.adapt_thresh:
|
|
153
|
+
self.update_adapt_thresh(self.forces_list[-1])
|
|
154
|
+
|
|
155
|
+
if not self.adapt_this_cycle(self.forces_list[-1]):
|
|
156
|
+
return base_reset
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# Adapation from here on
|
|
160
|
+
#
|
|
161
|
+
# Backup coords if we have to step back
|
|
162
|
+
self.coords_backup.append(self.coords)
|
|
163
|
+
# Determine highest energy index and image (HEI)
|
|
164
|
+
hei_index = self.get_hei_index(self.all_energies[-1])
|
|
165
|
+
self.log(f"Index of highest energy image is {hei_index}")
|
|
166
|
+
if (hei_index == 0) or (hei_index == len(self.images)-1):
|
|
167
|
+
self.log("Cant adapt, HEI is first or last!")
|
|
168
|
+
return base_reset
|
|
169
|
+
else:
|
|
170
|
+
self.fix_first = False
|
|
171
|
+
self.fix_last = False
|
|
172
|
+
self.log("First and last image are now free to move.")
|
|
173
|
+
prev_index = hei_index - 1
|
|
174
|
+
next_index = hei_index + 1
|
|
175
|
+
prev_image = self.images[prev_index]
|
|
176
|
+
hei_image = self.images[hei_index]
|
|
177
|
+
next_image = self.images[next_index]
|
|
178
|
+
|
|
179
|
+
# Two interpolations
|
|
180
|
+
# prev. neighbour - HEI
|
|
181
|
+
# HEI - next neighbour
|
|
182
|
+
# Usually the better idea
|
|
183
|
+
kwargs = {
|
|
184
|
+
"kind": "lst",
|
|
185
|
+
"only_between": True,
|
|
186
|
+
"interpol_kwargs": {"silent": True},
|
|
187
|
+
}
|
|
188
|
+
if self.keep_hei:
|
|
189
|
+
# Interpolation of new images between previous neighbour
|
|
190
|
+
# and the HEI.
|
|
191
|
+
kwargs["between"] = self.adapt_between
|
|
192
|
+
new_images_1 = interpolate(prev_image, hei_image, **kwargs)
|
|
193
|
+
new_images_2 = interpolate(hei_image, next_image, **kwargs)
|
|
194
|
+
# Between next neighbour and the HEI.
|
|
195
|
+
all_new_images = ([prev_image] + new_images_1
|
|
196
|
+
+ [hei_image]
|
|
197
|
+
+ new_images_2 + [next_image])
|
|
198
|
+
# One interpolation
|
|
199
|
+
# prev. neighbour - next neighbour
|
|
200
|
+
else:
|
|
201
|
+
kwargs["between"] = 2*self.adapt_between+1
|
|
202
|
+
new_images = interpolate(prev_image, next_image, **kwargs)
|
|
203
|
+
all_new_images = [prev_image] + new_images + [next_image]
|
|
204
|
+
|
|
205
|
+
assert len(all_new_images) <= len(self.images), \
|
|
206
|
+
f"The number of new images ({len(all_new_images)}) is smaller than " \
|
|
207
|
+
f"the number of current images ({len(self.images)}). Increase the number " \
|
|
208
|
+
"of starting images or decrease 'adapt_between'."
|
|
209
|
+
self.level += 1
|
|
210
|
+
|
|
211
|
+
print(f"Adapted images! New number of images is {len(all_new_images)}. "
|
|
212
|
+
f"Current level is {self.level}.")
|
|
213
|
+
|
|
214
|
+
# Backup old calculators
|
|
215
|
+
calcs = [img.calculator for img in self.images]
|
|
216
|
+
# Get numbered indices of the current calcs, so we can continue with
|
|
217
|
+
# higher numbers for the new images.
|
|
218
|
+
calc_numbers = [calc.calc_number for calc in calcs]
|
|
219
|
+
new_calc_number_start = max(calc_numbers) + 1
|
|
220
|
+
# Transfer calculators to the new images
|
|
221
|
+
for i, (new_image, calc) in enumerate(zip(all_new_images, calcs)):
|
|
222
|
+
calc.calc_number = new_calc_number_start + i
|
|
223
|
+
new_image.set_calculator(calc)
|
|
224
|
+
self.images = all_new_images
|
|
225
|
+
self.set_zero_forces_for_fixed_images()
|
|
226
|
+
|
|
227
|
+
# Reset adapt_thresh so it will be set again in the beginning
|
|
228
|
+
# of the next iteration.
|
|
229
|
+
self.adapt_thresh = None
|
|
230
|
+
return True
|