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,349 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
import importlib.util
|
|
7
|
+
from importlib import import_module
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
_EXT_CACHE: Dict[str, Optional[Any]] = {
|
|
12
|
+
"nonbonded": None,
|
|
13
|
+
"analytical_hessian": None,
|
|
14
|
+
"bonded": None,
|
|
15
|
+
}
|
|
16
|
+
_EXT_ERROR: Dict[str, Optional[str]] = {
|
|
17
|
+
"nonbonded": None,
|
|
18
|
+
"analytical_hessian": None,
|
|
19
|
+
"bonded": None,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _rebuild_hint() -> str:
|
|
24
|
+
return (
|
|
25
|
+
"mlmm-toolkit JIT-compiles C++ extensions on first use via torch.utils.cpp_extension.\n"
|
|
26
|
+
"This requires a C++ compiler (g++). If compilation fails, run: apt install g++ (or: yum install gcc-c++)\n"
|
|
27
|
+
"To manually rebuild:\n"
|
|
28
|
+
" cd $(python -c \"import hessian_ff; print(hessian_ff.__path__[0])\")/native && make clean && make"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _with_rebuild_hint(msg: str) -> str:
|
|
33
|
+
txt = str(msg).strip()
|
|
34
|
+
if not txt:
|
|
35
|
+
txt = "native extension unavailable"
|
|
36
|
+
return f"{txt}\n{_rebuild_hint()}"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _ensure_max_jobs() -> None:
|
|
40
|
+
"""Set Ninja parallel compile jobs if not provided by user.
|
|
41
|
+
|
|
42
|
+
This reduces first-build wall time for native extensions.
|
|
43
|
+
"""
|
|
44
|
+
if "MAX_JOBS" in os.environ:
|
|
45
|
+
return
|
|
46
|
+
ncpu = os.cpu_count()
|
|
47
|
+
if ncpu is None or ncpu < 1:
|
|
48
|
+
return
|
|
49
|
+
os.environ["MAX_JOBS"] = str(int(ncpu))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def try_load_native_backend(module_name: str = "hessian_ff_native") -> Optional[Any]:
|
|
53
|
+
"""Try importing a native extension backend module.
|
|
54
|
+
|
|
55
|
+
Returns the module object if available, otherwise ``None``.
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
return import_module(module_name)
|
|
59
|
+
except Exception:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def native_backend_status(module_name: str = "hessian_ff_native") -> Dict[str, str]:
|
|
64
|
+
"""Return a short status dict for native backend availability."""
|
|
65
|
+
mod = try_load_native_backend(module_name=module_name)
|
|
66
|
+
if mod is None:
|
|
67
|
+
return {
|
|
68
|
+
"available": "false",
|
|
69
|
+
"module": module_name,
|
|
70
|
+
"backend": "native_required",
|
|
71
|
+
"note": "native extension module is not loaded",
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
"available": "true",
|
|
75
|
+
"module": module_name,
|
|
76
|
+
"backend": "native",
|
|
77
|
+
"note": "native extension is loaded",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _cache_build_dir(build_subdir: str) -> Path:
|
|
82
|
+
"""Return the user-cache fallback build directory.
|
|
83
|
+
|
|
84
|
+
Used when the package-internal directory (site-packages) is read-only.
|
|
85
|
+
Location: $XDG_CACHE_HOME/mlmm-toolkit/hessian_ff/<build_subdir>
|
|
86
|
+
"""
|
|
87
|
+
cache_root = Path(
|
|
88
|
+
os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
|
89
|
+
)
|
|
90
|
+
return cache_root / "mlmm-toolkit" / "hessian_ff" / build_subdir
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _build_in_tree_extension(
|
|
94
|
+
*,
|
|
95
|
+
key: str,
|
|
96
|
+
ext_name: str,
|
|
97
|
+
source_files: list[str],
|
|
98
|
+
build_subdir: str,
|
|
99
|
+
verbose: bool,
|
|
100
|
+
force_rebuild: bool,
|
|
101
|
+
) -> Optional[Any]:
|
|
102
|
+
if _EXT_CACHE[key] is not None and not force_rebuild:
|
|
103
|
+
return _EXT_CACHE[key]
|
|
104
|
+
if _EXT_ERROR[key] is not None and not force_rebuild:
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
here = Path(__file__).resolve().parent
|
|
108
|
+
# Candidate build directories: package-internal first, then user cache.
|
|
109
|
+
pkg_build_dir = here / build_subdir
|
|
110
|
+
cache_build_dir = _cache_build_dir(build_subdir)
|
|
111
|
+
build_dirs = [pkg_build_dir, cache_build_dir]
|
|
112
|
+
|
|
113
|
+
def _find_prebuilt_so() -> Optional[Path]:
|
|
114
|
+
"""Search all candidate directories for a prebuilt .so."""
|
|
115
|
+
for bd in build_dirs:
|
|
116
|
+
if not bd.is_dir():
|
|
117
|
+
continue
|
|
118
|
+
cands = sorted(
|
|
119
|
+
bd.glob(f"{ext_name}*.so"),
|
|
120
|
+
key=lambda p: p.stat().st_mtime,
|
|
121
|
+
reverse=True,
|
|
122
|
+
)
|
|
123
|
+
if cands:
|
|
124
|
+
return cands[0]
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
def _load_prebuilt_so(path: Path) -> Optional[Any]:
|
|
128
|
+
try:
|
|
129
|
+
mod_name = path.stem
|
|
130
|
+
if mod_name in sys.modules:
|
|
131
|
+
mod = sys.modules[mod_name]
|
|
132
|
+
_EXT_CACHE[key] = mod
|
|
133
|
+
_EXT_ERROR[key] = None
|
|
134
|
+
return mod
|
|
135
|
+
spec = importlib.util.spec_from_file_location(mod_name, str(path))
|
|
136
|
+
if spec is None or spec.loader is None:
|
|
137
|
+
raise ImportError(f"spec loader is unavailable for {path}")
|
|
138
|
+
mod = importlib.util.module_from_spec(spec)
|
|
139
|
+
spec.loader.exec_module(mod)
|
|
140
|
+
_EXT_CACHE[key] = mod
|
|
141
|
+
_EXT_ERROR[key] = None
|
|
142
|
+
return mod
|
|
143
|
+
except Exception as e:
|
|
144
|
+
_EXT_ERROR[key] = _with_rebuild_hint(
|
|
145
|
+
f"failed to load prebuilt extension {path}: {e}"
|
|
146
|
+
)
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
# Prefer prebuilt artifact when available (useful on nodes without a compiler toolchain).
|
|
150
|
+
if not force_rebuild:
|
|
151
|
+
prebuilt = _find_prebuilt_so()
|
|
152
|
+
if prebuilt is not None:
|
|
153
|
+
loaded = _load_prebuilt_so(prebuilt)
|
|
154
|
+
if loaded is not None:
|
|
155
|
+
return loaded
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
from torch.utils.cpp_extension import load
|
|
159
|
+
except Exception as e:
|
|
160
|
+
_EXT_ERROR[key] = _with_rebuild_hint(
|
|
161
|
+
f"torch cpp_extension import failed: {e}"
|
|
162
|
+
)
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
_ensure_max_jobs()
|
|
166
|
+
|
|
167
|
+
srcs = [here / s for s in source_files]
|
|
168
|
+
|
|
169
|
+
def _try_build_in_dir(
|
|
170
|
+
build_dir: Path,
|
|
171
|
+
extra_cflags: list[str],
|
|
172
|
+
extra_ldflags: Optional[list[str]] = None,
|
|
173
|
+
):
|
|
174
|
+
os.makedirs(build_dir, exist_ok=True)
|
|
175
|
+
kwargs = dict(
|
|
176
|
+
name=ext_name,
|
|
177
|
+
sources=[str(s) for s in srcs],
|
|
178
|
+
extra_cflags=extra_cflags,
|
|
179
|
+
extra_ldflags=(extra_ldflags or []),
|
|
180
|
+
build_directory=str(build_dir),
|
|
181
|
+
verbose=bool(verbose),
|
|
182
|
+
)
|
|
183
|
+
# Some cluster conda envs do not provide ninja. Prefer distutils build
|
|
184
|
+
# in that case instead of failing hard.
|
|
185
|
+
if shutil.which("ninja") is None:
|
|
186
|
+
kwargs["use_ninja"] = False
|
|
187
|
+
try:
|
|
188
|
+
return load(**kwargs)
|
|
189
|
+
except TypeError:
|
|
190
|
+
kwargs.pop("use_ninja", None)
|
|
191
|
+
return load(**kwargs)
|
|
192
|
+
|
|
193
|
+
# Try aggressive CPU flags first, then fall back progressively.
|
|
194
|
+
build_attempts = [
|
|
195
|
+
(["-Ofast", "-ffast-math", "-funroll-loops", "-march=native", "-mtune=native", "-fopenmp"], ["-fopenmp"]),
|
|
196
|
+
(["-O3", "-ffast-math", "-funroll-loops", "-march=native", "-mtune=native", "-fopenmp"], ["-fopenmp"]),
|
|
197
|
+
(["-O3", "-ffast-math", "-funroll-loops", "-fopenmp"], ["-fopenmp"]),
|
|
198
|
+
(["-O3", "-fopenmp"], ["-fopenmp"]),
|
|
199
|
+
(["-O3"], []),
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
# Try each build directory: package-internal first, then user cache.
|
|
203
|
+
last_err: Optional[Exception] = None
|
|
204
|
+
for build_dir in build_dirs:
|
|
205
|
+
try:
|
|
206
|
+
os.makedirs(build_dir, exist_ok=True)
|
|
207
|
+
except OSError:
|
|
208
|
+
continue
|
|
209
|
+
for cflags, ldflags in build_attempts:
|
|
210
|
+
try:
|
|
211
|
+
_EXT_CACHE[key] = _try_build_in_dir(
|
|
212
|
+
build_dir,
|
|
213
|
+
extra_cflags=cflags,
|
|
214
|
+
extra_ldflags=ldflags,
|
|
215
|
+
)
|
|
216
|
+
_EXT_ERROR[key] = None
|
|
217
|
+
return _EXT_CACHE[key]
|
|
218
|
+
except Exception as e:
|
|
219
|
+
last_err = e
|
|
220
|
+
continue
|
|
221
|
+
# All flag combinations failed in this directory; try next.
|
|
222
|
+
|
|
223
|
+
_EXT_CACHE[key] = None
|
|
224
|
+
_EXT_ERROR[key] = _with_rebuild_hint(
|
|
225
|
+
f"hessian_ff build attempts failed: {last_err}"
|
|
226
|
+
)
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def get_nonbonded_extension(
|
|
231
|
+
*,
|
|
232
|
+
verbose: bool = False,
|
|
233
|
+
force_rebuild: bool = False,
|
|
234
|
+
) -> Optional[Any]:
|
|
235
|
+
"""Build/load in-tree C++ extension for nonbonded kernels.
|
|
236
|
+
|
|
237
|
+
References:
|
|
238
|
+
- torch.utils.cpp_extension.load() runtime build workflow.
|
|
239
|
+
"""
|
|
240
|
+
return _build_in_tree_extension(
|
|
241
|
+
key="nonbonded",
|
|
242
|
+
ext_name="hessian_ff_nonbonded_ext",
|
|
243
|
+
source_files=["nonbonded_ext.cpp"],
|
|
244
|
+
build_subdir=".build_nonbonded",
|
|
245
|
+
verbose=bool(verbose),
|
|
246
|
+
force_rebuild=bool(force_rebuild),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def nonbonded_extension_status() -> Dict[str, str]:
|
|
251
|
+
ext = get_nonbonded_extension(verbose=False, force_rebuild=False)
|
|
252
|
+
if ext is None:
|
|
253
|
+
note = _EXT_ERROR["nonbonded"] or _with_rebuild_hint("extension unavailable")
|
|
254
|
+
return {
|
|
255
|
+
"available": "false",
|
|
256
|
+
"backend": "native_required",
|
|
257
|
+
"note": note,
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
"available": "true",
|
|
261
|
+
"backend": "native_nonbonded_cpp",
|
|
262
|
+
"note": "nonbonded extension loaded",
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def get_analytical_hessian_extension(
|
|
267
|
+
*,
|
|
268
|
+
verbose: bool = False,
|
|
269
|
+
force_rebuild: bool = False,
|
|
270
|
+
) -> Optional[Any]:
|
|
271
|
+
"""Build/load in-tree C++ extension for analytical Hessian helpers."""
|
|
272
|
+
return _build_in_tree_extension(
|
|
273
|
+
key="analytical_hessian",
|
|
274
|
+
ext_name="hessian_ff_analytical_hessian_ext",
|
|
275
|
+
source_files=["analytical_hessian_ext.cpp"],
|
|
276
|
+
build_subdir=".build_analytical_hessian",
|
|
277
|
+
verbose=bool(verbose),
|
|
278
|
+
force_rebuild=bool(force_rebuild),
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def analytical_hessian_extension_status() -> Dict[str, str]:
|
|
283
|
+
ext = get_analytical_hessian_extension(verbose=False, force_rebuild=False)
|
|
284
|
+
if ext is None:
|
|
285
|
+
note = _EXT_ERROR["analytical_hessian"] or _with_rebuild_hint("extension unavailable")
|
|
286
|
+
return {
|
|
287
|
+
"available": "false",
|
|
288
|
+
"backend": "native_analytical_hessian_optional",
|
|
289
|
+
"note": note,
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
"available": "true",
|
|
293
|
+
"backend": "native_analytical_hessian_cpp",
|
|
294
|
+
"note": "analytical Hessian extension loaded",
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def get_bonded_extension(
|
|
299
|
+
*,
|
|
300
|
+
verbose: bool = False,
|
|
301
|
+
force_rebuild: bool = False,
|
|
302
|
+
) -> Optional[Any]:
|
|
303
|
+
"""Build/load in-tree C++ extension for bonded energy-force kernels."""
|
|
304
|
+
return _build_in_tree_extension(
|
|
305
|
+
key="bonded",
|
|
306
|
+
ext_name="hessian_ff_bonded_ext",
|
|
307
|
+
source_files=["bonded_ext.cpp"],
|
|
308
|
+
build_subdir=".build_bonded",
|
|
309
|
+
verbose=bool(verbose),
|
|
310
|
+
force_rebuild=bool(force_rebuild),
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def bonded_extension_status() -> Dict[str, str]:
|
|
315
|
+
ext = get_bonded_extension(verbose=False, force_rebuild=False)
|
|
316
|
+
if ext is None:
|
|
317
|
+
note = _EXT_ERROR["bonded"] or _with_rebuild_hint("extension unavailable")
|
|
318
|
+
return {
|
|
319
|
+
"available": "false",
|
|
320
|
+
"backend": "native_bonded_optional",
|
|
321
|
+
"note": note,
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
"available": "true",
|
|
325
|
+
"backend": "native_bonded_cpp",
|
|
326
|
+
"note": "bonded extension loaded",
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def build_native_extensions(
|
|
331
|
+
*,
|
|
332
|
+
verbose: bool = False,
|
|
333
|
+
force_rebuild: bool = False,
|
|
334
|
+
) -> Dict[str, str]:
|
|
335
|
+
"""Build/load all native extensions up front.
|
|
336
|
+
|
|
337
|
+
This provides a practical "compile together" workflow by triggering
|
|
338
|
+
all in-tree extension builds in one step before production runs.
|
|
339
|
+
"""
|
|
340
|
+
ext_nb = get_nonbonded_extension(verbose=verbose, force_rebuild=force_rebuild)
|
|
341
|
+
ext_ah = get_analytical_hessian_extension(verbose=verbose, force_rebuild=force_rebuild)
|
|
342
|
+
ext_bd = get_bonded_extension(verbose=verbose, force_rebuild=force_rebuild)
|
|
343
|
+
return {
|
|
344
|
+
"nonbonded": "ok" if ext_nb is not None else f"error: {_EXT_ERROR['nonbonded']}",
|
|
345
|
+
"analytical_hessian": "ok"
|
|
346
|
+
if ext_ah is not None
|
|
347
|
+
else f"error: {_EXT_ERROR['analytical_hessian']}",
|
|
348
|
+
"bonded": "ok" if ext_bd is not None else f"error: {_EXT_ERROR['bonded']}",
|
|
349
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
|
|
5
|
+
from .loader import get_nonbonded_extension, nonbonded_extension_status
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def nonbonded_energy_force_native(
|
|
9
|
+
*,
|
|
10
|
+
coords: torch.Tensor,
|
|
11
|
+
charge: torch.Tensor,
|
|
12
|
+
atom_type: torch.Tensor,
|
|
13
|
+
lj_acoef: torch.Tensor,
|
|
14
|
+
lj_bcoef: torch.Tensor,
|
|
15
|
+
hb_acoef: torch.Tensor,
|
|
16
|
+
hb_bcoef: torch.Tensor,
|
|
17
|
+
nb_index: torch.Tensor,
|
|
18
|
+
pair_i: torch.Tensor,
|
|
19
|
+
pair_j: torch.Tensor,
|
|
20
|
+
pair14_i: torch.Tensor,
|
|
21
|
+
pair14_j: torch.Tensor,
|
|
22
|
+
pair14_inv_scee: torch.Tensor,
|
|
23
|
+
pair14_inv_scnb: torch.Tensor,
|
|
24
|
+
cpu_fast: bool = True,
|
|
25
|
+
verbose: bool = False,
|
|
26
|
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
27
|
+
"""Call C++ nonbonded extension.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
(E_coul, E_lj, E_coul14, E_lj14, force)
|
|
32
|
+
|
|
33
|
+
References:
|
|
34
|
+
- native/nonbonded_ext.cpp in this repository.
|
|
35
|
+
"""
|
|
36
|
+
ext = get_nonbonded_extension(verbose=verbose, force_rebuild=False)
|
|
37
|
+
if ext is None:
|
|
38
|
+
status = nonbonded_extension_status()
|
|
39
|
+
raise RuntimeError(
|
|
40
|
+
"native nonbonded extension is unavailable; torch fallback is disabled. "
|
|
41
|
+
f"detail: {status.get('note')}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
chunk_size = max(int(pair_i.numel()), int(pair14_i.numel()), 1)
|
|
45
|
+
out = ext.nonbonded_energy_force(
|
|
46
|
+
coords,
|
|
47
|
+
charge,
|
|
48
|
+
atom_type,
|
|
49
|
+
lj_acoef,
|
|
50
|
+
lj_bcoef,
|
|
51
|
+
hb_acoef,
|
|
52
|
+
hb_bcoef,
|
|
53
|
+
nb_index,
|
|
54
|
+
pair_i,
|
|
55
|
+
pair_j,
|
|
56
|
+
pair14_i,
|
|
57
|
+
pair14_j,
|
|
58
|
+
pair14_inv_scee,
|
|
59
|
+
pair14_inv_scnb,
|
|
60
|
+
int(chunk_size),
|
|
61
|
+
bool(cpu_fast),
|
|
62
|
+
-1,
|
|
63
|
+
)
|
|
64
|
+
return out[0], out[1], out[2], out[3], out[4]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def nonbonded_energy_force_preparam_native(
|
|
68
|
+
*,
|
|
69
|
+
coords: torch.Tensor,
|
|
70
|
+
pair_i: torch.Tensor,
|
|
71
|
+
pair_j: torch.Tensor,
|
|
72
|
+
pair_coul_coeff: torch.Tensor,
|
|
73
|
+
pair_a12_coeff: torch.Tensor,
|
|
74
|
+
pair_b6_coeff: torch.Tensor,
|
|
75
|
+
pair_b10_coeff: torch.Tensor,
|
|
76
|
+
pair14_i: torch.Tensor,
|
|
77
|
+
pair14_j: torch.Tensor,
|
|
78
|
+
pair14_coul_coeff: torch.Tensor,
|
|
79
|
+
pair14_a12_coeff: torch.Tensor,
|
|
80
|
+
pair14_b6_coeff: torch.Tensor,
|
|
81
|
+
pair14_b10_coeff: torch.Tensor,
|
|
82
|
+
cpu_fast: bool = True,
|
|
83
|
+
verbose: bool = False,
|
|
84
|
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
85
|
+
"""Call C++ nonbonded extension using precomputed pair coefficients.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
(E_coul, E_lj, E_coul14, E_lj14, force)
|
|
90
|
+
"""
|
|
91
|
+
ext = get_nonbonded_extension(verbose=verbose, force_rebuild=False)
|
|
92
|
+
if ext is None:
|
|
93
|
+
status = nonbonded_extension_status()
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
"native nonbonded extension is unavailable; torch fallback is disabled. "
|
|
96
|
+
f"detail: {status.get('note')}"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
chunk_size = max(int(pair_i.numel()), int(pair14_i.numel()), 1)
|
|
100
|
+
out = ext.nonbonded_energy_force_preparam(
|
|
101
|
+
coords,
|
|
102
|
+
pair_i,
|
|
103
|
+
pair_j,
|
|
104
|
+
pair_coul_coeff,
|
|
105
|
+
pair_a12_coeff,
|
|
106
|
+
pair_b6_coeff,
|
|
107
|
+
pair_b10_coeff,
|
|
108
|
+
pair14_i,
|
|
109
|
+
pair14_j,
|
|
110
|
+
pair14_coul_coeff,
|
|
111
|
+
pair14_a12_coeff,
|
|
112
|
+
pair14_b6_coeff,
|
|
113
|
+
pair14_b10_coeff,
|
|
114
|
+
int(chunk_size),
|
|
115
|
+
bool(cpu_fast),
|
|
116
|
+
-1,
|
|
117
|
+
)
|
|
118
|
+
return out[0], out[1], out[2], out[3], out[4]
|