Skip to content

Feature: LR-TDDFT analytical forces (gradients) by Z-vector method and excited-state geometry relaxation - #8069

Merged
mohanchen merged 134 commits into
deepmodeling:developfrom
maki49:LR-Grad-relax
Oct 18, 2026
Merged

mohanchen merged 134 commits into
deepmodeling:developfrom
maki49:LR-Grad-relax

Conversation

@maki49

@maki49 maki49 commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Features

  1. Analytic LR-TDDFT excited-state forces (Z-vector method, gamma-only)
  • Implements the Lagrangian/Z-vector equations to solve for the relaxed and energy-weighted transition density matrices, giving analytic excited-state forces matching well with finite differences (see results.md).
  • Supports RPA, LDA, GGA, Hartree-Fock, hybrid functionals (HSE/range-separated, including a sigma-clamping fix for the wpbeh kernel's short-range divergence) and the long-range-corrected (LRC) kernel.
  • Supports both spin-restricted (singlet/triplet) and spin-unrestricted (open-shell) excited states.
  • For a degenerate excited multiplet, computes and prints the full (non-diagonal) gradient matrix over the degenerate subspace, with its eigen-decomposition, instead of a single force vector.
  1. Excited-state geometry relaxation
  • Drives the existing Relax_Driver on an excited-state PES: the ground state is re-converged and the Z-vector gradient is recomputed at every ionic step.
  • Tracks the target excited state across ionic steps by maximum wavefunction overlap, so relaxation follows the same diabatic state through near-degeneracies/state crossings.
  • For degenerate states, adds an isotropic (symmetry-averaged) relax mode and a Jahn-Teller mode that follows the distortion direction extracted from the degenerate gradient matrix (lr_relax_degen_mode).

Refactors

  • Generalizes OperatorLRHxc/OperatorLREXX (previously built only for the Casida A-matrix) so the same Hxc/EXX operators are reused to build the Z-vector/multiplier equations.
  • Keeps the ground-state KS solver as a persistent member of ESolver_LR (rather than a one-shot temporary) so it can be re-run every ionic step during relaxation.

Other Behavior changes

  • KXC-enabled LibXC build in CI/CD: the build will take longer time.
  • XC kernel cutoffs: the density cutoff changes from 1e-6 to 1e-14, and the gradient cutoff from 1e-10 to 1e-20. This can change excitation energies even when forces are disabled. A four-rank A/B run reproduces the LDA gamma reference changes. The periodic Si multi-k case has a minimum spin density of approximately 1.29e-3, above the old cutoff; its four excitation energies agree at 17-digit output precision between the two settings.
  • Closed-shell singlet weighting: nspin=1 singlet response uses the factor-two Hartree/XC contribution, while ground-state S1_gs retains weight one. Existing single-spin excitation results can therefore change. BSE grid initialization uses S1_gs because HamiltBSE already applies the singlet factor; the existing RI BSE path is unaffected by this grid correction.
  • HSE06 kernel regularization: the LR HSE06 implementation clamps sigma to at least 1e-6 when evaluating XC derivatives. This can change HSE06 response energies and gradients near vanishing density gradients; it does not apply this clamp to ordinary PBE.
  • Composite XC third derivatives: contributions from multiple XC functionals are accumulated when evaluating kxc, rather than allowing the last functional to overwrite earlier contributions. This affects the XC contribution to analytic excited-state forces.
  • Davidson MPI broadcast: eigenvector broadcasts use the actual scalar type through the guarded wrapper, replacing an unconditional complex-double broadcast. This fixes real-valued MPI buffer handling and can affect both ground-state and LR calculations using this solver.
  • Gradient orbital window: the Z-vector calculation uses all available ground-state virtual bands, while lr_nvirt continues to select the response basis. The gradient can depend on the available ground-state band window even when the response basis is held fixed.
  • Failure handling: incomplete full-window wavefunction reads and unconverged Z-vector CG solves now fail explicitly instead of continuing to produce a force. CG convergence is checked using the final residual; its iteration limit and tolerance remain internal constants.
  • MPI and buffer robustness: empty local grid matrices, spin-resolved EXX density-matrix buffers, and the single-channel complex spectrum buffer are handled without invalid indexing or incorrect allocation assumptions.
  • Force output and diagnostics: excited-state force output and test force summaries retain ten decimal places. Full Z-vector dumps are restricted to test_force runs.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 10:06

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.

@maki49
maki49 marked this pull request as draft October 2, 2026 10:11
Comment thread source/source_lcao/module_lr/cal_edm.cpp
Comment thread source/source_lcao/module_lr/lr_force.cpp
@mohanchen mohanchen added Features Needed The features are indeed needed, and developers should have sophisticated knowledge EXX/lr-TDDFT/RPA/BSE/GW Related to beyond DFT methods labels Oct 2, 2026
@maki49
maki49 force-pushed the LR-Grad-relax branch 6 times, most recently from e5a8e55 to cd8346b Compare October 5, 2026 07:56
@maki49
maki49 marked this pull request as ready for review October 6, 2026 13:40
@mohanchen

Copy link
Copy Markdown
Collaborator

Thanks a lot for your hard work on this PR — the overall direction looks great! Below are a few suggestions, ordered from the easiest to the more involved ones. Most should be quick to address, and I'm happy to discuss any of them.

  1. File naming: please use lowercase for source file names. For consistency with the rest of the codebase, new source files should use all-lowercase names.
  2. INPUT parameter names must not exceed 15 characters. The name lr_relax_degen_mode violates this rule — please shorten it. This limit exists so that INPUT files stay nicely aligned and readable.
  3. Keep new files under 500 lines. A single file shouldn't exceed 500 lines. I know some existing code is over this limit too, but that's exactly why we need everyone's help to gradually break things down — at the very least, new code should not add to the problem. Splitting it up will also make this PR much easier to review and maintain.
  4. No mutable members. Please avoid mutable, such as the members dmr and dmr_save declared mutable so that the const function cal_dmr can modify them. A const function that mutates state is a sign the design needs adjusting — you're welcome to refactor the density matrix class itself instead, for example by making cal_dmr non-const, or by restructuring where these buffers live.
  5. Don't obtain data indirectly through the density matrix. I've already removed Parallel_Orbitals and get_kvec_d() from the density matrix. If you need these quantities, please pass them in as explicit parameters rather than borrowing them through the density matrix — that creates unnecessary data dependencies. Convenience is nice, but dependency hygiene matters more.
  6. ESolver functions should stay high-level. There's a strict convention for ESolver functions: they should only contain the top-level flow — the skeleton of the algorithm. All detailed work should go into free functions (not class member functions); if that's truly impractical, a class member function is acceptable as a fallback. For example, something at the level of print_force is a detail, and its definition should not live inside the ESolver. Think of the ESolver as an outline that directs the flow — it shouldn't manage any details itself.
  7. Merge with the existing LR ESolver rather than adding a new one. LR already has an ESolver — why introduce another one? If the new functionality can't be merged into the existing LR ESolver, that usually indicates a framework design issue. And when problems aren't fixed at the root, they tend to grow bigger and harder to clean up over time. Conceptually, I'd strongly recommend merging this into the existing LR ESolver as much as possible. This is the biggest item on the list, so feel free to reach out if you'd like to discuss the design together!
    None of these are blockers in spirit — items 1–3 are quick fixes, and for items 4–7 I'm glad to help brainstorm the refactoring approach. Looking forward to the next iteration!

@maki49

maki49 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

@mohanchen For the last point (7.), no new ESolver is added: esolver_lr_grad.cpp is just a separate .cpp file from esolver_lr_lcao_tddft.cpp, corresponding to esolver_lr_lcao_tddft.h.
All of your other suggestions have been followed by the last several refactor commits.

maki49 and others added 15 commits October 7, 2026 00:19
Port the LR-Grad series (44 commits, 7c6398d..6aea1fc, all by maki49)
onto current develop as a single squashed change, adapted to develop's
large-scale refactor.

Path/layout migration:
  module_lr        -> source_lcao/module_lr
  module_ri        -> source_lcao/module_ri (Exx_LRI.h -> exx_lri.h)
  esolver_lrtd_lcao -> source_esolver/esolver_lr_lcao_tddft
  ESolver_LR now lives in namespace ModuleESolver, not LR.

Interface adaptation:
  - Grid integration: the Gint_Gamma/Gint_k objects and TGint<T> selector
    are gone. All call sites now use the free functions in ModuleGint
    (cal_gint_rho / cal_gint_vl / cal_gint_fvl); the gint pointer has been
    removed from LR_Force, LR_Density, OperatorLRHxc, HamiltLR/HamiltULR,
    the Z-equation Hamiltonians and the multiplier helpers.
  - PulayForceStress::cal_pulay_fs (grid overload) keeps the explicit
    `nspin` argument the gradient code needs; develop's own callers pass
    PARAM.inp.nspin.
  - Parallel_Orbitals::get_row_size(iat)/get_col_size(iat)
    -> get_nrow_atom(iat)/get_ncol_atom(iat).
  - elecstate::Potential::init_pot(istep, chg) -> init_pot(chg);
    get_effective_v -> get_eff_v; Structure_Factor::setup_structure_factor
    -> setup; Charge::allocate now takes kin_den.
  - ModuleIO::output_single_R takes a SparseWriteOptions struct.
  - ModuleIO::read_wfc_nao uses develop's signature (ik2iktot/nkstot/nspin).
  - ModuleBase::timer::tick -> start/end pairs.
  - LR_Util::gather_2d_to_full keeps develop's explicit-dimension form;
    scatter_full_to_2d is added for the Z-equation solver.
  - get_DMR_real_imag_part / set_HR_real_imag_part are now the templated,
    nat-free versions; module_bse call sites updated, the now-dead
    lr_util_hcontainer.cpp is removed.
  - DensityMatrix::cal_DMR is const (_DMR is mutable).

Known gap: LR_Force::cal_force_exx_gs_dm_relaxed_diff still uses
RI::LR from LibRI, which no longer derives from RI::Exx in the current
LibRI master (commit 5c6c262 refactored it into a k-space CVCX/BSE helper).
That single function does not compile; everything else does.
…X force kernel

LibRI commit 5c6c262 repurposed RI::LR: it no longer derives from RI::Exx and
lost set_Ds/cal_Hs/cal_force/force. Reintroduce just the piece the LR-TDDFT
gradient needs as LR::ExxForceTwoDM, a thin RI::Exx subclass whose cal_force
overload overwrites post_2D.saves["Ds_<suffix>"] with the left density matrix
before delegating to Exx::cal_force. This reproduces the old RI::LR semantics
(D_IJ from Ds_left, D_KL from set_Ds) without pinning LibRI.

Also drop dm_trans/dmr_complex.cpp from the build: develop moved the
DensityMatrix<complex,complex>::cal_DMR specialization into density_matrix.cpp,
so keeping both gave a duplicate definition at link time.
…ose HSolverLR timer

Two crashes found running the H2/TDHF/SZ gradient case:

1. PulayForceStress::cal_pulay_fs (the LR overload in pulay_force_hcontainer.h)
   passed the density matrix's spin count as `nspin` to ModuleGint::cal_gint_fvl
   while supplying a single potential channel. Gint_fvl::cal_fvl_svl_ indexes
   vr_eff_[is] for is<nspin, so with a two-channel DM (the test_force path feeds
   in the ground-state DM) it read past the vector and segfaulted inside the
   OpenMP region. The LR kernel produces one potential channel, so the grid
   integrals now run with nspin=1 on the leading DM channel -- exactly what the
   old `Gint_inout(is=0, ...)` calls did.

2. HSolverLR::solve started a timer that was never ended, so the second
   (triplet) call threw "timer::start HSolverLR::solve". Added the matching
   ModuleBase::timer::end on the common exit path.

Verified on H2 / TDHF / SZ (nspin=2, gamma-only):
  - SCF reproduces the pre-port reference bit-for-bit (E_KohnSham -2.3110142036 Ry,
    TOTAL-FORCE -14.7806682608 eV/Ang).
  - test_force cross-check: GS Hxc force via potential -28.4711400896 vs via the
    LR kernel -28.4711414920 eV/Ang (7 significant digits).
  - The reproduced EXX force (31.3817781891) is exactly 2x the SCF EXX force
    (15.6908890935), confirming ExxForceTwoDM replaces RI::LR correctly.
  - Excitations 22.484 eV (singlet) / 13.813 eV (triplet); excited-state
    gradients -0.6313 / -2.01497 eV/Ang, antisymmetric with ~1e-14 transverse
    components.
solve_Z_lapack built a replicated Hessian via HamiltLR::matrix() but handed
LAPACK the pX-distributed right-hand side `R` directly. lapack_linear_solver
then copies n_global*nstates entries out of a buffer that only holds
ld*nstates = nk*pX[0].get_local_size()*nstates -- an out-of-bounds read as soon
as the local size is smaller than the global one, and a segfault on any rank
whose local size is 0.

Gather R into a global buffer first, mirroring the scatter of Z_full that
already follows the solve. Serial results are bit-for-bit unchanged (verified
on H2/TDHF/SZ: excited-state gradients -0.631306 / -2.01497 eV/Ang, all
per-term forces identical to the pre-fix run).
`PotHxcLR::cal_v_eff` dominates an LR run: 74% of the total for 07_LiF/pbe
(949 s of 1289 s over 541 calls). Roughly half of that was FFT; the rest was
serial element-wise work and allocator traffic. Five changes, no algorithmic
change:

1. OpenMP on the element-wise loops. Everything these loops call
   (`grad_rho`, `grad_dot`, the Hartree kernel) was already parallel; the
   integrands here were the only part still running on one thread.

2. Raw pointers instead of `.at()` (43 sites). The bounds check is a branch
   per access, ~10 per grid point, and it blocks vectorization. The
   outer-vector lookups (`drho_gs.at(0)`) are hoisted out of the loops, where
   they keep their bounds check for free.

3. A scratch pool instead of per-call temporaries. `drho`, `gdot_terms` and
   `vxc_tmp` were allocated and value-initialized on every call and then
   overwritten before being read -- ~450 MB of pointless memset per call at a
   200^3 grid, plus the page faults. `grad_dot` assigns rather than
   accumulates, so even `vxc_tmp`'s zero-fill was dead. The pool is shared by
   all instances (a run holds three `PotHxcLR`) so it does not multiply.

4. `add_v_hartree` replaces `H_Hartree_pw::v_hartree`, which (a) re-did the
   forward FFT of rho^X that the GGA branch needs anyway -- 1 of the 10 FFTs
   per call was pure duplication, (b) reduced a Hartree "energy" of the
   transition density through `Parallel_Reduce::reduce_pool` every call, a
   collective nobody reads that also clobbers the global
   `H_Hartree_pw::hartree_energy`, and (c) returned a `matrix` by value, to
   which `v_eff += 2 * (...)` added a second full-size temporary.

5. The nspin=2 singlet/triplet combinations `v2rho2_uu -+ v2rho2_ud` and
   `2*vsigma_uu -+ vsigma_ud` are pre-contracted once per potential instead
   of being rebuilt at every grid point of every call, which also replaces
   two strided reads with one contiguous one. Costs 8-16 B/point, and only
   for closed-shell nspin=2.

`PotGradXCLR::cal_v_eff` (the g^xc branch feeding the Z-vector RHS) gets 1-3
of the same treatment, for -20% to -28%. The shared pool matters more there:
a `PotGradXCLR` is constructed inside the loop over excited states, so
per-object buffers would never be reused at all.

Measured (single node, 16 threads), analytic gradients unchanged:

  01_Si/lda    93 s -> 51 s   (-45%)   cal_v_eff  66 ->   45 ms/call
  01_Si/pbe   229 s -> 125 s  (-46%)   cal_v_eff 356 ->  268 ms/call
  02_Li2/lda  165 s -> 86 s   (-48%)   cal_v_eff 559 ->  278 ms/call
  02_Li2/pbe  530 s -> 253 s  (-52%)   cal_v_eff 2651 -> 1553 ms/call

(The total also benefits from solving the Z-vector equation once instead of
three times, a separate fix; the per-call figures above isolate this commit.)

Excitation energies are identical to every printed digit; the nspin=1 cases
agree to 1e-14, and of 60 force components per nspin=2 case, 2-3 differ by
exactly one unit in the last printed digit (the Hartree prefactor is now
associated differently).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QMV7xFZ69hhc3HnVBHbD96
Comment thread source/source_esolver/esolver_lr_cfg.cpp Outdated
@maki49
maki49 requested a review from mohanchen October 17, 2026 13:00
Comment thread source/source_estate/module_dm/unittests/test_cal_dm_r.cpp Outdated
@mohanchen

Copy link
Copy Markdown
Collaborator

487: [ RUN ] lr_tddft_hf_ulr_gamma
487: Info: Local MPI proc number: 4,OpenMP thread number: 1,Total thread number: 4,Local thread limit: 16
487: Signed LR force comparison passed: 27 components
487: [----------] LR-TDDFT HF on H2O, gamma_only, nspin=2, lr_unrestricted=1, lr_nstates=3, lr_solver=lapack.
487: [ OK ] totalforceref
487: [ OK ] CompareLRForce_pass
487: [ OK ] excitationenergyref1
487: [ OK ] excitationenergyref2
487: [ OK ] excitationenergyref3
487: [----------] Time elapsed: 28.671 seconds

487: [ RUN ] lr_relax_lda_beh2
487: Info: Local MPI proc number: 4,OpenMP thread number: 1,Total thread number: 4,Local thread limit: 16
487: Excited-state tracking check passed
487: [----------] Two-step LDA BeH2 degenerate-subspace average (2 -> 2). Checks dimensions, projection weight, singular values and finite energies/forces; requires LibXC KXC.
487: [ OK ] CompareStateTracking_pass
487: [----------] Time elapsed: 17.168 seconds

487: [ RUN ] lr_relax_lda_ch4
487: Info: Local MPI proc number: 4,OpenMP thread number: 1,Total thread number: 4,Local thread limit: 16
487: Excited-state tracking check passed
487: [----------] Two-step LDA CH4 JT mixed-state following after splitting (3 -> 1). Checks dimensions, projection weight, singular values and finite energies/forces; requires LibXC KXC.
487: [ OK ] CompareStateTracking_pass
487: [----------] Time elapsed: 52.800 seconds

487: [ RUN ] lr_tddft_hf_gamma
487: Info: Local MPI proc number: 4,OpenMP thread number: 1,Total thread number: 4,Local thread limit: 16
487: Signed LR force comparison passed: 36 components
487: [----------] LR-TDDFT HF on H2O, gamma_only, nspin=2, lr_nstates=2, lr_solver=dav.
487: [ OK ] totalforceref
487: [ OK ] CompareLRForce_pass
487: [ OK ] excitationenergyref1
487: [ OK ] excitationenergyref2
487: [ OK ] excitationenergyref3
487: [ OK ] excitationenergyref4
487: [----------] Time elapsed: 21.009 seconds

The example above takes a significant amount of testing time in CI/CD. Could you further reduce its testing time? If there are other examples where the testing time could also be reduced, that would be much appreciated as well.

@mohanchen

Copy link
Copy Markdown
Collaborator

I hope the above two will be the last two comments of this PR

@mohanchen

mohanchen commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Let me see if the bot have further comments.
@ABACUS-PR-BOT Could you provide any further comments?

@ABACUS-PR-BOT ABACUS-PR-BOT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed ac4bf0d7b2007160dcd4e5238493a58892e8d6b5 against 27bbd6cfa6ec40ef4c5699b0c46f2e7412b840b7 with independent static source/algebra reviews. New findings are inline; the signed-HSE issue remains in its existing discussion and is not repeated.

Existing governance blocker: the new-default-argument feedback remains unresolved. Ten new defaults across six existing interfaces (OperatorLRDiag, the three AO-to-MO functions, OperatorLRHxc, and OperatorLREXX) require explicit call-site updates or a maintainer-approved scoped exception under the governance matrix.

Non-blocking metadata: please use the registered names lr_degen_mode / nvirt in the PR description and add the exact validation commands and outcomes. Explain that YAML/Markdown INPUT references are build-generated from the updated Input_Item metadata; no generated files need to be committed.

Verification this round: trusted governance checker exit 0 (200 warnings, no mechanical errors); the manually verified default-argument rule above still applies. git diff --check failed with 32 trailing-whitespace diagnostics; all four changed Python files parsed. No builds, test suites, numerical/MPI jobs or CI verification were performed; CI diagnostics were unavailable. Full force accuracy and the recorded HSE/window/JT/occupation/parallel/BSE limitations remain unverified.

Comment thread source/source_esolver/esolver_lr_init.cpp Outdated
Comment thread source/source_esolver/esolver_lr_orb.cpp
Comment thread source/source_lcao/module_lr/utils/lr_util_hcontainer.h Outdated
Comment thread source/source_lcao/module_lr/utils/lr_util.cpp
Comment thread source/source_lcao/module_lr/zeq_cg.cpp
Comment thread source/source_lcao/module_lr/lr_grad_cs.cpp Outdated
Comment thread source/source_lcao/module_lr/potentials/pot_lr_base.h Outdated
Comment thread source/source_lcao/module_ri/unittests/test_exx_workspace.cpp
Comment thread source/source_lcao/module_lr/hamilt_zequlr.h Outdated
Comment thread source/source_lcao/module_lr/utils/lr_util_hcontainer.h Outdated
Prepare unrestricted Z dimensions at the call site, align the EXX workspace test name, and pass former default arguments explicitly throughout LR/BSE. Document parameter roles and reject external kernels/densities and fixed electric fields for LR forces or relaxation in INPUT metadata and validation.
Declare each force matrix on its own line without changing initialization. GNU/MPI main-program build, no-MPI LR module build and both focused Z-solver CTests pass. No behavior or INPUT changes; no new tests or generated documentation are needed for this declaration-only cleanup.
@maki49

maki49 commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

Existing governance blocker: the new-default-argument feedback remains unresolved. Ten new defaults across six existing interfaces (OperatorLRDiag, the three AO-to-MO functions, OperatorLRHxc, and OperatorLREXX) require explicit call-site updates or a maintainer-approved scoped exception under the governance matrix.

Fixed in 7b9c4eb. Removed all ten newly added default arguments from the six existing interfaces, together with preceding defaults where required by C++ parameter ordering. All call sites now pass the values explicitly, including LR/BSE and serial/MPI AO-to-MO tests. Added concise comments for scaling, accumulation, contraction selection, benchmark probe indices and operator type. The explicit values preserve the previous numerical behavior; no replacement defaulted overloads were introduced.

The comma declarations are also fixed in 2e13b88.

Keep save_HR/save_DMR as declaration-only adapters and put their common-writer
calls in lr_sparse.cpp. Synchronize structural R coordinates before conversion,
use explicit spin suffixes, and keep the LR gradient call site high-level.
Diagnostic headers follow the common CSR format; force formulas are unchanged.

Wire the new implementation through CMake and GNU Makefile. Pyabacus has no
independent LR source list. Move the disjoint-R regression into the LR DM test
and exercise both wrapper layers with two spin channels, a zero rank and a
globally zero R block. Common IO tests retain no dependency on LR.

GNU/MPI main build and serial LR build pass. Serial and four-rank wrapper tests
pass; actual one/four-rank LDA test_force CSR files are byte-identical to the
pre-wrapper version. Unit-test global references decrease by three; the retained
DRANK assignment adapts the common writer's existing output-rank interface.
Temporarily select the resolved GS functional while Potential initializes its cached Hxc values, then restore all incoming XC selection and runtime settings with an exception-safe scoped adapter. Potential, PotXC and XC evaluation still use process-wide state; removing that dependency requires a separate three-layer refactor. Handle HF's empty functional-ID list safely.

Four focused scope tests cover restoration, exception unwinding, nesting and LibXC backend selection. MPI and no-MPI builds/tests pass. HF GS reconstruction is invariant under RPA/LDA/PBE LR kernel selection (previous deviations 3.35/3.48 eV/Angstrom); one/four-rank probes use bz=1 to avoid an independent empty-grid diagnostic limitation. All six existing LR cases pass at one and four ranks with unchanged references.
Adapt the response-density screening fix from GPU branch commit
e82898e. Retain density blocks in
Casida/Z exchange and both sides of the LR exchange-force contractions;
leave the ground-state SCF threshold unchanged and document its scope.

Always evaluate the true residual of the returned CG vector, including
zero/small RHS exits. Preserve the normal iteration sequence and the
existing 1e-6 absolute tolerance. Add false-convergence and zero-RHS
operator checks, also exercised on four MPI ranks.

Update only the two HF force baselines after checking operator linearity,
CG versus LU, MPI agreement, and full-window H2 finite differences.
Excitation-energy and LDA/PBE references are unchanged. Temporary operator
probes and extra-precision FD output are excluded from this commit.

Validation: GNU/MPI executable build; no-MPI/no-ELPA lr/esolver builds;
four focused CTests pass; six original LR cases pass on one/four ranks.
Full-window H2 force FD relative errors are below 3e-7 at 0.001 Angstrom.
Add abs_gauge=none for LR-TDDFT and BSE while preserving excitation-energy checks, charge output, forces and relaxation. Initialize required projector metadata independently of the optical gauge. Test the energy collector, including stale optical files.

Use coarser tracking-regression inputs and a direct solver for the small unrestricted HF Z equation. Keep the closed-shell HF CG coverage and all existing references and tolerances.

Validation: GNU MPI executable and INPUT test builds passed; serial no-MPI/no-ELPA lr and esolver module builds passed. Eight integration cases passed with one and four MPI ranks. BSE TDA/full none-versus-velocity energies, standalone LR, INPUT/collector tests, CLI checks and generated parameter documentation passed.

Governance: moved BSE rank guards retain the existing global dependency count. The print helper includes provide its inline numerical output. INPUT documentation is generated from the updated metadata.
@maki49

maki49 commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator Author

The example above takes a significant amount of testing time in CI/CD. Could you further reduce its testing time? If there are other examples where the testing time could also be reduced, that would be much appreciated as well.

@mohanchen Fixed in 05e814650. I reduced the cost of the four regression cases by:

  • Use ecutwfc=5 Ry and scf_thr=1e-6 for the two relaxation cases. They test state tracking rather than physical convergence and still retain two ionic steps and the original BeH2 2→2 / CH4 JT 3→1 checks.
  • Add a new option none to the parameter abs_gauge to skip optical postprocessing while retaining excitation-energy checks and forces, and apply to all four cases, where the spectra are not checked.
  • The small unrestricted HF Z equation uses direct LU (lapack); the closed-shell HF case retains CG coverage.

A local comparison using four MPI ranks, one thread per rank, and identical CPU pinning gives the following wall-clock medians of two runs per configuration, including MPI startup, using the same executable:

Case Original inputs Updated inputs Reduction
lr_relax_lda_beh2 9.47 s 1.47 s 84.5%
lr_relax_lda_ch4 31.56 s 5.26 s 83.3%
lr_tddft_hf_gamma 10.35 s 9.84 s 4.9%
lr_tddft_hf_ulr_gamma 14.36 s 9.89 s 31.1%

The sum of these medians decreased from 65.73 to 26.46 s (59.7%). These are local measurements rather than predicted CI timings; the closed-shell HF improvement is small. EXX thresholds, numerical references, and comparison tolerances are unchanged. Other LR cases continue to exercise the optical paths.

Include parallel_reduce.h directly for the collective used by the empty-block regression, fixing the undeclared Parallel_Reduce error in CUDA CI builds. No user-facing behavior or documentation changes.

Validation: MODULE_LR_zeqlin_solv built with GNU/MPI; ctest -R ^MODULE_LR_zeqlin_(solv|failure_mpi)$ passed both tests, including the four-rank regression. Full CUDA build was not tested locally because nvcc is unavailable.
@maki49
maki49 requested a review from mohanchen October 18, 2026 09:31
@mohanchen

Copy link
Copy Markdown
Collaborator

There are some further places that can be improved. However, since the PR is already large. I will accept it in its current form. Please keep in mind that further refactors are still needed, I do hope that you can help in future @maki49

@mohanchen mohanchen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM now.

@mohanchen
mohanchen merged commit ecfaf94 into deepmodeling:develop Oct 18, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

EXX/lr-TDDFT/RPA/BSE/GW Related to beyond DFT methods Features Needed The features are indeed needed, and developers should have sophisticated knowledge Refactor Refactor ABACUS codes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants