Refactor hsolver: LCAO direct solvers take H(k)/S(k), not the Hamiltonian - #7948
Merged
mohanchen merged 1 commit intoSep 10, 2026
Conversation
…nian DiagoScalapack, DiagoElpa, DiagoElpaNative, DiagoLapack, DiagoPexsi and DiagoCusolverMP each took a hamilt::Hamilt<T>* and used it for exactly one thing: `phm_in->matrix(h_mat, s_mat)` on the first line of diag(). Hoist that call into the caller and take the two matrix blocks instead, which is what DiagoCusolver::diag() and every diag_pool() already did. Parallel_K2D::distribute_hsk interleaves updateHk() and matrix() inside a collective loop, so it cannot simply hoist. It now takes an HskFunc callback and HSolverLCAO supplies the closure; the loop structure and the sequence of collective calls are unchanged. HSolverLCAO::hamiltSolvePsiK fetches H(k)/S(k) once instead of once per solver branch. HamiltLCAO::matrix() is a pure accessor (OperatorLCAO:: matrixHk only fills the blocks from pointers it already holds) and updateHk(ik) still runs before it, so the hoist is behaviour-neutral. The four LCAO test files defined a `HamiltTEST : public hamilt::Hamilt<T>` whose only job was handing back H and S; they are now plain matrix suppliers with no source_hamilt dependency. The matd/matcd typedefs existed only for the deleted temporaries and are removed. source_hsolver -> source_hamilt includes: 13 files / 13 lines -> 6 files / 6 lines. No behaviour change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reminder
AGENTS.mdanddocs/developers_guide/agent_governance.md.source/changes.Linked Issue
No issue. Follow-up to #7920, second step of making
source_hsolveraself-contained numerical module. Behaviour-neutral and self-contained, so it is
sent on its own rather than bundled with the remaining steps.
Unit Tests and/or Case Tests for my changes
Commands run (Linux, gcc, cmake 3.31 + ninja, 15 cores). The base commit
d3722debdand this branch were built and tested in the same build tree, sothe comparison is exact rather than approximate.
Full build.
ENABLE_ELPA=ONmatters here: without itdiago_elpa.cppanddiago_elpa_native.cppare not compiled at all, and two of the six changedclasses would go unchecked.
CUDA paths — the
__CUDAbranch ofhsolver_lcao.cppand the cusolver testboth changed:
PEXSI path — no PEXSI library on this machine, but
module_pexsi/pexsi_solver.honly needs
<vector>, so the translation unit is still syntax-checkable:Result summary
d3722debdhsolver+diag_cusolver+MODULE_HSOLVER_LCAO_cusolverdiago_pexsi.cpp-D__PEXSI -fsyntax-onlyagent_governance_check.py --stagedThe two failing sets are identical test-for-test —
diffof the sortedThe following tests FAILEDlists is empty.Direct numerical check of the changed solvers.
MODULE_HSOLVER_LCAOsits inthat pre-existing failing set, but only because ctest runs it from the build
directory where it cannot find its
*.datfixtures. Run fromsource/source_hsolver/test/, where the fixtures live, it does real work andchecks eigenvalues against stored references:
DiagoGammaOnlyTest.LCAO/0— genelpa, Si64, NLOCAL=832DiagoGammaOnlyTest.LCAO/1— scalapack_gvx, Si2DiagoGammaOnlyTest.LCAO/2— lapack, Si2DiagoKPointsTest.LCAO/*So
DiagoElpa,DiagoScalapackandDiagoLapackeach reproduce theirreference eigenvalues through the new signature. The
DiagoKPointsTestsuitesegfaults identically before and after this change — on 1 rank and on 4, and
also with the genelpa case filtered out — so it is a pre-existing problem with
that suite in this sandbox, which I have not tried to fix here.
Checks not run, with reason
-DENABLE_CUSOLVERMP=ON(diago_cusolvermp.cpp): this machine has nocuSOLVERMp / NCCL headers, so
kernels/cuda/diag_cusolvermp.cuhcannot evenbe preprocessed (the same limitation as Refactor hsolver: move MatrixBlock to source_base, drop dead hamilt include #7920). The edit there is the same
signature change as the other five; I checked its declaration and definition
against each other by hand.
tests/: no code path and no arithmetic changes, onlywhere the two matrix blocks are fetched. CI covers them.
What's changed?
Six LCAO direct eigensolvers took a
hamilt::Hamilt<T>*and used it for exactlyone thing —
phm_in->matrix(h_mat, s_mat)on the first line ofdiag():DiagoScalapack,DiagoElpa,DiagoElpaNative,DiagoLapack,DiagoPexsi,DiagoCusolverMP.They now take the two matrix blocks directly, and the caller does the one
matrix()call. That is already howDiagoCusolver::diag()and everydiag_pool()in this directory work, so this makes the six consistent with theparts of the module that were decoupled first, rather than inventing a pattern.
Three consequences:
HSolverLCAO::hamiltSolvePsiKfetchesH(k)/S(k)once at the topinstead of once inside each of the six solver branches.
HamiltLCAO::matrix()is a pure accessor —
OperatorLCAO::matrixHkonly fills the blocks frompointers it already holds — and
updateHk(ik)still runs before it insolve(), so hoisting is behaviour-neutral. Same hoist in the PEXSI branch,where
matrix()now sits next to theupdateHk(ik)it belongs to.Parallel_K2D::distribute_hskinterleavesupdateHk()andmatrix()inside a loop of collective
Cpxgemr2dcalls, so it cannot simply hoist. Itnow takes an
HskFunccallback andHSolverLCAOsupplies the closure. Theloop structure and the sequence of collective calls are untouched — only the
source of the blocks moved out.
Parallel_K2Dis now a pure redistributionhelper with no Hamiltonian dependency.
The four LCAO test files each defined a
HamiltTEST : public hamilt::Hamilt<T>whose entire body was handing backHand
S. They are now plain matrix suppliers, with thehamilt::Hamiltsubclass, the empty
constructHamilt/updateHkoverrides, and thesource_hamiltdependency all gone.The
matd/matcdtypedefs in four.cppfiles existed only to declare thetemporaries that are now parameters, and are removed.
source_hsolverfiles includingsource_hamilt#include "source_hamilt/..."lines thereWhat is left is
diago_iter_assist.hand the fourHSolver*façade files, whichgenuinely hold a
hamilt::Hamilt*— those are the next two steps, not this one.Governance Notes
Input_Item, no user-visible behavior, nooutput format is touched.
Hamiltinterface as seen fromHSolver. No
hamilt::class changes at all — the six solvers simply stopasking for one.
hamilt::Hamilt<T>::matrix()keeps all its other callers insource_lcao,source_estate,source_ioandsource_esolver, untouched.No numerical change: the same
MatrixBlockvalues reach the same solver codein the same order.
agent_governance_check.pywarnings:
source_hamilt/hamilt.hand gainssource_base/matrix_block.hand/orsource_psi/psi.h— the declarations it actually needs, which used toarrive transitively through
hamilt.h. Net direction is narrower, notwider.
changed (they had to be, the mock's base class is gone), and the assertions
they make are identical. This is a signature refactor with no behaviour
change, so no new test would add coverage.
is updated in this PR (AGENTS.md rule 5).
🤖 Generated with Claude Code