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,297 @@
|
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from pysisyphus.config import T_DEFAULT
|
|
7
|
+
from pysisyphus.constants import FORCE2ACC
|
|
8
|
+
from pysisyphus.dynamics.helpers import (
|
|
9
|
+
kinetic_energy_from_velocities,
|
|
10
|
+
temperature_for_kinetic_energy,
|
|
11
|
+
energy_forces_getter_closure,
|
|
12
|
+
kinetic_energy_for_temperature,
|
|
13
|
+
remove_com_velocity,
|
|
14
|
+
)
|
|
15
|
+
from pysisyphus.dynamics.thermostats import csvr_closure, csvr_closure_2, berendsen_closure
|
|
16
|
+
from pysisyphus.dynamics.rattle import rattle_closure
|
|
17
|
+
from pysisyphus.helpers import check_for_end_sign
|
|
18
|
+
from pysisyphus.helpers_pure import log
|
|
19
|
+
from pysisyphus.io.hdf5 import get_h5_group
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("dynamics")
|
|
22
|
+
|
|
23
|
+
MDResult = namedtuple(
|
|
24
|
+
"MDResult",
|
|
25
|
+
"coords t_ps step terminated T E_tot",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
THERMOSTATS = {
|
|
29
|
+
"csvr": csvr_closure,
|
|
30
|
+
"csvr_2": csvr_closure_2,
|
|
31
|
+
"berendsen": berendsen_closure,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_data_model(atoms, dump_steps):
|
|
36
|
+
coord_size = 3 * len(atoms)
|
|
37
|
+
_1d = (dump_steps,)
|
|
38
|
+
_2d = (dump_steps, coord_size)
|
|
39
|
+
|
|
40
|
+
data_model = {
|
|
41
|
+
"cart_coords": _2d,
|
|
42
|
+
"step": _1d,
|
|
43
|
+
"energy_tot": _1d,
|
|
44
|
+
"energy_pot" : _1d,
|
|
45
|
+
"energy_kin": _1d,
|
|
46
|
+
"energy_conserved": _1d,
|
|
47
|
+
"T": _1d,
|
|
48
|
+
"T_avg": _1d,
|
|
49
|
+
"velocity": _2d,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return data_model
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def md(
|
|
56
|
+
geom,
|
|
57
|
+
v0,
|
|
58
|
+
steps,
|
|
59
|
+
dt,
|
|
60
|
+
remove_com_v=True,
|
|
61
|
+
thermostat=None,
|
|
62
|
+
T=T_DEFAULT,
|
|
63
|
+
timecon=100,
|
|
64
|
+
term_funcs=None,
|
|
65
|
+
constraints=None,
|
|
66
|
+
constraint_kwargs=None,
|
|
67
|
+
gaussians=None,
|
|
68
|
+
verbose=True,
|
|
69
|
+
print_stride=50,
|
|
70
|
+
dump_stride=None,
|
|
71
|
+
h5_group_name="run",
|
|
72
|
+
):
|
|
73
|
+
"""Velocity verlet integrator.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
geom : Geometry
|
|
78
|
+
The system for which the dynamics are to be run.
|
|
79
|
+
v0 : np.array, floats
|
|
80
|
+
Initial velocities in Bohr/fs.
|
|
81
|
+
steps : float
|
|
82
|
+
Number of simulation steps.
|
|
83
|
+
dt : float
|
|
84
|
+
Timestep in fs.
|
|
85
|
+
remove_com_v : bool, default=True
|
|
86
|
+
Remove center-of-mass velocity.
|
|
87
|
+
thermostat : str, optional, default None
|
|
88
|
+
Which and whether to use a thermostat.
|
|
89
|
+
T : float, optional, default=None
|
|
90
|
+
Desired temperature in thermostated runs.
|
|
91
|
+
timecon : float
|
|
92
|
+
Timeconsanst of the thermostat in fs.
|
|
93
|
+
term_funcs : dict, optional
|
|
94
|
+
Iterable of functions that are called with the atomic
|
|
95
|
+
coordinates in every MD cycle and result in termination
|
|
96
|
+
constraints : 2d iterable, optional
|
|
97
|
+
2D iterable containing atom indices describing constrained
|
|
98
|
+
bond lengths.
|
|
99
|
+
of the MD integration when they evaluate to true.
|
|
100
|
+
constraint_kwargs : dict, optional
|
|
101
|
+
Keyword arguments for the constraint algorithm.
|
|
102
|
+
gaussians: list, optional, default=None
|
|
103
|
+
List of Gaussians to be used in a metadynamics run.
|
|
104
|
+
verbose : bool, default=True
|
|
105
|
+
Do additional printing when True.
|
|
106
|
+
print_stride : int, default=50
|
|
107
|
+
Report every n-th step.
|
|
108
|
+
dump_stride : int, default=None
|
|
109
|
+
If given, MD data will be dumped to a HDF5 file every n-th step.
|
|
110
|
+
h5_group_name = str, optional
|
|
111
|
+
Name of the HDF5 group, used for dumping.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
assert geom.coord_type == "cart"
|
|
115
|
+
|
|
116
|
+
if term_funcs is None:
|
|
117
|
+
term_funcs = dict()
|
|
118
|
+
|
|
119
|
+
# if dump_stride:
|
|
120
|
+
# dump_steps = steps // dump_stride
|
|
121
|
+
# data_model = get_data_model(geom.atoms, dump_steps)
|
|
122
|
+
# h5_group = get_h5_group("md.h5", h5_group_name, data_model, reset=True)
|
|
123
|
+
# h5_group.attrs["atoms"] = geom.atoms
|
|
124
|
+
# h5_group.attrs["dt"] = dt
|
|
125
|
+
# h5_group.attrs["steps"] = steps
|
|
126
|
+
# h5_group.attrs["masses"] = geom.masses
|
|
127
|
+
# h5_group.attrs["T_target"] = T
|
|
128
|
+
|
|
129
|
+
if verbose:
|
|
130
|
+
t_ps = steps * dt * 1e-3 # Total simulation time
|
|
131
|
+
print(f"Doing {steps} steps of {dt:.4f} fs for a total of {t_ps:.2f} ps.\n")
|
|
132
|
+
|
|
133
|
+
energy_forces_getter = energy_forces_getter_closure(geom)
|
|
134
|
+
|
|
135
|
+
if gaussians is None:
|
|
136
|
+
gaussians = tuple()
|
|
137
|
+
gau_centers = list()
|
|
138
|
+
gau_center_num = np.zeros(len(gaussians), dtype=int)
|
|
139
|
+
for _, gaussian, gau_stride in gaussians:
|
|
140
|
+
num_centers = steps // gau_stride
|
|
141
|
+
gau_centers.append(np.zeros(num_centers))
|
|
142
|
+
|
|
143
|
+
def update_gaussians(step, coords):
|
|
144
|
+
for i, (gau_key, gaussian, gau_stride) in enumerate(gaussians):
|
|
145
|
+
if (step + 1) % gau_stride == 0:
|
|
146
|
+
new_center = gaussian.colvar.value(coords.reshape(-1, 3))
|
|
147
|
+
gau_centers[i][gau_center_num[i]] = new_center
|
|
148
|
+
gau_center_num[i] += 1
|
|
149
|
+
log(
|
|
150
|
+
logger,
|
|
151
|
+
f"Added {gau_center_num[i]: >6d}. '{gau_key}' Gaussian in step {step}.",
|
|
152
|
+
)
|
|
153
|
+
gaussian.dump(step, gaussian.s, gaussian.w, new_center)
|
|
154
|
+
|
|
155
|
+
def gaussian_wrapper(coords):
|
|
156
|
+
E_pot, forces = energy_forces_getter(geom.coords)
|
|
157
|
+
for i, (_, gaussian, _) in enumerate(gaussians):
|
|
158
|
+
center_num = gau_center_num[i]
|
|
159
|
+
gau_pot, gau_grad = gaussian.eval(coords, gau_centers[i][:center_num])
|
|
160
|
+
# print("\tgau_pot", gau_pot)
|
|
161
|
+
gau_forces = -gau_grad.flatten()
|
|
162
|
+
E_pot += gau_pot
|
|
163
|
+
forces += gau_forces
|
|
164
|
+
return E_pot, forces
|
|
165
|
+
|
|
166
|
+
if constraint_kwargs is None:
|
|
167
|
+
constraint_kwargs = dict()
|
|
168
|
+
|
|
169
|
+
# Fixed degrees of freedom
|
|
170
|
+
fixed_dof = 0
|
|
171
|
+
if remove_com_v:
|
|
172
|
+
print("Removing center-of-mass velocity.")
|
|
173
|
+
fixed_dof += 3
|
|
174
|
+
constrained_md = constraints is not None
|
|
175
|
+
# Get RATTLE function from closure for constrained MD
|
|
176
|
+
if constrained_md:
|
|
177
|
+
fixed_dof += len(constraints)
|
|
178
|
+
rattle = rattle_closure(
|
|
179
|
+
geom,
|
|
180
|
+
constraints,
|
|
181
|
+
dt,
|
|
182
|
+
energy_forces_getter=energy_forces_getter,
|
|
183
|
+
**constraint_kwargs,
|
|
184
|
+
)
|
|
185
|
+
print(f"Fixed degrees of freedom: {fixed_dof}")
|
|
186
|
+
dof = len(geom.coords) - fixed_dof
|
|
187
|
+
|
|
188
|
+
if thermostat is not None:
|
|
189
|
+
sigma = kinetic_energy_for_temperature(len(geom.atoms), T, fixed_dof=fixed_dof)
|
|
190
|
+
thermo_func = THERMOSTATS[thermostat](sigma, dof, dt=dt, tau=timecon)
|
|
191
|
+
# In amu
|
|
192
|
+
masses = geom.masses
|
|
193
|
+
masses_rep = geom.masses_rep
|
|
194
|
+
|
|
195
|
+
x = geom.cart_coords
|
|
196
|
+
# v is given in Bohr/fs
|
|
197
|
+
v = v0
|
|
198
|
+
a_prev = np.zeros_like(x)
|
|
199
|
+
xs = list()
|
|
200
|
+
Ts = list()
|
|
201
|
+
E_tots = list()
|
|
202
|
+
|
|
203
|
+
E_pot, forces = energy_forces_getter(geom.coords)
|
|
204
|
+
|
|
205
|
+
t_cur = 0
|
|
206
|
+
terminate = False
|
|
207
|
+
terminate_key = None
|
|
208
|
+
T_avg = 0
|
|
209
|
+
log(logger, f"Running MD with Δt={dt:.2f} fs for {steps} steps.")
|
|
210
|
+
print()
|
|
211
|
+
thermo_corr = 0.0
|
|
212
|
+
for step in range(steps):
|
|
213
|
+
xs.append(x.copy())
|
|
214
|
+
|
|
215
|
+
E_kin = kinetic_energy_from_velocities(masses, v.reshape(-1, 3))
|
|
216
|
+
T = temperature_for_kinetic_energy(len(masses), E_kin, fixed_dof=fixed_dof)
|
|
217
|
+
T_avg += T
|
|
218
|
+
Ts.append(T)
|
|
219
|
+
E_tot = E_pot + E_kin
|
|
220
|
+
E_tots.append(E_tot)
|
|
221
|
+
E_conserved = E_pot + E_kin - thermo_corr
|
|
222
|
+
|
|
223
|
+
status_msg = (
|
|
224
|
+
f"Step {step:06d} {t_cur*1e-3: >6.2f} ps E={E_tot: >8.6f} E_h "
|
|
225
|
+
f"T={T: >8.2f} K <T>={T_avg/(step+1): >8.2f} K"
|
|
226
|
+
)
|
|
227
|
+
if step % print_stride == 0:
|
|
228
|
+
log(logger, status_msg)
|
|
229
|
+
if verbose:
|
|
230
|
+
print(status_msg)
|
|
231
|
+
|
|
232
|
+
# if dump_stride and (step % dump_stride == 0):
|
|
233
|
+
# ind = step // dump_stride
|
|
234
|
+
# h5_group["step"][ind] = step
|
|
235
|
+
# h5_group["cart_coords"][ind] = x
|
|
236
|
+
# h5_group["velocity"][ind] = v
|
|
237
|
+
# h5_group["energy_tot"][ind] = E_tot
|
|
238
|
+
# h5_group["energy_pot"][ind] = E_pot
|
|
239
|
+
# h5_group["energy_kin"][ind] = E_kin
|
|
240
|
+
# h5_group["energy_conserved"][ind] = E_conserved
|
|
241
|
+
# h5_group["T"][ind] = T
|
|
242
|
+
# h5_group["T_avg"][ind] = T_avg / (step + 1)
|
|
243
|
+
|
|
244
|
+
if thermostat:
|
|
245
|
+
alpha = thermo_func(E_kin)
|
|
246
|
+
thermo_corr += (alpha**2 - 1) * E_kin
|
|
247
|
+
v *= alpha
|
|
248
|
+
|
|
249
|
+
update_gaussians(step, x)
|
|
250
|
+
|
|
251
|
+
# RATTLE algorithm
|
|
252
|
+
if constrained_md:
|
|
253
|
+
x, v, E_pot, forces = rattle(x, v, forces)
|
|
254
|
+
# Simple Velocity-Verlet integration
|
|
255
|
+
else:
|
|
256
|
+
# E_pot, forces = energy_forces_getter(geom.coords)
|
|
257
|
+
E_pot, forces = gaussian_wrapper(geom.coords)
|
|
258
|
+
# Acceleration, convert from Hartree / (Bohr * amu) to Bohr/fs²
|
|
259
|
+
a = forces / masses_rep * FORCE2ACC
|
|
260
|
+
v += 0.5 * (a + a_prev) * dt
|
|
261
|
+
|
|
262
|
+
if remove_com_v:
|
|
263
|
+
v = remove_com_velocity(v.reshape(-1, 3), masses).flatten()
|
|
264
|
+
# v*dt = Bohr/fs * fs -> Bohr
|
|
265
|
+
# a*dt**2 = Bohr/fs² * fs² -> Bohr
|
|
266
|
+
x += v * dt + 0.5 * a * dt ** 2
|
|
267
|
+
a_prev = a
|
|
268
|
+
|
|
269
|
+
# Update coordinates
|
|
270
|
+
geom.coords = x
|
|
271
|
+
|
|
272
|
+
for name, func in term_funcs.items():
|
|
273
|
+
if func(x.reshape(-1, 3)):
|
|
274
|
+
terminate = True
|
|
275
|
+
terminate_key = name
|
|
276
|
+
break
|
|
277
|
+
if terminate:
|
|
278
|
+
log(logger, f"Termination function '{name}' evaluted to True. Breaking.")
|
|
279
|
+
break
|
|
280
|
+
|
|
281
|
+
if check_for_end_sign():
|
|
282
|
+
break
|
|
283
|
+
|
|
284
|
+
# Advance time
|
|
285
|
+
t_cur += dt
|
|
286
|
+
log(logger, "")
|
|
287
|
+
|
|
288
|
+
md_result = MDResult(
|
|
289
|
+
coords=np.array(xs),
|
|
290
|
+
t_ps=t_cur * 1e-3,
|
|
291
|
+
step=step,
|
|
292
|
+
terminated=terminate_key,
|
|
293
|
+
T=np.array(Ts),
|
|
294
|
+
E_tot=np.array(E_tots),
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
return md_result
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pysisyphus.xyzloader import make_trj_str
|
|
4
|
+
from pysisyphus.Geometry import get_trans_rot_projector
|
|
5
|
+
from pysisyphus.constants import BOHR2ANG, KBAU, VELO2E
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def dump_coords(atoms, coords, trj_fn):
|
|
9
|
+
coords = np.array(coords)
|
|
10
|
+
coords = coords.reshape(-1, len(atoms), 3) * BOHR2ANG
|
|
11
|
+
trj_str = make_trj_str(atoms, coords)
|
|
12
|
+
|
|
13
|
+
with open(trj_fn, "w") as handle:
|
|
14
|
+
handle.write(trj_str)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def kinetic_energy_from_velocities(masses, velocities):
|
|
18
|
+
"""Kinetic energy for given velocities and masses.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
masses : 1d array, shape (number of atoms, )
|
|
23
|
+
Atomic masses in amu.
|
|
24
|
+
velocities : 2d array, (number of atoms, 3)
|
|
25
|
+
Atomic velocities in Bohr/fs.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
E_kin : float
|
|
30
|
+
Kinetic energy in Hartree.
|
|
31
|
+
"""
|
|
32
|
+
return np.sum(masses[:,None] / 2 * velocities**2) * VELO2E
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def kinetic_energy_for_temperature(atom_number, T, fixed_dof=0):
|
|
36
|
+
"""Kinetic energy for given temperature and number of atoms.
|
|
37
|
+
|
|
38
|
+
Each atom has three degrees of freedom (1/2 * 3 == 3/2).
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
atom_number : int
|
|
43
|
+
Number of atoms. Each atom has three degrees of freedom.
|
|
44
|
+
T : float
|
|
45
|
+
Temperature in Kelvin.
|
|
46
|
+
fixed_dof : int, optional, default=0
|
|
47
|
+
Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
|
|
48
|
+
velocity is removed.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
E_kin : float
|
|
53
|
+
Kinetic energy in Hartree.
|
|
54
|
+
"""
|
|
55
|
+
return (3*atom_number - fixed_dof) / 2 * T * KBAU
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def temperature_for_kinetic_energy(atom_number, E_kin, fixed_dof=0):
|
|
59
|
+
"""Temperature for given kinetic energy and atom number.
|
|
60
|
+
|
|
61
|
+
Each atom has three degrees of freedom (1/2 * 3 == 3/2).
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
atom_number : int
|
|
66
|
+
Number of atoms. Each atom has three degrees of freedom.
|
|
67
|
+
E_kin : float
|
|
68
|
+
Kinetic energy in Hartree.
|
|
69
|
+
fixed_dof : int, optional, default=0
|
|
70
|
+
Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
|
|
71
|
+
velocity is removed.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
Temperature : float
|
|
76
|
+
Temperature in Kelvin.
|
|
77
|
+
"""
|
|
78
|
+
return 2 * E_kin / ((3*atom_number - fixed_dof) * KBAU)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def remove_com_velocity(v, masses, keep_norm=True):
|
|
82
|
+
"""Remove center-of-mass velocity.
|
|
83
|
+
|
|
84
|
+
Returned units vary with the given input units.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
89
|
+
Velocities.
|
|
90
|
+
masses : np.array, 1d, shape (number of atoms, )
|
|
91
|
+
Atomic masses.
|
|
92
|
+
keep_norm : bool, default=True
|
|
93
|
+
Whether to rescale v to its original norm, after removal of v_com.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
v : np.array
|
|
98
|
+
Velocities without center-of-mass velocity.
|
|
99
|
+
"""
|
|
100
|
+
org_norm = np.linalg.norm(v)
|
|
101
|
+
v_com = (v * masses[:,None] / np.sum(masses)).sum(axis=0)
|
|
102
|
+
v -= v_com
|
|
103
|
+
if keep_norm:
|
|
104
|
+
v /= np.linalg.norm(v) / org_norm
|
|
105
|
+
return v
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def scale_velocities_to_temperatue(masses, v, T_desired, fixed_dof=0):
|
|
109
|
+
"""Scale velocities to a given temperature.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
masses : np.array, 1d, shape (number of atoms, )
|
|
114
|
+
Atomic masses in amu.
|
|
115
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
116
|
+
(Unscaled) velocities in Bohr/fs.
|
|
117
|
+
T_desired : float
|
|
118
|
+
Desired temperature in Kelvin.
|
|
119
|
+
fixed_dof : int, optional, default=0
|
|
120
|
+
Number of fixed degrees of freedom, e.g. 3 when the center-of-mass
|
|
121
|
+
velocity is removed.
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
126
|
+
Scaled velocities in Bohr/fs.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
E_ref = kinetic_energy_for_temperature(len(masses), T_desired,
|
|
130
|
+
fixed_dof=fixed_dof) # in Hartree
|
|
131
|
+
E_cur = kinetic_energy_from_velocities(masses, v) # in Hartree
|
|
132
|
+
scale = (E_ref / E_cur)**0.5
|
|
133
|
+
v *= scale
|
|
134
|
+
# E_now = kinetic_energy_from_velocities(masses, v)
|
|
135
|
+
# np.testing.assert_allclose(E_now, E_ref)
|
|
136
|
+
return v
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def scale_velocities_to_energy(masses, v, E_desired):
|
|
140
|
+
"""Scale velocities to a given temperature.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
masses : np.array, 1d, shape (number of atoms, )
|
|
145
|
+
Atomic masses in amu.
|
|
146
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
147
|
+
(Unscaled) velocities in Bohr/fs.
|
|
148
|
+
E_desired : float
|
|
149
|
+
Desired kinetic energy in Hartree.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
154
|
+
Scaled velocities in Bohr/fs.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
E_cur = kinetic_energy_from_velocities(masses, v) # in Hartree
|
|
158
|
+
scale = (E_desired / E_cur)**0.5
|
|
159
|
+
v *= scale
|
|
160
|
+
return v
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def unscaled_velocity_distribution(masses, T, seed=None):
|
|
164
|
+
"""
|
|
165
|
+
ρ ∝ exp(- v² * m / (2 * kT))
|
|
166
|
+
ln(ρ) ∝ - 1/2 * v² * m / kT
|
|
167
|
+
v² ∝ -2 * ln(ρ) * kT / m
|
|
168
|
+
v ∝ ±(-2 * ln(ρ) * kT / m)**0.5
|
|
169
|
+
v ∝ ±(-2 * k)**0.5 * (ln(ρ) * T / m)**0.5
|
|
170
|
+
|
|
171
|
+
The first term of the RHS is constant. As we later scale the
|
|
172
|
+
velocities we neglect it. Don't use these velocities unscaled!
|
|
173
|
+
|
|
174
|
+
v ∝ ±(ln(ρ) * T / m)**0.5
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
if seed is not None:
|
|
178
|
+
np.random.seed(seed)
|
|
179
|
+
|
|
180
|
+
ps = np.random.standard_normal((len(masses), 3))
|
|
181
|
+
v = ps * np.sqrt(T / masses[:,None])
|
|
182
|
+
return v
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_mb_velocities(masses, cart_coords, T, remove_com_v=True, remove_rot_v=True,
|
|
186
|
+
seed=None):
|
|
187
|
+
"""Initial velocities from Maxwell-Boltzmann distribution.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
masses : np.array, 1d, shape (number of atoms, )
|
|
192
|
+
Atomic masses in amu.
|
|
193
|
+
cart_coords : iterable, 1d, shape (3 * number of atoms, )
|
|
194
|
+
Atomic cartesian coordinates. Needed for removal of rotation.
|
|
195
|
+
T : float
|
|
196
|
+
Temperature in Kelvin.
|
|
197
|
+
remove_com_v : bool, default=True, optional
|
|
198
|
+
Whether to remove center-of-mass velocity.
|
|
199
|
+
remove_rot_v : bool, default=True, optional
|
|
200
|
+
Whether to remove rotational velocity.
|
|
201
|
+
seed : int, default=None, optional
|
|
202
|
+
Seed for the random-number-generator.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
v : np.array, 2d, shape (number of atoms, 3)
|
|
207
|
+
Initial velocities in Bohr/fs.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
masses = np.array(masses)
|
|
211
|
+
|
|
212
|
+
# Initial velocities
|
|
213
|
+
v = unscaled_velocity_distribution(masses, T, seed=seed)
|
|
214
|
+
|
|
215
|
+
if (len(masses) == 1) and remove_com_v:
|
|
216
|
+
raise Exception("Removing COM velocity with only 1 atom is a bad idea!")
|
|
217
|
+
|
|
218
|
+
fixed_dof = 0
|
|
219
|
+
# Remove center-of-mass velocity
|
|
220
|
+
if remove_com_v:
|
|
221
|
+
v = remove_com_velocity(v, masses)
|
|
222
|
+
fixed_dof += 3
|
|
223
|
+
|
|
224
|
+
if remove_rot_v:
|
|
225
|
+
# Right now this also removes the translational components
|
|
226
|
+
P = get_trans_rot_projector(cart_coords, masses, full=True)
|
|
227
|
+
v = P.dot(v.flatten()).reshape(-1, 3)
|
|
228
|
+
fixed_dof = 6
|
|
229
|
+
|
|
230
|
+
# In Bohr/fs
|
|
231
|
+
v = scale_velocities_to_temperatue(masses, v, T, fixed_dof=fixed_dof)
|
|
232
|
+
|
|
233
|
+
return v
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def get_mb_velocities_for_geom(geom, T, remove_com_v=True, remove_rot_v=True,
|
|
237
|
+
seed=None):
|
|
238
|
+
"""Initial velocities from Maxwell-Boltzmann distribution.
|
|
239
|
+
|
|
240
|
+
See 'get_mb_velocities' for explanation.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
return get_mb_velocities(geom.masses, geom.cart_coords, T,
|
|
244
|
+
remove_com_v=remove_com_v,
|
|
245
|
+
remove_rot_v=remove_rot_v,
|
|
246
|
+
seed=seed,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def energy_forces_getter_closure(geom):
|
|
251
|
+
def energy_forces_getter(coords):
|
|
252
|
+
results = geom.get_energy_and_forces_at(coords)
|
|
253
|
+
energy = results["energy"]
|
|
254
|
+
forces = results["forces"]
|
|
255
|
+
return energy, forces
|
|
256
|
+
return energy_forces_getter
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def lincs_closure(geom, constraints, order=4):
|
|
5
|
+
"""
|
|
6
|
+
Drop conn_nums and keep conns_ in a list of list, instead of an array.
|
|
7
|
+
We could do everything with
|
|
8
|
+
for i, conn_constr in enumerate(conns)
|
|
9
|
+
pass
|
|
10
|
+
instead of the pseudo-code way as given in the paper.
|
|
11
|
+
"""
|
|
12
|
+
# Number of constraints
|
|
13
|
+
K = len(constraints)
|
|
14
|
+
# Inverse atom masses
|
|
15
|
+
inv_masses = 1 / geom.masses
|
|
16
|
+
|
|
17
|
+
# List of constraint sets
|
|
18
|
+
constraint_sets = [set(c) for c in constraints]
|
|
19
|
+
constraints = np.array(constraints, dtype=int)
|
|
20
|
+
# Indices of the atoms that make up the bond constraints
|
|
21
|
+
atom_1, atom_2 = constraints.T
|
|
22
|
+
|
|
23
|
+
# Original bond lengths
|
|
24
|
+
lengths = np.linalg.norm(geom.coords3d[atom_1] - geom.coords3d[atom_2], axis=1)
|
|
25
|
+
|
|
26
|
+
# Determine number of constraints that are connected to every constraint
|
|
27
|
+
conn_nums = np.zeros(K, dtype=int)
|
|
28
|
+
conns_ = [list() for _ in range(K)]
|
|
29
|
+
for i, con_1 in enumerate(constraint_sets):
|
|
30
|
+
for j, con_2 in enumerate(constraint_sets):
|
|
31
|
+
if i == j:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
if con_1 & con_2:
|
|
35
|
+
conn_nums[i] += 1
|
|
36
|
+
conns_[i].append(j)
|
|
37
|
+
# Maximum number of connected constraints
|
|
38
|
+
c_max = conn_nums.max()
|
|
39
|
+
S_diag = 1 / np.sqrt(inv_masses[atom_1] + inv_masses[atom_2])
|
|
40
|
+
|
|
41
|
+
# Array containing the indices of the connected constraints for every constraint
|
|
42
|
+
conns = np.zeros((K, c_max), dtype=int)
|
|
43
|
+
for i, c in enumerate(conns_):
|
|
44
|
+
conns[i, :len(c)] = c
|
|
45
|
+
|
|
46
|
+
coefs = np.zeros((K, c_max))
|
|
47
|
+
signs = {
|
|
48
|
+
True: -1,
|
|
49
|
+
False: 1,
|
|
50
|
+
}
|
|
51
|
+
for i, con_1 in enumerate(constraint_sets):
|
|
52
|
+
for j in range(c_max):
|
|
53
|
+
conns_ij = conns[i, j]
|
|
54
|
+
sign = signs[(atom_1[i] == atom_1[conns_ij]) or (atom_2[i] == atom_2[conns_ij])]
|
|
55
|
+
# Connected atom
|
|
56
|
+
c = tuple(con_1 & constraint_sets[conns_ij])
|
|
57
|
+
assert len(c) == 1
|
|
58
|
+
c = int(c[0])
|
|
59
|
+
coefs[i, j] = sign * inv_masses[c] * S_diag[i] * S_diag[conns_ij]
|
|
60
|
+
|
|
61
|
+
def solve(rhs, sol, new_coords3d, A, B):
|
|
62
|
+
w = 1
|
|
63
|
+
for _ in range(order):
|
|
64
|
+
for i, _ in enumerate(constraints):
|
|
65
|
+
rhs[w, i] = 0.
|
|
66
|
+
for j in range(conn_nums[i]):
|
|
67
|
+
# rhs[w, i] += A[i, j] * rhs[2-w, conns_[i][j]]
|
|
68
|
+
rhs[w, i] += A[i, j] * rhs[2-w, conns[i, j]]
|
|
69
|
+
sol[i] += rhs[w, i]
|
|
70
|
+
w = 2 - w
|
|
71
|
+
|
|
72
|
+
for i, (a1, a2) in enumerate(constraints):
|
|
73
|
+
new_coords3d[a1] -= inv_masses[a1] * S_diag[i] * sol[i] * B[i].sum()
|
|
74
|
+
new_coords3d[a2] += inv_masses[a2] * S_diag[i] * sol[i] * B[i].sum()
|
|
75
|
+
|
|
76
|
+
def lincs(prev_coords3d, new_coords3d):
|
|
77
|
+
# Calculate constraint directions
|
|
78
|
+
B = prev_coords3d[atom_1] - prev_coords3d[atom_2]
|
|
79
|
+
B /= np.linalg.norm(B, axis=1)[:, None]
|
|
80
|
+
print("B", B)
|
|
81
|
+
|
|
82
|
+
A = np.zeros((K, c_max))
|
|
83
|
+
rhs = np.zeros((2, K))
|
|
84
|
+
sol = np.zeros(K)
|
|
85
|
+
|
|
86
|
+
for i, (a1, a2) in enumerate(constraints):
|
|
87
|
+
print(i, a1, a2)
|
|
88
|
+
for j, k in enumerate(conns[i]):
|
|
89
|
+
A[i, j] = coefs[i, j] * (B[i] * B[k]).sum()
|
|
90
|
+
|
|
91
|
+
rhs[0, i] = S_diag[i] * ((B[i] * (new_coords3d[a1] - new_coords3d[a2])).sum() - lengths[i])
|
|
92
|
+
sol[i] = rhs[0, i]
|
|
93
|
+
solve(rhs, sol, new_coords3d, A, B)
|
|
94
|
+
|
|
95
|
+
# Correction for rotational lenghthening
|
|
96
|
+
for i, (a1, a2) in enumerate(constraints):
|
|
97
|
+
length_i = lengths[i]
|
|
98
|
+
p = (2 * length_i**2 - (-(new_coords3d[a1] - new_coords3d[a2])**2).sum())**0.5
|
|
99
|
+
rhs[0, i] = S_diag[i] * (length_i - p)
|
|
100
|
+
sol[i] = rhs[0, i]
|
|
101
|
+
|
|
102
|
+
solve(rhs, sol, new_coords3d, A, B)
|
|
103
|
+
# import pdb; pdb.set_trace()
|
|
104
|
+
return new_coords3d
|
|
105
|
+
return lincs
|