Skip to content

feat(lcao): add optional LibRI GPU contractions through DDLA - #8169

Draft
Stardust0831 wants to merge 12 commits into
deepmodeling:developfrom
Stardust0831:experiment/lcao-hse-gpu
Draft

Stardust0831 wants to merge 12 commits into
deepmodeling:developfrom
Stardust0831:experiment/lcao-hse-gpu

Conversation

@Stardust0831

@Stardust0831 Stardust0831 commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

What's changed?

Add ENABLE_LIBRI_GPU (default OFF) and INPUT exx_device (default cpu) for optional LCAO exact-exchange contractions through LibRI's DDLA CUDA backend. With GPU RI compiled in, set device gpu and exx_device gpu to use it. Omitting exx_device or setting it to cpu retains CPU RI and GPU solvers in the same executable.

  • Provide LibRI::LibRI and DDLA::DDLA imported targets with transitive dependencies and compile/link checks for real and complex GPU contractions. Make the base MKL target importable by these checks.
  • Select the backend before EXX initialization through the existing input parser, metadata registry and MPI broadcast. Reject unsupported build/device combinations and GPU RI with real-space EXX symmetry reduction (symmetry=1 and exx_symmetry_realspace=true). With symmetry=1, use CPU RI or set exx_symmetry_realspace=0.
  • Document the LCAO Kohn-Sham scope of exx_device and the shared GPU visibility required by the pinned LibRI backend. Independent LR/RDMFT exchange objects retain CPU mode; LR inherits the selected backend only when it reuses the Kohn-Sham object.
  • Add opt-in numerical CTest coverage for signed accumulation in all 18 LibRI contraction branches, using real and complex data and nonempty outputs.
  • Keep the default CPU dependency download unchanged. Document installation and runtime selection in docs/advanced/install.md.

GPU mode requires LibRI 6ce3c84 with tests/lcao_hse_gpu/libri-compat.patch and a CUDA build of DDLA v0.0.4 (9c404ac), located through DDLA_ROOT or CMAKE_PREFIX_PATH. The patch fixes API mismatches and output accumulation needed for correct forces and stress.

Unit Tests and/or Case Tests for my changes

Validation used SAI V100 GPUs and OMP_NUM_THREADS=1.

Revision Check Result
63ca5ef07 CPU/GPU dependency consumers; optional numerical GPU test Passed; real and complex signed accumulation across all 18 contraction branches, starting with nonempty outputs. Restoring the old download destination causes the expected failure.
63ca5ef07 Optional-test configuration Passed; GPU numerical tests are off by default and rejected without GPU RI.
63ca5ef07 Incremental GPU build; CPU/GPU input unit tests; CLI help and metadata Passed; all other production source files were verified unchanged before build reuse.
63ca5ef07 One-GPU HSE Gamma and two-GPU complex multi-k; --check-input All eight solver/RI combinations passed against unchanged references; both valid selections and three invalid-input diagnostics passed.
f07d8d14f Full GPU build; input unit tests with and without GPU RI Passed; all eight input tests passed in each configuration.
f07d8d14f HSE Gamma, complex multi-k, spin-polarized Gamma and symmetry-enabled multi-k All 17 solver/RI combinations passed against unchanged references.
f07d8d14f Complex multi-k with two MPI ranks and two GPUs All four solver/RI combinations passed.
f07d8d14f --version, -h exx_device, generated parameter metadata and --check-input Passed; both valid selections and three invalid-input diagnostics checked.
d8d32046f Full CPU/GPU builds and CMake dependency consumers Passed, including seven CPU/GPU and static/shared MKL consumer configurations; CPU executable has no DDLA/CUDA dependency.
d8d32046f Missing prerequisites and incompatible LibRI Four configurations correctly disable GPU RI; unpatched LibRI is rejected.
Verification commands

For the full GPU build and input-test builds (the incremental rebuild used --parallel 8):

cmake --build "$BUILD_DIR" --target abacus_std_gpu --parallel 32
cmake --build "$BUILD_DIR" --target MODULE_IO_read_item_serial --parallel 32
ctest --test-dir "$BUILD_DIR" --output-on-failure -R '^MODULE_IO_read_item_serial$'
"$ABACUS_BIN" --version
"$ABACUS_BIN" --info
"$ABACUS_BIN" -h exx_device
"$ABACUS_BIN" --generate-parameters-yaml
"$ABACUS_BIN" --check-input

From copies of tests/08_RI, using the existing references:

bash ../integrate/Autotest.sh -a "$ABACUS_BIN" -n 1 -o 1 -f CASES.task.txt
bash ../integrate/Autotest.sh -a "$ABACUS_BIN" -n 2 -o 1 -f CASES.task.txt

Variants cover device cpu, device gpu with the default EXX backend, and explicit exx_device cpu|gpu. Solver selections are scalapack_gvx and cusolver, respectively. Symmetry cases exercise CPU RI with real-space symmetry enabled and CPU/GPU RI with it disabled. Gamma and symmetry cases check energy, forces and stress; complex multi-k checks energy. The two-rank run uses the complex multi-k case.

Standalone dependency checks use the following command. Add -DENABLE_LIBRI_GPU_TESTS=ON to enable the numerical test, which requires one GPU and MPI. The default consumer test needs no GPU hardware.

