Skip to content

feat(xc): add libvdwxc-backed rVV10 nonlocal XC - #8140

Draft
CleverPhysician wants to merge 18 commits into
deepmodeling:developfrom
CleverPhysician:rvv10-latest-clean
Draft

CleverPhysician wants to merge 18 commits into
deepmodeling:developfrom
CleverPhysician:rvv10-latest-clean

Conversation

@CleverPhysician

@CleverPhysician CleverPhysician commented Oct 13, 2026 •

Copy link
Copy Markdown

Reminder

  • Read AGENTS.md and docs/developers_guide/agent_governance.md.
  • Explained the issue/proposal context below.
  • Added focused numerical and build-report tests.
  • Listed verification and checks not run.
  • Described INPUT changes and core-module impact.
  • Requested maintainer agreement on the staged scope.

Linked Issue

No linked issue. This replaces the implementation approach in closed #8031 with
a generic additive nonlocal-XC component and a thin libvdwxc adapter. It remains
Draft while the external API and first-PR scope are reviewed.

What's changed?

dft_functional remains the semilocal functional. xc_nonlocal rvv10 adds a
separate correction after the existing PotXC; the first parameterization uses
GGA_X_RPW86+GGA_C_PBE, rvv10_b 6.3, and rvv10_c 0.0093.

The adapter reuses PW_Basis, XC_Functional::grad_rho, grad_dot, charge
layouts and XC bookkeeping. The numerical backend lives in module_vdw; there
is no second ABACUS rVV10 kernel and no rVV10-specific branch in the generic SCF
loop. It passes total density to the library, converts its derivatives from Ha
to Ry, and contracts the resulting potential with valence density for vtxc.
The library already includes the beta compensation.

Supported scope: CPU/double, full-complex PW, one process, nspin=1, single
density grid, right-handed cell, norm-conserving pseudopotentials, SCF energy
and potential. Other modes fail explicitly; MPI, ordinary spin, GPU/LCAO,
gamma-only, USPP/PAW, forces/stress and additional parameterizations are not
implemented by this PR.

The latest revision removes manual CMake target/header/API probes, uses the
exported libvdwxc::vdwxc target, adopts standard WARNING_QUIT diagnostics,
removes the redundant developer page and replaces eight source-text assertions
with one executable Makefile build-report test. Python is not a new mandatory
dependency of ordinary BUILD_TESTING configurations.
The ownership follow-up explicitly prohibits copying the adapter's owned
library handle. A focused host test now exercises real charge/cell storage and
checks that the correction is added without replacing existing XC values.

Unit Tests and/or Case Tests for my changes

Current verified head: be61717cd373468c94e919096ebe9fe3e0e71eff, merging
develop at a2b8bc30f3f5288bbef9a01fa2d5f188269cf2af. The only manual merge
resolution retains the upstream mapped-density comment beside all rVV10 INPUT
fields; both parents' additions/deletions are preserved. No adapter algorithm
change was made. Its exact source tree 1b801998eb5dc8b3eb8f1a2521fbb32766d864eb
was archived, built and tested before creating the merge commit.

The complete serial PW executable, both C++ test targets, all three
LIBVDWXC CTests and a fresh Si SCF now pass with the fixed standalone-FFTW
libvdwxc revision 94410ebdf3dc9615a40f40c3a5b59dbe20a433d2. This remains the
unreleased Draft MR !32, not a released rVV10 API. The earlier complete
build used its parent 91ef4820...; those old results are not used as evidence
for this new dependency build.

Current toolchain: GCC 11.5.0, CMake 3.26.5, Libxc 6.2.2, OpenBLAS 0.3.34,
standalone FFTW 3.3.11, CPU/serial/OpenMP-off. CMake's testing configuration
selects C++14. Actual runtime DSO paths and hashes match the selected library;
there is no MKL FFT provider in the process. The binary SHA256 is
620fbe9d54ec15896ddc163c4aac87626bdfbc91bff14b0b90b485af87e2aec5.
The archive build reports Git Commit N/A; its external tree identity is recorded,
not inferred from that version string.

Executed in intern004 Slurm jobs 556238 (build/tests) and 556243 (SCF):

cd /data/home/intern004/projects/rvv10-abacus-20260911/validation/abacus-libvdwxc944-full-20261015-KdlDXr
dep=/data/home/intern004/projects/rvv10-abacus-20260911/validation/libvdwxc-fix-20261015-KY3Ff0
fftw=/data/home/intern004/miniforge3/pkgs/fftw-3.3.11-nompi_h3b011a4_100
blas=/data/home/intern004/miniforge3/pkgs/libopenblas-0.3.34-pthreads_hf13c14d_2/lib/libopenblasp-r0.3.34.so
unset MKLROOT MKL_ROOT
export OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 MKL_NUM_THREADS=1
export LD_LIBRARY_PATH="$dep/install-fftw/lib64:$PWD/deps/libxc/lib64:$fftw/lib:/data/home/intern004/miniforge3/pkgs/libopenblas-0.3.34-pthreads_hf13c14d_2/lib"
cmake -S source -B build \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DCMAKE_BUILD_TYPE=Release \
  -DENABLE_MPI=OFF -DENABLE_OPENMP=OFF -DENABLE_LCAO=OFF \
  -DENABLE_LIBXC=ON -DENABLE_LIBVDWXC=ON -DBUILD_TESTING=ON \
  -DUSE_CUDA=OFF -DUSE_ROCM=OFF -DENABLE_FLOAT_FFTW=OFF \
  -DENABLE_NATIVE_OPTIMIZATION=OFF -DGIT_SUBMODULE=OFF -DCOMMIT_INFO=OFF \
  -DFETCHCONTENT_SOURCE_DIR_GOOGLETEST="$PWD/deps/googletest" \
  -DFETCHCONTENT_FULLY_DISCONNECTED=ON -DBLA_VENDOR=OpenBLAS \
  -DBLAS_LIBRARY="$blas" -DLAPACK_LIBRARY="$blas" -DFFTW3_DIR="$fftw" \
  -DBLAS_openblas_LIBRARY="$blas" -DLAPACK_openblas_LIBRARY="$blas" \
  -DLibxc_DIR="$PWD/deps/libxc/lib64/cmake/Libxc" \
  -Dlibvdwxc_DIR="$dep/install-fftw/lib64/cmake/libvdwxc"
cmake --build build --target abacus_pw_ser MODULE_HAMILT_vdwTest_LIBVDWXC MODULE_ESTATE_pot_nonlocal_xc_LIBVDWXC --parallel 4
ctest --test-dir build -R LIBVDWXC --output-on-failure --no-tests=error
./build/abacus_pw_ser --version
./build/abacus_pw_ser --info
./build/abacus_pw_ser -h xc_nonlocal
# New shared Si case: original scientific settings, only pseudo_dir relocated.
(cd si && ../build/abacus_pw_ser --check-input)
(cd si && ../build/abacus_pw_ser)
  • Full PW executable build passed. CTest: 3/3, comprising seven C++ adapter
    cases, one real host case, and the Makefile build-report test.
  • Fresh 944 Si SCF converged in seven iterations: density residual
    6.95559e-7 < scf_thr=1e-6, total energy -208.0135469216236 eV.
    The log records eight PotNonlocalXC::cal_v_eff calls. Actual DSO hashing,
    explicit convergence/final-energy markers, finite residuals, CLI success and
    seven normal/seven Python--O verifier tests passed. No new energy tolerance
    relative to the old run was introduced. No additional QE run was required.
  • Numerical coverage includes nonuniform density/API accounting, a
    finite-difference energy/potential check and independent reciprocal geometry
    for equivalent oblique/orthogonal cells. Reintroducing the wrong cell
    transpose makes the geometry test fail (1.22e-4 Ry energy discrepancy);
    restoring the correct mapping passes.
  • The ownership test fails before deleting copy construction/assignment and
    passes afterward. The host test checks valence-plus-core input, preservation
    of prior nonzero energy/potential, valence-only vtxc and unchanged input
    arrays. Deliberately omitting core density makes it fail (3.33e-5 Ry energy
    discrepancy); replacing additive updates with assignment also fails.
    All mutation copies were restored before final tests and builds.
  • Standard error tests cover left-handed cells, invalid parameters, wrong
    density length and nonfinite density.
  • Earlier c3dedfb/parent-dependency coverage: two-atom Si SCF converged in seven iterations with
    E_total = -208.0135469216242 eV and E_xc = -4.2517234318 Ry.
    The matching xc_nonlocal none case also converged. Both passed
    --check-input; double-grid and nspin=2 negative cases exited with code 1
    at the intended parser diagnostic. The pseudopotential is the repository's
    source/source_estate/test/support/Si_ONCV_PBE-1.0.upf, ecutwfc=20 Ry,
    Gamma k-point and scf_thr=1e-6.
  • A separate ENABLE_LIBVDWXC=OFF, BUILD_TESTING=ON,
    CMAKE_DISABLE_FIND_PACKAGE_Python3=ON configuration and nonlocal_xc
    target build passed. This is a default-path smoke check, not a second full
    executable build.

