Add long-range Coulomb Hessians and batched Hessian support#78
Conversation
Enable Hessians for periodic long-range Coulomb and lift the single-structure restriction on Hessian calculations. - DSF: add a closed-form, autograd-twice-differentiable pure-PyTorch DSF Coulomb energy and route to it for Hessian and force/stress training (the nvalchemiops DSF kernel detaches geometry). Includes the DSF self-energy term; matches the kernel energy to 1e-4. - Ewald/PME: provide a Hessian via finite-difference of the analytic nvalchemiops forces (computed in float64), summed with the NN and short-range autograd Hessian in get_derivatives. - Batched Hessian: support 3D batched inputs (stacked (B,N,3,N,3)) and multi-molecule mol_idx inputs (per-molecule list) via a per-structure loop over the validated single-structure path. - Document fixed-charge (Ewald/PME) vs relaxed-charge (DSF) Hessian semantics and the DSF cutoff C2 discontinuity for vibrational use.
- float64: accumulate the Ewald/PME FD Hessian block in its own precision instead of downcasting to the model Hessian dtype - batched Hessian: snapshot/restore calculator state around the per-structure eval loop so a periodic batch no longer leaves the coulomb method permanently switched - _split_mol_idx forwards the pbc key; _split_batch_dim drops precomputed nbmat/shifts/mol_idx so they are rebuilt per structure - FD Hessian loop reuses one scratch buffer (drops 6N per-iter clones) - drop redundant q.clone() in the DSF self-energy mask - type eval/__call__ as dict[str, Any] and document the batched/list return regimes; reword the multi-molecule in-call guard message - docs: correct the stale LRCoulomb class docstring and surface the fixed-charge (Ewald/PME) vs relaxed-charge (DSF) Hessian caveat on set_lrcoulomb_method for vibrational/IR users - gitignore stray Hessian/optimization run artifacts
|
Addressed multi-review findings in Fixed (commit 7622349):
Deferred (not blocking): the larger contract redesign (a separate batched-Hessian entry point vs. the polymorphic Full suite green: |
|
Added a matrix-free Hessian-vector product ( Why: the dense Hessian is O(N²) memory + 3N backward passes. For negative-curvature saddle checks (Lanczos/LOBPCG) and Hessian-preconditioned optimization (CG-Newton), what's actually needed is How it mirrors the dense assembly (so it's verifiable against the trusted dense Hessian):
Correctness gate: Scope & contract: single-structure only (mirrors the dense-Hessian restriction; batched/ Multi-agent reviewed (gpu-pytorch / computational-chemist / architect). The review caught and we fixed: DFT-D3 curvature was being dropped from Full suite green: |
Summary
Enables long-range Coulomb Hessians and lifts the single-structure restriction on Hessian calculations in
AIMNet2Calculator. Previouslycalc(data, hessian=True)raisedNotImplementedErrorfor all periodic LR Coulomb methods (dsf,ewald,pme) and supported only a single structure.LRCoulomb._coul_dsf_torch) and routes to it for Hessian and force/stress training (thenvalchemiopsDSF kernel detaches geometry). Includes the DSF self-energy term; matches the kernel energy to 1e-4, including the periodic path (shifts @ cell).nvalchemiopsforces (_coul_nvalchemi_fd_hessian), computed in float64, summed with the NN + short-range autograd Hessian inget_derivatives. The short-range subtraction stays in the autograd graph, so the FD block supplies only the full-periodic term (correct for bothsubtract_srsettings).(B,N,3,N,3)) and multi-moleculemol_idxinputs (per-molecule list) via a per-structure loop over the existing validated single-structure path. Composes with the periodic paths above.Test Plan
tests/test_calculator.py,tests/test_pbc.py,tests/test_lr.py: 227 passed.Notes
nvalchemi-toolkit-ops >= 0.3.1(already declared inpyproject.toml; thehybrid_forceskernel arg the Ewald/PME path uses is absent in 0.3.0).tests/test_pbc.py::TestCalculatorPBC::test_calculator_pbc_both_methods[dsf]fails under certain test orderings withRuntimeError: Cannot access data pointer ... that doesn't have storage(a FakeTensor leak from an earliertorch.compile/vmaptest). This reproduces onmainand passes in isolation; it is a test-isolation artifact, not a product regression from this PR.