cmake -S tests/lcao_hse_gpu/cmake -B build-consumer \
  -DLIBRI_DIR="$LIBRI_PREFIX" -DLIBCOMM_DIR="$LIBCOMM_PREFIX" \
  -Dcereal_DIR="$CEREAL_CONFIG" \
  -DENABLE_LIBRI_GPU=ON -DDDLA_ROOT="$DDLA_PREFIX"
cmake --build build-consumer --parallel 2
ctest --test-dir build-consumer --output-on-failure

The numerical regression was run with OMP_NUM_THREADS=1 and ctest --test-dir build-consumer -V -R '^libri_gpu_accumulation$'. Its CPU reference and GPU result are checked after each factor in -1, +1, +1, -1. The negative control keeps the API fixes but restores the 18 original download destinations; the same test must then fail with an accumulation mismatch.

CPU variants disable GPU RI and DDLA discovery. MKL variants additionally set MKL_ROOT, MKL_MPI=openmpi, and MKL_LINK=static or dynamic.

The GPU regression build uses ENABLE_NCCL_PARALLEL_DEVICE=OFF: the input-test target had unresolved NCCL symbols with it enabled. NCCL runtime behavior was not verified. GPU memory use increases, and prior single-node multi-GPU tests reduce per-GPU usage without establishing ideal memory scaling. Initialization remains largely on CPU. A Si32 comparison needed explicit scf_ene_thr=1e-8 for consistent outer-loop stopping. Default-threshold convergence, full MKL application builds, multi-node execution, SOC and long MD runs need further validation; the backend remains experimental.

Follow-up

Add DDLA installation to the existing toolchain/scripts/ workflow, including pinned versions, checksums, CUDA builds and support for existing installations.

Linked Issue

No linked issue; this adds optional support for an existing LibRI backend.

Governance Notes

  • INPUT/docs: add exx_device=cpu|gpu, default cpu, with help metadata, installation documentation and focused input tests. Generated parameter documentation is not committed.
  • Core impact: pass EXX device selection into LCAO initialization without adding global dependencies or changing ABACUS contraction kernels. GPU RI requires C++17; CPU RI retains C++14.
  • The standalone LibRI numerical test initializes and finalizes MPI directly because it links only the dependency target; communicator queries use the LibRI wrapper. ABACUS runtime code is unchanged by this test.
  • Changed-line formatting, LF, whitespace and PR-diff governance checks pass.
Contribution checklist
  • I have read AGENTS.md and docs/developers_guide/agent_governance.md.
  • I have linked an issue or explained why this PR does not need one.
  • I have added adequate unit tests and/or case tests, or explained why not.
  • I have listed the exact verification commands run and their results.
  • I have described user-visible behavior changes, including INPUT parameter changes.
  • I have explained core-module impact for ESolver, HSolver, ElecState, Hamilt, Operator, Psi, or other source/ changes.
  • I have requested any needed governance exception below.

@userchba

Copy link
Copy Markdown

the LibDDLA version which is compatible with LibRI GPU is https://github.com/userchba/LibDDLA/releases/tag/v0.0.4, current LibRI GPU can't correctly compute symmetry situation which LibRI CPU can compute correctly

@mohanchen mohanchen added the GPU & DCU & HPC GPU and DCU and HPC related any issues label Oct 18, 2026

@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.

Static review of f07d8d14f39d26782490cc4bc15d0a58c5700e62 with independent source review and adjudication. No build/runtime/MPI/GPU tests were run; CI diagnostics were unavailable.

Comment thread docs/advanced/install.md
(default OFF), `USE_CUDA=ON`, and a CUDA build of DDLA. Like other dependent
options, GPU RI is disabled when its LibRI/CUDA prerequisites are disabled.
INPUT `exx_device` defaults to `cpu`, retaining CPU contractions even with
`device gpu`. To use GPU contractions, set both `device gpu` and `exx_device gpu`.

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.

[P2] State the GPU visibility requirement for MPI runs

For two ranks on one node, exposing one different GPU per rank through CUDA_VISIBLE_DEVICES passes ABACUS device setup but makes the pinned LibRI validate_local_gpu_count() throw at the first GPU contraction (local_size=2 > device_count=1). This backend therefore requires each process to see at least as many GPUs as there are node-local ranks, a constraint missing here. Please document it with a compatible launch layout, or extend the compatibility patch to respect the existing per-rank binding.

Exx_Info& exx_info)
{
#ifdef __EXX
const bool use_gpu = inp.exx_device == "gpu";

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.

Non-blocking: Please clarify the selector's scope for independent LR/RDMFT exchange engines. Standalone LR, fresh LR-kernel setup after KS, and RDMFT construct their own Exx_LRI objects, which retain CPU mode despite accepted exx_device=gpu; matching-kernel KS pointer reuse retains GPU mode. If those engines are in scope, pass the selection to them; otherwise document or reject the unsupported combinations. A follow-up after merge is fine for these additional workflows.

{
return 1;
}
lri.cal_mode = RI::LRI_Cal_Mode::GPU;

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.

Non-blocking: Consider an opt-in numerical regression for the patch's signed accumulation in a follow-up after merge. This consumer switches cal_mode but then executes only CPU nrm2, and the configure probe only compiles/links. Alongside the reported force/stress runs, a tiny real/complex CPU-versus-GPU case with nonempty output and repeated +1/-1 contractions would preserve the specific accumulation fix across dependency updates.

This branch has not been deployed

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

Labels

GPU & DCU & HPC GPU and DCU and HPC related any issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants