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,59 @@
|
|
|
1
|
+
# [1] Transition-State Optimization Methods using Internal Coordinates
|
|
2
|
+
# https://macsphere.mcmaster.ca/handle/11375/15450?mode=full
|
|
3
|
+
# Rabi, 2014, Phd Thesis
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from pysisyphus.intcoords.Primitive import Primitive
|
|
8
|
+
from pysisyphus.intcoords.derivatives import (
|
|
9
|
+
q_rd1,
|
|
10
|
+
dq_rd1,
|
|
11
|
+
d2q_rd1,
|
|
12
|
+
q_rd2,
|
|
13
|
+
dq_rd2,
|
|
14
|
+
d2q_rd2,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RobustTorsion1(Primitive):
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
21
|
+
return 1.0
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def _calculate(coords3d, indices, gradient=False):
|
|
25
|
+
args = coords3d[indices].flatten()
|
|
26
|
+
val = q_rd1(*args)
|
|
27
|
+
|
|
28
|
+
if gradient:
|
|
29
|
+
row = np.zeros_like(coords3d)
|
|
30
|
+
grad = dq_rd1(*args).reshape(-1, 3)
|
|
31
|
+
row[indices] = grad
|
|
32
|
+
return val, row.flatten()
|
|
33
|
+
return val
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _jacobian(coords3d, indices):
|
|
37
|
+
return d2q_rd1(*coords3d[indices].flatten())
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RobustTorsion2(Primitive):
|
|
41
|
+
@staticmethod
|
|
42
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
43
|
+
return 1.0
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def _calculate(coords3d, indices, gradient=False):
|
|
47
|
+
args = coords3d[indices].flatten()
|
|
48
|
+
val = q_rd2(*args)
|
|
49
|
+
|
|
50
|
+
if gradient:
|
|
51
|
+
row = np.zeros_like(coords3d)
|
|
52
|
+
grad = dq_rd2(*args).reshape(-1, 3)
|
|
53
|
+
row[indices] = grad
|
|
54
|
+
return val, row.flatten()
|
|
55
|
+
return val
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _jacobian(coords3d, indices):
|
|
59
|
+
return d2q_rd2(*coords3d[indices].flatten())
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# [1] http://dx.doi.org/10.1063/1.4952956
|
|
2
|
+
# Lee-Ping Wang, 2016
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.intcoords.Primitive import Primitive
|
|
7
|
+
from pysisyphus.linalg import eigvec_grad, rot_quaternion
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def compare_to_geometric(c3d, ref_c3d, dR, dF, dqdx, dvdx, atol=1e-14):
|
|
11
|
+
from geometric.rotate import get_R_der, get_F_der, get_q_der, get_expmap_der
|
|
12
|
+
|
|
13
|
+
dR_ref = get_R_der(c3d, ref_c3d)
|
|
14
|
+
np.testing.assert_allclose(dR, dR_ref)
|
|
15
|
+
dF_ref = get_F_der(c3d, ref_c3d)
|
|
16
|
+
np.testing.assert_allclose(dF.reshape(-1, 3, 4, 4), dF_ref)
|
|
17
|
+
dq_ref = get_q_der(c3d, ref_c3d)
|
|
18
|
+
np.testing.assert_allclose(dqdx.T.flatten(), dq_ref.flatten(), atol=atol)
|
|
19
|
+
dvdx_ref = get_expmap_der(c3d, ref_c3d)
|
|
20
|
+
np.testing.assert_allclose(dvdx.T.flatten(), dvdx_ref.flatten(), atol=atol)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Rotation(Primitive):
|
|
24
|
+
"""See (II. Theory) in [1], Eq. (3) - (14)"""
|
|
25
|
+
|
|
26
|
+
index = None
|
|
27
|
+
|
|
28
|
+
def __init__(self, indices, *args, ref_coords3d, **kwargs):
|
|
29
|
+
kwargs["cache"] = False
|
|
30
|
+
kwargs["calc_kwargs"] = ("index", "ref_coords3d")
|
|
31
|
+
super().__init__(indices, *args, **kwargs)
|
|
32
|
+
|
|
33
|
+
self.ref_coords3d = ref_coords3d.reshape(-1, 3).copy()
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
37
|
+
return 1
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def _calculate(coords3d, indices, gradient=False, index=0, ref_coords3d=None):
|
|
41
|
+
w, v_, c3d, ref_c3d = rot_quaternion(coords3d[indices], ref_coords3d[indices])
|
|
42
|
+
|
|
43
|
+
quat = v_[:, -1]
|
|
44
|
+
# Eigenvector sign is ambigous. Force first item to be positive,
|
|
45
|
+
# similar to geomeTRIC code.
|
|
46
|
+
if quat[0] < 0.0:
|
|
47
|
+
quat *= -1
|
|
48
|
+
|
|
49
|
+
# Eq. (8) in [1].
|
|
50
|
+
# v = 2 * q_i * (cos⁻¹(q_0) / sqrt(1 - q_0 ** 2)
|
|
51
|
+
#
|
|
52
|
+
# As q_0 approaches 1, the denominator becomes very small, and dividing
|
|
53
|
+
# by this small number results in numerical instability.
|
|
54
|
+
#
|
|
55
|
+
# According to wolframalpha v(q_0) limit approaches 2 for q_0 = 1.
|
|
56
|
+
#
|
|
57
|
+
# input: limit of (2 * arccos(x) / sqrt(1-x**2))
|
|
58
|
+
# output: lim v(x) for x -> 1 becomes 2.
|
|
59
|
+
q0 = quat[0]
|
|
60
|
+
if abs(q0 - 1.0) <= 1e-8:
|
|
61
|
+
prefac = 2 - 2 / 3 * (q0 - 1)
|
|
62
|
+
dvdq0 = -2 / 3
|
|
63
|
+
else:
|
|
64
|
+
arccos_q0 = np.arccos(q0)
|
|
65
|
+
diff = 1 - q0 ** 2
|
|
66
|
+
prefac = 2 * arccos_q0 / np.sqrt(diff)
|
|
67
|
+
dvdq0 = 2 * q0 * arccos_q0 / diff ** 1.5 - 2 / diff
|
|
68
|
+
|
|
69
|
+
# Exponential map
|
|
70
|
+
v = prefac * quat[1:]
|
|
71
|
+
|
|
72
|
+
if gradient:
|
|
73
|
+
# Gradient of correlation matrix
|
|
74
|
+
y1, y2, y3 = ref_c3d.T
|
|
75
|
+
dR = np.zeros((*c3d.shape, 3, 3))
|
|
76
|
+
dR[:, 0, 0, 0] = y1
|
|
77
|
+
dR[:, 0, 0, 1] = y2
|
|
78
|
+
dR[:, 0, 0, 2] = y3
|
|
79
|
+
#
|
|
80
|
+
dR[:, 1, 1, 0] = y1
|
|
81
|
+
dR[:, 1, 1, 1] = y2
|
|
82
|
+
dR[:, 1, 1, 2] = y3
|
|
83
|
+
#
|
|
84
|
+
dR[:, 2, 2, 0] = y1
|
|
85
|
+
dR[:, 2, 2, 1] = y2
|
|
86
|
+
dR[:, 2, 2, 2] = y3
|
|
87
|
+
dR11, dR12, dR13, dR21, dR22, dR23, dR31, dR32, dR33 = dR.reshape(-1, 9).T
|
|
88
|
+
|
|
89
|
+
# Gradient of F matrix. Construct full matrix, as we have to do a dot
|
|
90
|
+
# product later on.
|
|
91
|
+
dF = np.zeros((ref_c3d.size, 4, 4))
|
|
92
|
+
dF[:, 0, 0] = dR11 + dR22 + dR33
|
|
93
|
+
dF[:, 0, 1] = dR23 - dR32
|
|
94
|
+
dF[:, 0, 2] = dR31 - dR13
|
|
95
|
+
dF[:, 0, 3] = dR12 - dR21
|
|
96
|
+
#
|
|
97
|
+
dF[:, 1, 0] = dF[:, 0, 1]
|
|
98
|
+
dF[:, 1, 1] = dR11 - dR22 - dR33
|
|
99
|
+
dF[:, 1, 2] = dR12 + dR21
|
|
100
|
+
dF[:, 1, 3] = dR13 + dR31
|
|
101
|
+
#
|
|
102
|
+
dF[:, 2, 0] = dF[:, 0, 2]
|
|
103
|
+
dF[:, 2, 1] = dF[:, 1, 2]
|
|
104
|
+
dF[:, 2, 2] = -dR11 + dR22 - dR33
|
|
105
|
+
dF[:, 2, 3] = dR23 + dR32
|
|
106
|
+
#
|
|
107
|
+
dF[:, 3, 0] = dF[:, 0, 3]
|
|
108
|
+
dF[:, 3, 1] = dF[:, 1, 3]
|
|
109
|
+
dF[:, 3, 2] = dF[:, 2, 3]
|
|
110
|
+
dF[:, 3, 3] = -dR11 - dR22 + dR33
|
|
111
|
+
|
|
112
|
+
# Quaternion gradient
|
|
113
|
+
dqdx = eigvec_grad(w, v_, ind=-1, mat_grad=dF)
|
|
114
|
+
|
|
115
|
+
dvdq = np.zeros((3, 4))
|
|
116
|
+
dvdq[:, 0] = dvdq0 * quat[1:]
|
|
117
|
+
dvdq[:, 1:] = np.diag((prefac, prefac, prefac))
|
|
118
|
+
|
|
119
|
+
# Gradient of exponential map from chain rule.
|
|
120
|
+
# See bottom-left on 214108-3 in [1], after Eq. (11).
|
|
121
|
+
dvdx = np.einsum("ji,ik->jk", dvdq, dqdx)
|
|
122
|
+
|
|
123
|
+
# compare_to_geometric(c3d, ref_c3d, dR, dF, dqdx, dvdx)
|
|
124
|
+
row = np.zeros_like(coords3d)
|
|
125
|
+
if index is None:
|
|
126
|
+
return v, dvdx.reshape(3, -1)
|
|
127
|
+
row[indices] = dvdx[index].reshape(-1, 3)
|
|
128
|
+
return v[index], row.flatten()
|
|
129
|
+
return v[index]
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def _jacobian(coords3d, indices, index=0, ref_coords3d=None):
|
|
133
|
+
"""Not implemented!"""
|
|
134
|
+
size = len(indices) * 3
|
|
135
|
+
return np.zeros(size * size)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class RotationA(Rotation):
|
|
139
|
+
index = 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class RotationB(Rotation):
|
|
143
|
+
index = 1
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class RotationC(Rotation):
|
|
147
|
+
index = 2
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.intcoords.Primitive import Primitive
|
|
4
|
+
from pysisyphus.intcoords.derivatives import d2q_b
|
|
5
|
+
from pysisyphus.linalg import norm3
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Stretch(Primitive):
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
12
|
+
return Stretch.rho(atoms, coords3d, indices)
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def _calculate(coords3d, indices, gradient=False):
|
|
16
|
+
n, m = indices
|
|
17
|
+
bond = coords3d[m] - coords3d[n]
|
|
18
|
+
bond_length = norm3(bond)
|
|
19
|
+
if gradient:
|
|
20
|
+
bond_normed = bond / bond_length
|
|
21
|
+
row = np.zeros_like(coords3d)
|
|
22
|
+
# 1 / -1 correspond to the sign factor [1] Eq. 18
|
|
23
|
+
row[m,:] = bond_normed
|
|
24
|
+
row[n,:] = -bond_normed
|
|
25
|
+
row = row.flatten()
|
|
26
|
+
return bond_length, row
|
|
27
|
+
return bond_length
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def _jacobian(coords3d, indices):
|
|
31
|
+
return d2q_b(*coords3d[indices].flatten())
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from math import sin
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pysisyphus.intcoords.Primitive import Primitive
|
|
6
|
+
from pysisyphus.intcoords import Bend
|
|
7
|
+
from pysisyphus.intcoords.derivatives import d2q_d2
|
|
8
|
+
from pysisyphus.linalg import cross3, norm3
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Torsion(Primitive):
|
|
12
|
+
@staticmethod
|
|
13
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
14
|
+
m, o, p, n = indices
|
|
15
|
+
rho_mo = Torsion.rho(atoms, coords3d, (m, o))
|
|
16
|
+
rho_op = Torsion.rho(atoms, coords3d, (o, p))
|
|
17
|
+
rho_pn = Torsion.rho(atoms, coords3d, (p, n))
|
|
18
|
+
rad_mop = Bend._calculate(coords3d, (m, o, p))
|
|
19
|
+
rad_opn = Bend._calculate(coords3d, (o, p, n))
|
|
20
|
+
return (
|
|
21
|
+
(rho_mo * rho_op * rho_pn) ** (1 / 3)
|
|
22
|
+
* (f_damping + (1 - f_damping) * sin(rad_mop))
|
|
23
|
+
* (f_damping + (1 - f_damping) * sin(rad_opn))
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def _calculate(coords3d, indices, gradient=False):
|
|
28
|
+
m, o, p, n = indices
|
|
29
|
+
u_dash = coords3d[m] - coords3d[o]
|
|
30
|
+
v_dash = coords3d[n] - coords3d[p]
|
|
31
|
+
w_dash = coords3d[p] - coords3d[o]
|
|
32
|
+
u_norm = norm3(u_dash)
|
|
33
|
+
v_norm = norm3(v_dash)
|
|
34
|
+
w_norm = norm3(w_dash)
|
|
35
|
+
u = u_dash / u_norm
|
|
36
|
+
v = v_dash / v_norm
|
|
37
|
+
w = w_dash / w_norm
|
|
38
|
+
phi_u = np.arccos(u.dot(w))
|
|
39
|
+
phi_v = np.arccos(-w.dot(v))
|
|
40
|
+
uxw = cross3(u, w)
|
|
41
|
+
vxw = cross3(v, w)
|
|
42
|
+
cos_dihed = uxw.dot(vxw) / (np.sin(phi_u) * np.sin(phi_v))
|
|
43
|
+
# Restrict cos_dihed to the allowed interval for arccos [-1, 1]
|
|
44
|
+
cos_dihed = min(1, max(cos_dihed, -1))
|
|
45
|
+
|
|
46
|
+
dihedral_rad = np.arccos(cos_dihed)
|
|
47
|
+
|
|
48
|
+
# Arccos only returns values between 0 and π, but dihedrals can
|
|
49
|
+
# also be negative. This is corrected now.
|
|
50
|
+
#
|
|
51
|
+
# (v ⨯ w) · u will be < 0 when both vectors point in different directions.
|
|
52
|
+
#
|
|
53
|
+
# M ---> N
|
|
54
|
+
# ^ ^
|
|
55
|
+
# \ /
|
|
56
|
+
# u v positive dihedral, M rotates into N clockwise
|
|
57
|
+
# \ / (v ⨯ w) · u > 0, keep positive sign
|
|
58
|
+
# OwP
|
|
59
|
+
# w points downward, into the screen plane.
|
|
60
|
+
# The vector resulting from the cross-product is easily
|
|
61
|
+
# visualized with your right hand.
|
|
62
|
+
#
|
|
63
|
+
# M
|
|
64
|
+
# \
|
|
65
|
+
# | u
|
|
66
|
+
# | \
|
|
67
|
+
# | OwP negative dihedral, M rotates into N counter-clockwise
|
|
68
|
+
# v / (v ⨯ w) · u < 0, invert dihedral sign
|
|
69
|
+
# v
|
|
70
|
+
# /
|
|
71
|
+
# N
|
|
72
|
+
#
|
|
73
|
+
if (dihedral_rad != np.pi) and (vxw.dot(u) < 0):
|
|
74
|
+
dihedral_rad *= -1
|
|
75
|
+
|
|
76
|
+
if gradient:
|
|
77
|
+
row = np.zeros_like(coords3d)
|
|
78
|
+
# | m | n | o | p |
|
|
79
|
+
# ------------------------------------------
|
|
80
|
+
# sign_factor(amo) | 1 | 0 | -1 | 0 | 1st term
|
|
81
|
+
# sign_factor(apn) | 0 | -1 | 0 | 1 | 2nd term
|
|
82
|
+
# sign_factor(aop) | 0 | 0 | 1 | -1 | 3rd term
|
|
83
|
+
# sign_factor(apo) | 0 | 0 | -1 | 1 | 4th term
|
|
84
|
+
sin2_u = np.sin(phi_u) ** 2
|
|
85
|
+
sin2_v = np.sin(phi_v) ** 2
|
|
86
|
+
first_term = uxw / (u_norm * sin2_u)
|
|
87
|
+
second_term = vxw / (v_norm * sin2_v)
|
|
88
|
+
third_term = uxw * np.cos(phi_u) / (w_norm * sin2_u)
|
|
89
|
+
fourth_term = -vxw * np.cos(phi_v) / (w_norm * sin2_v)
|
|
90
|
+
row[m, :] = first_term
|
|
91
|
+
row[n, :] = -second_term
|
|
92
|
+
row[o, :] = -first_term + third_term - fourth_term
|
|
93
|
+
row[p, :] = second_term - third_term + fourth_term
|
|
94
|
+
row = row.flatten()
|
|
95
|
+
return dihedral_rad, row
|
|
96
|
+
return dihedral_rad
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def _jacobian(coords3d, indices):
|
|
100
|
+
sign = np.sign(Torsion._calculate(coords3d, indices))
|
|
101
|
+
return sign * d2q_d2(*coords3d[indices].flatten())
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# See
|
|
2
|
+
# https://en.wikipedia.org/wiki/Dihedral_angle#In_polymer_physics
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.intcoords import Torsion
|
|
7
|
+
from pysisyphus.intcoords.derivatives import q_d2, dq_d2, d2q_d2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Torsion2(Torsion):
|
|
11
|
+
@staticmethod
|
|
12
|
+
def _calculate(coords3d, indices, gradient=False):
|
|
13
|
+
args = coords3d[indices].flatten()
|
|
14
|
+
val = q_d2(*args)
|
|
15
|
+
|
|
16
|
+
if gradient:
|
|
17
|
+
row = np.zeros_like(coords3d)
|
|
18
|
+
grad = dq_d2(*args).reshape(-1, 3)
|
|
19
|
+
row[indices] = grad
|
|
20
|
+
return val, row.flatten()
|
|
21
|
+
return val
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def _jacobian(coords3d, indices):
|
|
25
|
+
return d2q_d2(*coords3d[indices].flatten())
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# [1] http://dx.doi.org/10.1063/1.4952956
|
|
2
|
+
# Lee-Ping Wang, 2016
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.intcoords.Primitive import Primitive
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Translation(Primitive):
|
|
10
|
+
"""See (II. Theory) in [1], Eq. (2)"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, *args, **kwargs):
|
|
13
|
+
kwargs["calc_kwargs"] = ("cart_axis",)
|
|
14
|
+
super().__init__(*args, **kwargs)
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def _weight(atoms, coords3d, indices, f_damping):
|
|
18
|
+
return 1
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def _calculate(coords3d, indices, gradient=False, cart_axis=0):
|
|
22
|
+
value = coords3d[indices, cart_axis].mean()
|
|
23
|
+
if gradient:
|
|
24
|
+
row = np.zeros_like(coords3d)
|
|
25
|
+
row[indices, cart_axis] = 1 / len(indices)
|
|
26
|
+
row = row.flatten()
|
|
27
|
+
return value, row
|
|
28
|
+
return value
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def _jacobian(coords3d, indices, cart_axis):
|
|
32
|
+
size = len(indices) * 3
|
|
33
|
+
return np.zeros(size * size)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TranslationX(Translation):
|
|
37
|
+
cart_axis = 0
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TranslationY(Translation):
|
|
41
|
+
cart_axis = 1
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TranslationZ(Translation):
|
|
45
|
+
cart_axis = 2
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"PrimitiveNotDefinedException",
|
|
3
|
+
"Bend",
|
|
4
|
+
"Bend2",
|
|
5
|
+
"CartesianX",
|
|
6
|
+
"CartesianY",
|
|
7
|
+
"CartesianZ",
|
|
8
|
+
"DummyImproper",
|
|
9
|
+
"DummyTorsion",
|
|
10
|
+
"DistanceFunction",
|
|
11
|
+
"LinearBend",
|
|
12
|
+
"LinearDisplacement",
|
|
13
|
+
"OutOfPlane",
|
|
14
|
+
"Stretch",
|
|
15
|
+
"Torsion",
|
|
16
|
+
"Torsion2",
|
|
17
|
+
"RobustTorsion1",
|
|
18
|
+
"RobustTorsion2",
|
|
19
|
+
"RotationA",
|
|
20
|
+
"RotationB",
|
|
21
|
+
"RotationC",
|
|
22
|
+
"TranslationX",
|
|
23
|
+
"TranslationY",
|
|
24
|
+
"TranslationZ",
|
|
25
|
+
"DLC",
|
|
26
|
+
"HDLC",
|
|
27
|
+
"CartesianCoords",
|
|
28
|
+
"MWCartesianCoords",
|
|
29
|
+
"RedundantCoords",
|
|
30
|
+
"TRIC",
|
|
31
|
+
"TMTRIC",
|
|
32
|
+
"HybridRedundantCoords",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
from pysisyphus.intcoords.exceptions import PrimitiveNotDefinedException
|
|
36
|
+
from pysisyphus.intcoords.Bend import Bend
|
|
37
|
+
from pysisyphus.intcoords.Bend2 import Bend2
|
|
38
|
+
from pysisyphus.intcoords.BondedFragment import BondedFragment
|
|
39
|
+
from pysisyphus.intcoords.Cartesian import CartesianX, CartesianY, CartesianZ
|
|
40
|
+
from pysisyphus.intcoords.DistanceFunction import DistanceFunction
|
|
41
|
+
from pysisyphus.intcoords.DummyImproper import DummyImproper
|
|
42
|
+
from pysisyphus.intcoords.DummyTorsion import DummyTorsion
|
|
43
|
+
from pysisyphus.intcoords.CartesianCoords import CartesianCoords, MWCartesianCoords
|
|
44
|
+
from pysisyphus.intcoords.LinearBend import LinearBend
|
|
45
|
+
from pysisyphus.intcoords.LinearDisplacement import LinearDisplacement
|
|
46
|
+
from pysisyphus.intcoords.OutOfPlane import OutOfPlane
|
|
47
|
+
from pysisyphus.intcoords.Rotation import RotationA, RotationB, RotationC
|
|
48
|
+
from pysisyphus.intcoords.RobustTorsion import RobustTorsion1, RobustTorsion2
|
|
49
|
+
from pysisyphus.intcoords.Stretch import Stretch
|
|
50
|
+
from pysisyphus.intcoords.Torsion import Torsion
|
|
51
|
+
from pysisyphus.intcoords.Torsion2 import Torsion2
|
|
52
|
+
from pysisyphus.intcoords.Translation import TranslationX, TranslationY, TranslationZ
|
|
53
|
+
from pysisyphus.intcoords.RedundantCoords import (
|
|
54
|
+
RedundantCoords,
|
|
55
|
+
TRIC,
|
|
56
|
+
TMTRIC,
|
|
57
|
+
HybridRedundantCoords,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# DLC inherits from RedundantCoords, so we import it after RedundantCoords
|
|
61
|
+
from pysisyphus.intcoords.DLC import DLC, HDLC
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from pysisyphus.Geometry import Geometry
|
|
6
|
+
from pysisyphus.helpers_pure import log
|
|
7
|
+
from pysisyphus.intcoords.setup import get_bond_sets
|
|
8
|
+
from pysisyphus.intcoords import RedundantCoords
|
|
9
|
+
from pysisyphus.intcoords.PrimTypes import PrimTypes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("internal_coords")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def augment_bonds(geom, root=0, proj=False):
|
|
16
|
+
assert geom.coord_type != "cart"
|
|
17
|
+
log(logger, "Trying to augment bonds.")
|
|
18
|
+
|
|
19
|
+
hessian = geom.cart_hessian
|
|
20
|
+
try:
|
|
21
|
+
energy = geom.energy
|
|
22
|
+
except AttributeError:
|
|
23
|
+
energy = None
|
|
24
|
+
|
|
25
|
+
func = find_missing_bonds_by_projection if proj else find_missing_strong_bonds
|
|
26
|
+
|
|
27
|
+
missing_bonds = func(geom, hessian, root=root)
|
|
28
|
+
|
|
29
|
+
if missing_bonds:
|
|
30
|
+
aux_bond_pt = PrimTypes.AUX_BOND
|
|
31
|
+
missing_aux_bonds = [(aux_bond_pt, *mbond) for mbond in missing_bonds]
|
|
32
|
+
print("\t@Missing bonds:", missing_bonds)
|
|
33
|
+
new_geom = Geometry(geom.atoms, geom.cart_coords,
|
|
34
|
+
coord_type=geom.coord_type,
|
|
35
|
+
coord_kwargs={"define_prims": missing_aux_bonds,},
|
|
36
|
+
)
|
|
37
|
+
new_geom.set_calculator(geom.calculator)
|
|
38
|
+
new_geom.energy = energy
|
|
39
|
+
new_geom.cart_hessian = hessian
|
|
40
|
+
return new_geom
|
|
41
|
+
else:
|
|
42
|
+
return geom
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def find_missing_strong_bonds(geom, hessian, bond_factor=1.7, thresh=0.3,
|
|
46
|
+
root=0):
|
|
47
|
+
# Define only bonds
|
|
48
|
+
red = RedundantCoords(geom.atoms, geom.cart_coords,
|
|
49
|
+
bond_factor=bond_factor, bonds_only=True)
|
|
50
|
+
cur_bonds = set([frozenset(b) for b in geom.internal.bond_atom_indices])
|
|
51
|
+
|
|
52
|
+
# Transform cartesian hessian to bond hessian
|
|
53
|
+
bond_hess = red.transform_hessian(hessian)
|
|
54
|
+
# Determine transisiton vector
|
|
55
|
+
eigvals, eigvecs = np.linalg.eigh(bond_hess)
|
|
56
|
+
# There are probably no bonds missing if there are no negative eigenvalues
|
|
57
|
+
if sum(eigvals < 0) == 0:
|
|
58
|
+
return list()
|
|
59
|
+
|
|
60
|
+
trans_vec = eigvecs[:, root]
|
|
61
|
+
# Find bonds that strongly contribute to the selected transition vector
|
|
62
|
+
strong = np.abs(trans_vec) > thresh
|
|
63
|
+
strong_bonds = np.array(red.bond_atom_indices)[strong]
|
|
64
|
+
strong_bonds = set([frozenset(b) for b in strong_bonds])
|
|
65
|
+
|
|
66
|
+
# Check which strong bonds are missing from the currently defiend bonds
|
|
67
|
+
missing_bonds = strong_bonds - cur_bonds
|
|
68
|
+
missing_bonds = [tuple(_) for _ in missing_bonds]
|
|
69
|
+
return missing_bonds
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def find_missing_bonds_by_projection(geom, hessian, bond_factor=2.0, bond_thresh=0.35,
|
|
73
|
+
concerted_thresh=0.35, root=0):
|
|
74
|
+
|
|
75
|
+
def array2set(arr):
|
|
76
|
+
return set([tuple(_) for _ in arr])
|
|
77
|
+
|
|
78
|
+
bonds_present = array2set(geom.internal.bond_atom_indices)
|
|
79
|
+
eigvals, eigvecs = np.linalg.eigh(hessian)
|
|
80
|
+
|
|
81
|
+
# There are probably no bonds missing if there are no negative eigenvalues
|
|
82
|
+
if sum(eigvals < 0) == 0:
|
|
83
|
+
return list()
|
|
84
|
+
|
|
85
|
+
trans_vec = eigvecs[:, root]
|
|
86
|
+
|
|
87
|
+
c3d = geom.coords3d
|
|
88
|
+
bond_vec_empty = np.zeros_like(c3d)
|
|
89
|
+
unique_bonds = array2set(get_bond_sets(geom.atoms, c3d, bond_factor=bond_factor))
|
|
90
|
+
unique_bonds -= bonds_present
|
|
91
|
+
unique_bonds = np.array(list(unique_bonds))
|
|
92
|
+
|
|
93
|
+
bond_vecs = list()
|
|
94
|
+
concerted_vecs = list()
|
|
95
|
+
for m, k in unique_bonds:
|
|
96
|
+
displ = c3d[k] - c3d[m]
|
|
97
|
+
displ /= np.linalg.norm(displ)
|
|
98
|
+
|
|
99
|
+
# Bond
|
|
100
|
+
bond = bond_vec_empty.copy()
|
|
101
|
+
bond[k] = displ
|
|
102
|
+
bond[m] = -displ
|
|
103
|
+
bond_vecs.append(bond)
|
|
104
|
+
|
|
105
|
+
# Concerted movement
|
|
106
|
+
conc = bond_vec_empty.copy()
|
|
107
|
+
conc[k] = displ
|
|
108
|
+
conc[m] = displ
|
|
109
|
+
concerted_vecs.append(conc)
|
|
110
|
+
|
|
111
|
+
def reshape(arr):
|
|
112
|
+
return np.array(arr).reshape(-1, trans_vec.size)
|
|
113
|
+
bond_vecs = reshape(bond_vecs)
|
|
114
|
+
concerted_vecs = reshape(concerted_vecs)
|
|
115
|
+
|
|
116
|
+
def overlaps(arr):
|
|
117
|
+
return np.abs(arr.dot(trans_vec))
|
|
118
|
+
bond_ovlps = overlaps(bond_vecs)
|
|
119
|
+
concerted_ovlps = overlaps(concerted_vecs)
|
|
120
|
+
|
|
121
|
+
unique_bonds = np.array(unique_bonds)
|
|
122
|
+
missing_bonds = unique_bonds[bond_ovlps > bond_thresh]
|
|
123
|
+
missing_concerted = unique_bonds[concerted_ovlps > concerted_thresh]
|
|
124
|
+
|
|
125
|
+
missing_inds = array2set(missing_bonds) | array2set(missing_concerted)
|
|
126
|
+
return missing_inds
|