Local checks:

python3 -m unittest discover -s tests/rvv10 -p 'test_*.py'
python3 docs/generate_input_main.py /tmp/rvv10-final-parameters-oct14.yaml
python3 tools/03_code_analysis/agent_governance_check.py --base origin/develop --head HEAD --format text
git diff --check origin/develop...HEAD

Results: Python 1/1; INPUT reference generated from the new executable's
metadata; no whitespace errors; governance has no blocking findings (only
header-dependency review warnings). Generated INPUT documents remain untracked
following the latest upstream documentation change.

Dependency follow-up: after Growl's FFT-boundary fix, revision 94410eb...
passes 8/8 CTests with standalone FFTW and 8/8 with MKL
2022.2.1/lp64/sequential/dynamic (GCC 11.2.1). Both include fft.weights
and rvv10.serial. The seven ABACUS adapter cases and one real host case
also pass with the new standalone-FFTW library. These runs used Slurm job
555743 on intern004's test001; FFT providers were kept separate.
The earlier 69 failing comparisons describe the retained parent-revision
MKL result, not the updated dependency. This is not an MKL ABACUS validation.

Independent fixed-QE comparison now reads the unchanged saved density and
original QE output (QE b3af0d0e810a611c455fd80fca6ee523dfaaee95). Seven
cases use an 8x10x12 grid and a 10x12.5x15 Bohr cell, comparing energy,
valence vtxc, all 960 potential values and nine directional steps per case.
The maximum energy difference is 3.50e-13 Ry; the current-adapter
energy/potential directional residual is at most 1.25e-10 Ry at h=1e-4
after normalization by the direction's integrated absolute value.

Pointwise potential equivalence is not established: the ordinary
valence/core case differs by 2.49e-6 Ry; low-q and small-gradient cases
differ by up to 7.71e-2 Ry. Original QE retains derivatives after qmin
clipping and zeros the sigma derivative at sigma<=1e-12, whereas the library
uses the derivative of its clipped/analytic energy. Their own-energy and
QE-energy directional checks are reported separately. Also, 245 host PW
modes describe the gradient/divergence cutoff, not identical convolution
cutoffs: QE uses its spherical PW set; libvdwxc uses the full FFT grid.
Both dependency revisions produced byte-identical output for these orthogonal
fixtures. No reference output was modified and no global pass verdict is assigned.

Material follow-up on the unchanged implementation (Slurm 555799): full archived
20/30/40 Bohr graphene densities give energy differences of 1.22e-15,
4.16e-16 and -5.45e-15 Ry relative to the original QE output. Raw pointwise
potential differences remain 1.499/1.603/0.657 Ry; density-weighted RMS is
0.00771/0.00631/0.00759 Ry. Most of this survives projection onto the exact
host PW set, so the reference's out-of-PW divergence terms are not a sufficient
explanation. All 27 input hashes were checked; the negative tail sample is retained.

Eight retained/excluded/Nyquist direction cases have candidate-self residuals
at most 5.80e-12 Ry at h=1e-4 (L1 normalized). The actual explicit-grid cutoff
is recorded; a 20 Ry request in the small oblique cell is clamped to 3.553 Ry.
Real-material self differences (Slurm 555816) separately use whole, fixed dense,
and fixed positive-tail directions, retaining all five steps. At h=1e-4, whole
and dense residuals are at most 7.37e-12 and 8.87e-10 Ry. Tail directions have
small L1 and develop small-step cancellation noise; all raw residuals remain
reported, with no overall accuracy verdict or tolerance relaxation. Independent
reconstruction confirms their baseline potential contractions and direction norms.
These are candidate-self derivatives, not original-QE energy derivatives.

Original-QE material energy differences have now been computed for all 45 prescribed
perturbations without modifying its numerical module (Slurm 555845). The first
40 Bohr baseline reproduces energy, vtxc and every potential value exactly; tiny
20/30 Bohr baseline drifts remain recorded and fail the unchanged exact-baseline
check. Only the first 40 Bohr case is admitted to the strict partial comparison.
Its perturbed energies differ by at most 6.62e-15 Ry; at h=1e-4, QE-energy versus
candidate-potential residuals are 7.65e-12 Ry for the whole-density direction and
8.98e-10 Ry for the dense direction (L1 normalized). Original-QE self residuals
are 4.20e-8 and 4.48e-7 Ry respectively; its positive-tail self residual remains
about 0.004469 Ry over all five steps. All steps and both potentials are retained;
this supports these tested derivatives, not general pointwise equivalence.
Repeat/allocation controls (Slurm 555852) also show small potential changes from
the same QE executable, up to 2.18e-9 Ry relative to its first 40 Bohr baseline,
with energy-FD variation at most 3.82e-13 Ry. This does not establish FFT planning
as the cause or justify changing the exact-baseline criterion. Twelve focused
analysis tests pass normally and with Python -O. The subsequent single-branch diagnostic is described below; no production
change or global numerical pass is claimed.

Separately named diagnostic-only QE modules isolate two numerical conventions,
without changing the saved original reference or the adapter. B restores only
the small-sigma gradient derivative: compiled scalar probes first reproduce
the original discrepancy, then ten witnesses agree with independent
80/100-digit Decimal differences while density/zero-gradient/high-sigma
controls stay unchanged. The original kernel, energy, q0 and beta are retained.

A B observer streams the actual three H fields. Independent full-FFT
reconstruction reproduces that run within 3.33e-16 Ry and identifies the
unmodified out-of-PW H coefficients in its divergence buffer. This observer
differs from the first B baseline by up to 2.21e-8 Ry; both remain separate,
with no selection, reference replacement or asserted cause for this drift.
The existing QE fftx_oned2threed helper was subsequently tested through the
real FFT path: the original mixed/outside/Nyquist cases fail the predeclared
analytic check, while independent save/clear/refill passes all five cases.
Clear-without-refill and wrong-index mutants fail; all 245 saved coefficients
are retained exactly and all 715 excluded entries become zero.

Full C-only and B+C modules have now actually run once each on the archived
40 Bohr density (Slurm 556049, 110592 points, requested/actual 160 Ry,
25709 host G, serial/non-Gamma). C-only adds only independent h_g storage
and the existing clear/refill helper after fwfft; its q0/sigma branch stays
original. B+C derives separately from B. Complete inverse source patches
restore their respective parents; iG, signs, inverse FFTs, kernel and energy
bodies are unchanged. C minus original is confined to out-of-PW coefficients
(PW-inside maximum 5.14e-17 Ry), but C versus adapter still differs by
0.656 Ry. B+C versus the current adapter has raw full-grid maximum
1.87e-8 Ry, density-weighted RMS 2.69e-11 Ry, energy difference
5.45e-15 Ry and vtxc difference -8.47e-16 Ry, without offset fitting.
B+C versus first B has a 2.05e-8 Ry PW-inside cross-run difference; B+C
versus the earlier H-based algebraic prediction differs by 2.70e-8 Ry raw,
reported descriptively rather than forced to zero.

All fifteen saved original-QE and candidate E+/E- steps are retained.
At h=1e-4, original-QE energy differences versus B+C potential contractions
have whole/dense normalized residuals 7.65e-12/8.98e-10 Ry; all five
positive-tail residuals remain reported (6.59e-8 to 8.18e-7 Ry with small-L1
cancellation noise). These are not newly computed C/B+C self energy
differences. Seven new analysis tests pass normally and with Python -O;
an independent raw-array/reciprocal-cell/component-FFT crosscheck confirms
all fifteen records and the unshifted full-grid statistics.
This single-density diagnostic supports the two-convention explanation;
it is not an unmodified-QE pointwise pass, a resolution of every low-q case,
or a global accuracy verdict. Those diagnostics did not change the adapter.

The uniform lower-q witness is now checked independently. For saved case 2,
all 960 points and all 18 perturbed endpoints stay inside the q floor, with
zero gradient. Thus theta is proportional to n^(3/4) at fixed qmin and the
fixed-kernel energy has E=betaN+AVn^(3/2), giving
v=beta+1.5
(E-beta*N)/N. Using each source's own energy, the candidate's
full-grid potential differs from this relation by 2.43e-16 Ry maximum;
the saved original-QE potential differs by 1.90e-4 Ry. All nine saved
energy-difference steps, original potentials and accumulated norms remain
separate; the uniform G0 case does not test the differing convolution cutoffs.

A further diagnostic-only A probe changes only dq0_dq to zero inside the
original q0<qmin branch, without B/C changes or removal of the weight
derivative. Archived actual-original scalar output first fails the new
80/100-digit clamped-scalar central-difference check (Slurm 556090).
Only afterward was A derived and compiled; Slurm 556093 evaluates ten
scalar witnesses once: floor_zero dq/dn changes from 1.861687e5 to zero,
all ten q0/chi values and the other nine density derivatives remain
bitwise unchanged. Thirteen focused analysis tests pass normally and with
Python -O, with independent raw-index/Decimal crosschecks. The main
diagnostic API stays private; the separately exposed probe has the same
q0 routine body. No original QE rerun, new E+/E-, full A energy/potential,
nonzero-gradient floor-chi, unclamped UEG cancellation, or global numerical
pass is claimed. Original references and production sources remain unchanged.

Checks not run: independent SCF reference comparisons;
MPI/spin/force/stress validation; the complete local default test suite.
The former 95528a1... head had successful hosted checks, but that result does
not certify the new merge. At 2026-10-15 02:12:38 UTC, head be61717... is Draft
and conflict-free; its CI/doc builds are running (one check successful, twelve
in progress, two queued; both doc statuses pending). Default upstream CI does
not build the optional unreleased libvdwxc backend. The complete backend build
and SCF evidence above is separate from hosted CI.

Governance Notes

  • Header warnings: the base-class headers are needed for inheritance; standard
    headers declare the stored unique_ptr, vector, array and string types.
    The concrete adapter needs libvdwxc's vdwxc_data declaration; its documented
    complex.h pre-include avoids C-linkage parsing problems. The host still
    forward-declares the numerical backend rather than including its C API.
  • INPUT/docs: added xc_nonlocal, rvv10_b, rvv10_c metadata, installation
    instructions and VV10/rVV10 citations. xc_nonlocal none preserves existing
    behavior. Pairwise D2/D3/D4 combinations are rejected.
  • The latest ownership/test-only changes do not change INPUT or numerical
    behavior; no additional user-facing documentation is needed. The test README
    includes the new host target and what it checks.
  • Core impact: Potential receives the selection explicitly and registers the
    additive component after semilocal XC. Its numerical work stays behind the
    module_vdw interface; existing solvers, operators and DFT-D code are not
    replaced.
  • Scope decision requested: is this CPU/serial/nspin=1 SCF first PR acceptable
    with MPI and ordinary spin in follow-ups? Earlier review of feat: add restricted rVV10 plane-wave support #8031 expected
    those capabilities; I have not treated the staged scope as approved. The PR
    stays Draft pending this decision, the external API review, independent
    reference validation.

@CleverPhysician

Copy link
Copy Markdown
Author

Update after the hosted checks completed:

  • The standard upstream workflow is green: 18/18 checks passed on head f3d41ad55ed53abb18ec8953d64df805d926dedd.
  • The serial intern004 validation remains green: the libvdwxc adapter test passed 1/1 and the minimal CPU/PW/nspin=1 Si SCF converged with the recorded energy and density checks.
  • This revision addresses the main concerns from feat: add restricted rVV10 plane-wave support #8031: semilocal and nonlocal XC are separate inputs, the host side uses a generic additive component, and rVV10-specific numerical work is kept behind the thin libvdwxc adapter rather than duplicated in the generic XC evaluator.
  • Following the pattern of merged Add optional DFT-D4 support #7380, the PR now includes explicit dependency/build commands, user-facing INPUT documentation, citations, unit coverage, and an honest statement of checks not run.

The PR remains Draft while the maintainer confirms the staged CPU/serial/nspin=1 scope and while the QE same-density reference comparison (including gradient/divergence sign and normalization) is completed. libvdwxc MR !32 is still a Draft dependency, so I am not presenting it as a stable release.

@Growl1234

Copy link
Copy Markdown

The pinned libvdwxc Draft branch's own rvv10.serial test is not fully green: 7/8 CTest groups passed and 69 finite-difference/strain checks fail at roughly 1e-6--1e-5. This is reported as a dependency-side Draft issue, not hidden.

Could you provide the detailed information?

Another side note: libvdwxc currently requires FFTW-MPI wrapper when MPI is enabled, so be careful with MKL; for now you can consider adding a USE_FFTW3_WITH_MKL that use MKL Blas/lapack/scalapack but standalone FFTW library, but I'm in progress of refactoring its FFT backend and dropping the direct FFTW-MPI dependency, so hopefully in the future everything will be better.

@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 32e12de74c07d2307a90c695dac6f8e452f592e5, independently cross-checked against the pinned libvdwxc implementation. Two geometry issues and one nonblocking timer-label cleanup are noted inline. No builds or runtime tests were run.

Comment on lines +30 to +34
return {a.e11 * pw.lat0,
a.e21 * pw.lat0,
a.e31 * pw.lat0,
a.e12 * pw.lat0,
a.e22 * pw.lat0,

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.

[P1] Pass ABACUS lattice rows to libvdwxc

ABACUS stores lattice vectors in rows, while libvdwxc treats each C00,C10,C20 argument group as one lattice vector, so this mapping makes the convolution use the transposed cell. For the oblique lattice in the new test, mode (1,0,0) gets |G|²=1 instead of 4/3 in units of (2π/lat0)², giving the wrong nonlocal geometry. Please pass each ABACUS row consecutively and add an independent geometry check; the direct-API test currently repeats the same transpose.

Comment on lines +19 to +21
if (pw.gamma_only || pw.get_device() != "cpu" || pw.get_precision() != "double" || pw.poolnproc != 1
|| pw.nrxx != pw.nxyz || pw.nx <= 0 || pw.ny <= 0 || pw.nz <= 0 || pw.nxyz <= 0 || pw.npw <= 0
|| !std::isfinite(pw.omega) || pw.omega <= 0.0 || !std::isfinite(pw.tpiba) || pw.tpiba <= 0.0)

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] Handle left-handed cells before calling the backend

pw.omega > 0 also accepts left-handed cells: ABACUS preserves their lattice and stores abs(det), whereas the pinned libvdwxc uses the signed determinant for its integration volume. A reflected diagonal cell therefore reverses the returned nonlocal energy while the potential contraction still uses the host’s positive volume, making energy and potential inconsistent. Please reject this orientation explicitly for the staged interface or transform the cell and density consistently, and add a regression case.

void PotNonlocalXC::cal_v_eff(const Charge* chg, const UnitCell* cell, ModuleBase::matrix& v_eff)
{
ModuleBase::TITLE("PotNonlocalXC", "cal_veff");
ModuleBase::timer::start("PotNonlocalXC", "cal_veff");

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: The new timer labels use cal_veff, while the enclosing function is cal_v_eff. Please use cal_v_eff in both start and end to follow the timer naming rule; this has no numerical effect and can be handled in a follow-up.

@CleverPhysician

Copy link
Copy Markdown
Author

Follow-up on head 32e12de:

  • The parser now rejects para.sys.double_grid explicitly, so unsupported double-density-grid inputs fail during input validation with a clear single-density-grid diagnostic.
  • The host component now enforces the declared first-PR nspin=1 scope instead of retaining an untested nspin=2 path.
  • The updated Python contract test is 7/7. On intern004, the real libvdwxc adapter CTest is 1/1, the abacus_pw_ser target relinks successfully, the two-atom Si CPU/PW/nspin=1 SCF converges with E_xc=-4.2517234318 Ry, E_total=-208.0135469216 eV, and the double-grid and nspin=2 negative-input checks both fail at the intended parser diagnostic.

The PR remains Draft while the new head's hosted checks are queued and the QE same-density reference is discussed.

@CleverPhysician

Copy link
Copy Markdown
Author

Addressed the ABACUS-PR-BOT static review on head e65e07c:

  • The libvdwxc cell adapter now passes ABACUS lattice rows as the C API's C00,C10,C20 vector groups. The oblique-cell test constructs the direct reference with the same documented row convention, so a transpose mismatch is now detected.
  • The adapter rejects non-positive latvec.Det() before constructing the backend. A left-handed-cell regression test covers this case.
  • The PotNonlocalXC timer labels now use cal_v_eff consistently.

The intern004 adapter CTest is 1/1 after these changes, and the Si CPU/PW/nspin=1 SCF remains numerically unchanged. The PR stays Draft pending the hosted checks for the new head and maintainer review.

Comment thread CMakeLists.txt Outdated
Comment on lines +633 to +637
if(NOT TARGET libvdwxc::vdwxc)
message(FATAL_ERROR
"ENABLE_LIBVDWXC requires the libvdwxc::vdwxc CMake target. "
"Use the libvdwxc development build that includes the rVV10 API.")
endif()

@Growl1234 Growl1234 Oct 14, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That shouldn't be needed as libvdwxc's CMake config will definitely have libvdwxc::vdwxc target. Previously I did this in abacus for RapidJSON due to its embarrassing release status, but with it replaced by nlohmann-json there's no longer the case. If abacus can deal with items like dftd4 and pexsi well then the same for libvdwxc (its cmake is cleaner). If you really encountered issues please report them.

Comment thread CMakeLists.txt Outdated
Comment on lines +638 to +670
get_target_property(LIBVDWXC_INCLUDE_DIRS libvdwxc::vdwxc INTERFACE_INCLUDE_DIRECTORIES)
if(NOT LIBVDWXC_INCLUDE_DIRS)
message(FATAL_ERROR "libvdwxc::vdwxc does not expose its include directory")
endif()
# Installed packages expose a concrete include path, while build-tree
# targets may expose generator expressions. Strip those expressions before
# probing so configuration gives a useful error instead of a later include
# failure.
set(_libvdwxc_include_hints)
foreach(_include_dir IN LISTS LIBVDWXC_INCLUDE_DIRS)
string(GENEX_STRIP "${_include_dir}" _include_dir_stripped)
if(IS_DIRECTORY "${_include_dir_stripped}")
list(APPEND _libvdwxc_include_hints "${_include_dir_stripped}")
endif()
endforeach()
unset(LIBVDWXC_HEADER_DIR CACHE)
find_path(LIBVDWXC_HEADER_DIR NAMES vdwxc.h HINTS ${_libvdwxc_include_hints}
NO_DEFAULT_PATH)
if(NOT LIBVDWXC_HEADER_DIR)
message(FATAL_ERROR "libvdwxc::vdwxc does not provide vdwxc.h")
endif()
file(READ "${LIBVDWXC_HEADER_DIR}/vdwxc.h" LIBVDWXC_HEADER_TEXT)
if(NOT LIBVDWXC_HEADER_TEXT MATCHES "VDWXC_RVV10"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_new"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_set_rvv10_parameters"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_set_unit_cell"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_init_serial"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_calculate"
OR NOT LIBVDWXC_HEADER_TEXT MATCHES "vdwxc_finalize")
message(FATAL_ERROR
"The selected libvdwxc headers do not provide the complete serial rVV10 API; "
"use the pinned development build containing MR !32.")
endif()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks like you add a lot of lines simply for detecting rVV10 API? For the time it might be okay, but we should drop it at some time in the future.

Comment thread docs/developers_guide/nonlocal_xc.md Outdated

## Follow-up work

The next PRs can add a libvdwxc MPI/PFFT adapter, ordinary spin, GPU/LCAO

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just a side note: PFFT dependency might be dropped in the future. Actually I'm proposing a minimal dependency policy upstream, but anyways PFFT will be the first lucky one.

@CleverPhysician

Copy link
Copy Markdown
Author

Thanks for asking. I reran the unchanged libvdwxc revision 91ef4820f3270e22b35fddc2ab4cab8efa4b6d79 in two fresh build directories. My earlier wording was too broad: these were 69 failed comparisons within one CTest, rather than 69 failed tests or evidence that all libvdwxc algorithms fail.

Both builds used GCC 11.2.1, Release (-O3 -DNDEBUG; the tests also use -UNDEBUG), shared libraries, and MPI disabled. The MKL imported target additionally supplies -m64:

-DCMAKE_BUILD_TYPE=Release
-DCMAKE_C_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc
-DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=ON -DVDWXC_ENABLE_MPI=OFF

With -DVDWXC_FFT_PROVIDER=MKL -DMKL_INTERFACE=lp64 -DMKL_THREADING=sequential -DMKL_LINK=dynamic and MKL 2022.2.1, 7/8 CTests pass. rvv10.serial reports:

  • 50 density-derivative finite-difference mismatches: maximum absolute discrepancy 2.34733549e-6; tolerance 3e-8 × (1 + |expected|).
  • 16 sigma-derivative mismatches: maximum absolute discrepancy 5.68711029e-6; tolerance 3e-7 × (1 + |expected|).
  • 3 full-strain derivative mismatches: maximum absolute discrepancy 9.01266900e-6; tolerance 3e-7 × (1 + |expected|).

The original MKL executable reproduces exactly the same values under a clean environment with no LD_LIBRARY_PATH:

env -i PATH=/usr/bin:/bin LANG=C LC_ALL=C OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 \
  /tmp/libvdwxc-mr32-audit/build-audit/libvdwxc_rvv10_test

Selecting -DVDWXC_FFT_PROVIDER=FFTW3 with standalone FFTW 3.3.11 and the same common settings gives 8/8 CTests passing, and the same rvv10.serial test reports 0 failures, also under env -i.

Both configurations pass the separate CP2K-table reference comparisons in that test: energy, density/sigma derivatives, and explicit stress on a 3 × 3 × 5 oblique grid, for both default and custom parameters. Those fixtures were generated independently using CP2K's kernel table, NumPy FFT, and SciPy splines; this is a table-level reference, not a CP2K SCF or QE comparison.

The current evidence therefore isolates the discrepancy to this MKL backend configuration. The underlying cause has not been established.

Updated head c23f000 now builds ABACUS with OpenBLAS and the same standalone FFTW as libvdwxc, avoiding mixed fftw_* implementations. The full serial PW executable builds, the adapter/Makefile CTests pass 2/2 (six C++ numerical/error cases), and the Si SCF converges with E_total=-208.0135469216242 eV. I corrected the PR description accordingly. MPI is not yet implemented, so I have not tested the FFTW-MPI wrapper or added a new MKL/FFTW mixing option.

This update also removes the manual CMake target/header/API checks and uses libvdwxc::vdwxc directly as suggested. The redundant developer page has been removed, and the adapter does not encode a PFFT dependency. It uses ABACUS's standard error diagnostics and adds an independent oblique/orthogonal-cell geometry test: deliberately restoring the wrong transpose makes that test fail. The PR stays Draft pending the scope decision and independent QE comparison.

@Growl1234

Copy link
Copy Markdown

Ah OK, I can now reproduce the failure with oneMKL 2026.1.0. I will have a look into it.

@Growl1234

Copy link
Copy Markdown

Ah OK, I can now reproduce the failure with oneMKL 2026.1.0. I will have a look into it.

@CleverPhysician This should be fixed on libvdwxc side, please check

@CleverPhysician

Copy link
Copy Markdown
Author

Follow-up on c3dedfb:

  • The adapter now forbids copying its owned libvdwxc handle. A type-contract
    regression failed on the original implicit copy constructor/assignment and
    passes with the two deleted operations.
  • Added one focused host test using real Charge, UnitCell, and the backend.
    It checks valence-plus-core density construction, additive energy/vtxc/potential,
    preservation of existing XC values and unchanged density arrays. The separately
    tested adapter supplies the correction reference; this is host bookkeeping
    coverage, not an independent physical reference.
  • Mutation checks confirm it catches missing core density (3.33e-5 Ry energy
    discrepancy) and replacing += by =. Production source was restored and
    checksum-matched before final verification.
  • The full serial PW executable builds and all three libvdwxc-related CTests
    pass (seven adapter cases, one host case, one build-report test). The Si SCF
    and unsupported-input checks were rerun. Scope is unchanged.

The earlier 18 successful hosted checks apply to c23f000, not this new head;
new CI still needs to finish. The PR remains Draft pending scope approval and
independent QE validation. I found preserved raw QE density/output fixtures for
that next comparison, but have not counted the old native-backend results as
validation of this adapter.

@CleverPhysician

Copy link
Copy Markdown
Author

Thanks, checked the fix at 94410ebdf3dc9615a40f40c3a5b59dbe20a433d2.
With GCC 11.2.1, both standalone FFTW 3.3.11 and MKL 2022.2.1
(lp64/sequential/dynamic) now pass all 8 library CTests, including
fft.weights and rvv10.serial. The seven ABACUS adapter tests and the real
host bookkeeping test also pass with the new standalone-FFTW library.
These runs were on a scheduled compute node (Slurm 555743), with the two
FFT providers kept separate. I updated the documented pin; no ABACUS
implementation change was needed for this fix.

The new adapter has now also been compared against the immutable original-QE
directional fixtures: seven cases, 960 points each, nine steps each.
Maximum energy difference is 3.50e-13 Ry, and its own-energy directional
residual is at most 1.25e-10 Ry at h=1e-4 (L1-direction normalized).
I have not called the pointwise potential comparison a pass: low-q and
small-sigma conventions differ, and the kernel convolution G sets are not
identical even when the host PW gradient cutoff is the same. Those differences
are recorded separately in the PR description; material/vacuum reference
validation and staged-scope agreement are still pending. Keeping this Draft.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants