Skip to content

feat(nttda): add analytic gradients for ROKS and AOCSCF - #18

Open
wtpeter wants to merge 18 commits into
NonDFT:mainfrom
wtpeter:jingjjkk/feature/dz0scf-gradient-clean
Open

wtpeter wants to merge 18 commits into
NonDFT:mainfrom
wtpeter:jingjjkk/feature/dz0scf-gradient-clean

Conversation

@wtpeter

@wtpeter wtpeter commented Sep 26, 2026

Copy link
Copy Markdown
Collaborator

Adds NTTDA analytic nuclear gradients for ΔS = −1 and 0 with both conventional ROKS and average-occupation ROKS (AOCSCF) references. Finite-difference gradients are available for all three spin channels. td.Gradients().kernel(state=n) and the gradient scanner return derivatives of the selected total energy.

Implementation and compatibility

  • Reuses the existing gradient equations, orbital response, and MO-grid GGA/MGGA response contractions from the contributor's branch, adapting them to the current AOCSCF interfaces.
  • Preserves main's ΔS = −1 projection and physical zero roots, and uses nest._lr_eig with its existing subspace sizing.
  • Uses the existing td._scf.e_tot and td.e_tot energy interfaces. Includes selected-state scanner handling, symmetry-aware atom selection, maintained examples, and documentation.
  • Keeps the contributor's commit history. No new dependencies.

Validation

Run in the nest Conda environment with PySCF 2.14.0 and OMP_NUM_THREADS=2:

  • NTTDA tests (test_nttda.py, test_nttda_aocscf.py, test_nttda_oscillator_strength.py): 17 passed, 36 subtests passed.
  • Gradient tests (test_nttda_grad.py, test_nttda_aocscf_fd.py, test_nttda_aocscf_response.py, test_nttda_gradient_layers.py, test_nttda_scalar_ledger.py): 18 passed, 105 subtests passed.
  • python -m ruff check . and git diff --check main...HEAD: passed.
  • Temporary scanner checks passed for ROKS/AOCSCF × ΔS = −1/0, including a selected excited state, displaced geometry, and the reference state.
  • Temporary AOCSCF checks across six functionals, with and without symmetry, found a maximum response-action difference of approximately 1.3e-14 between the two nobeta settings.

The full repository suite has not been rerun on the final commit; the results above cover the affected NTTDA and gradient tests.

Limitations

Analytic ΔS = +1 gradients remain unsupported. Analytic DFT gradients omit numerical-grid response; finite-difference validation uses fixed grids by default. The NTTDA gradient driver does not support density fitting, X2C, solvent response, or nonlocal correlation.

Betty0621 and others added 17 commits August 29, 2026 06:35
Port the average/roks dual-semantics EnsembleRKS reference (fixed
2/1/0 occupations, Dz = 0) and align Dz0SCF with the shared
reference_energy semantics so NTTDA can treat both reference types
uniformly.
Port the NTTDA response/gradient stack (deltaS = -1/0 channels,
XC ledger kernels, ensemble orbital-response backend) and wire
NTTDA.nuc_grad_method to nest.grad.nttda.Gradients.  The linear
solver uses pyscf.tdscf._lr_eig: the nest._lr_eig fork does not
converge on the ensemble orbital Hessian.
Add the ensemble FD/response, scalar-ledger, gradient-layer, and
known-value NTTDA energy suites.
Drop the EnsembleRKS reference path and drive the NTTDA gradient from
Dz0SCF (average-occupation) and ROKS only.  Dz0SCF now exposes the
average-occupation marker plus a charge-RKS companion for the
spin-unpolarized response, rebuilt on every call so a reused mean-field
object (reset/new geometry/xc change) never reuses a stale reference.
Port the ensemble suites to Dz0SCF and add a cache-invalidation
regression test.
Remove the stale spin-lowering-only transition methods that shadow the upstream all-channel implementation after merging main. Restore nest._lr_eig so oscillator strengths retain upstream convergence behavior. The existing all-channel oscillator-strength regression passes without changing its tolerance.
Keep spin-channel amplitudes and coefficients explicit while sharing orbital partitions, reference responses, J/K derivative batching, Fz exchange and adjoint assembly. Consolidate identical GGA and meta-GGA quadrature flows with explicit density dimensions and kernel dispatch. Remove 1216 net lines from the gradient package; retain existing numerical checks and tolerances.
Retain the branch's PySCF response solver: the shared NEST solver fails the existing small-system Dz0SCF convergence checks. Explicitly converge oscillator-strength amplitudes to 1e-9 with lindep=1e-18 rather than relying on the default 1e-5 residual; reference values and assertion tolerances are unchanged. Seven targeted tests and eight subtests pass.
Build channel projections once per gradient and reuse the shared transition-potential projection. Share adjoint assembly and Krylov mechanics while retaining reference-specific Hessians and preconditioners. Use a singleton density-feature axis for LDA to share the GGA/MGGA quadrature loops, retaining distinct pair kernels. Consolidate HF/DFT Fock derivatives and remove unreferenced channel projection wrappers. Net reduction: 604 implementation lines; existing numerical tests and tolerances are unchanged.
@wtpeter
wtpeter requested a review from jingjjkkyj September 26, 2026 12:32
@wtpeter
wtpeter requested a lite review from Copilot September 27, 2026 12:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants