Repository navigation
Tests: scf_out_wf fails on GPU with phase-sensitive per-band coefficient references #8153
Description
Describe the Testing Issue
The scheduled GPU validation fails in tests/11_PW_GPU/scf_out_wf when comparing the Max_wfc_1–Max_wfc_6 properties. What is the appropriate way to retain useful wavefunction-output coverage without requiring a particular phase or basis choice within degenerate eigenspaces?
Failing run and output
- Workflow run at commit
8b546bdf369f8ff9c25a8aea580dd3560a1e3931. - Download test results. The failure log is
results/cases/11_PW_GPU__scf_out_wf/attempt-1.loginside the archive (GitHub sign-in may be required; artifact retention applies).
Relevant output:
[ OK ] etotref
[ OK ] etotperatomref
[WARNING ] Max_wfc_1 cal=0.75350000 ref=0.95270000 deviation=0.19920000
[WARNING ] Max_wfc_2 cal=0.33310000 ref=0.36750000 deviation=0.03440000
[WARNING ] Max_wfc_3 cal=0.35840000 ref=0.33510000 deviation=-0.02330000
[WARNING ] Max_wfc_4 cal=0.34430000 ref=0.38250000 deviation=0.03820000
[WARNING ] Max_wfc_5 cal=0.45310000 ref=0.44090000 deviation=-0.01220000
[WARNING ] Max_wfc_6 cal=0.46110000 ref=0.47520000 deviation=0.01410000
This run reports 116 passed cases, 1 failed case and 0 infrastructure failures. The reference was not stale: the workflow copies the case and its references from the tested source commit and uses that commit's shared integration-test scripts.
What the test compares
The collector reads the first k-point's wfk1_pw.txt and emits one maximum for each numbered band. It scans real and imaginary fields separately, so the current quantity is max_G(max(|Re c_n(G)|, |Im c_n(G)|)), rather than the maximum complex modulus. It is sensitive to an arbitrary overall phase.
Even replacing it with max_G |c_n(G)| leaves a second question: this case contains degenerate bands, whose individual eigenvectors need not be uniquely defined.
Additional Context
CPU/GPU reproduction
The tested commit was rebuilt with the GPU CI build options. CPU/GPU comparisons used the same executable, one MPI rank, OMP_NUM_THREADS=1, and identical inputs apart from device. The GPU was an NVIDIA Tesla V100. The case uses init_wfc random and pw_seed 1.
- CPU output matches all six current reference values.
- GPU output reproduces all six CI values; an independent repeat gives the same values.
- CPU/GPU total energies differ by about
1.2e-11 eV. - After matching G-vector coordinates and normalizing each vector, corresponding first-k-point band overlaps have magnitudes greater than
0.9999999992at the originalscf_thr=1e-9. - Aligning each GPU vector's overall phase to its CPU counterpart reproduces all six reference values at the collector's four-decimal precision.
Thus, the original failure is primarily explained by overall phases, not evidence of different physical states.
To check whether tighter convergence makes a phase-invariant, per-band maximum reliable, I also tightened SCF convergence. The largest CPU/GPU difference across the six max_G |c_n(G)| values was:
scf_thr |
Maximum difference |
|---|---|
1e-9 |
8.55e-6 |
1e-11 |
7.33e-6 |
1e-13 |
1.31e-3 |
1e-14 |
1.12e-1 |
All eight calculations in this table reported SCF convergence. Tightening the threshold does not stabilize the individual-band quantity.
For example, the CPU OUT.autotest/eig_occ.txt at scf_thr=1e-13 contains:
spin=1 k-point=1/3 Cartesian=0.0000000 0.0000000 0.0000000 (411 plane wave)
1 -5.438151623432725 0.2500000000000000
2 6.727204110149499 0.2411498411155524
3 6.727204110149511 0.2411498411155507
4 6.727204110149645 0.2411498411155326
5 9.179147962382407 0.000000000000000
6 9.179147962385155 0.000000000000000
Bands 2–4 are degenerate, as are the displayed bands 5–6. Across the successful convergence comparisons, the CPU/GPU overlap singular values for these displayed groups remain within about 1e-7 of unity, despite changes in their individual-band maxima. This supports equivalent subspaces with different internal eigenvector choices. We have not yet checked whether band 7 extends the latter degenerate group.
Possible cause and question
The CPU subspace diagonalization uses LAPACK hegvd, while the GPU path uses cuSOLVER. Different eigensolver implementations may choose different phases and bases within a degenerate eigenspace. The shared CG reorder logic orders energies when an inversion exceeds its threshold, but does not impose a unique convention for equal-energy states.
Energy ordering alone does not uniquely identify individual orbitals within a degenerate group. Equal-energy states may be permuted or mixed by a unitary transformation, so stabilizing their order alone would not guarantee matching coefficients. The exact solver operation at which the CPU/GPU vectors first diverge has not been isolated.
The test currently checks a particular numbered orbital's maximum coefficient even within these degenerate groups. How should this case be handled so it stops reporting false failures while still detecting broken wavefunction output?
Would it be preferable to compare a phase- and degenerate-subspace-invariant quantity (for example, a sum of squared coefficient magnitudes over a complete degenerate group), or to choose a nondegenerate fixture for this particular output test? Is there an existing ABACUS comparison convention or helper that should be reused? Simply regenerating backend-specific maxima or increasing tolerances seems unlikely to address the underlying issue.
Task list for Issue attackers (only for developers)
- Review the failing case and CPU/GPU comparison results.
- Agree on a phase- and degeneracy-aware comparison criterion for this output test.
- Implement and validate the test change on CPU and GPU.
Activity
mohanchen commentedon Oct 15, 2026
@ABACUS-PR-BOT Could you loo into the issue and see if this is a bug? If it is a bug, could you fix it? If it is not a bug, please give some suggestions.
Stardust0831 commentedon Oct 17, 2026
I have isolated the phase change in
tests/11_PW_GPU/scf_out_wffurther. The first divergence occurs in a nondegenerate subspace eigensolve, so band permutations within degenerate groups are not needed to explain the original failure.With commit
8b546bdf369f, the executable, input, V100 GPU and other loaded libraries fixed, changing only cuSOLVER viaLD_PRELOADgives:Max_wfcreferences matchThe failing 11.7.5.82 binary matches NVIDIA's official archive by SHA256. Separate tests using 1–3 GPUs and different MPI/OpenMP configurations retained the same six reported values.
I captured the first
cusolverDnZhegvdcall (n=6,itype=1, upper triangle) and replayed it independently with 11.5.2.141 and 11.7.5.82. The input matrices A and B are bitwise identical between the ABACUS runs; each replay reproduces its corresponding solver output bitwise. The smallest eigenvalue gap is0.27356. The maximum eigenvalue difference is1.78e-15, and the residuals||AV−BVΛ||F / ||A||Fare1.12e-15and1.63e-15. After aligning each vector's overall phase, the maximum component difference is9.19e-15.For this captured problem, explicit reconstruction and GPU traces identify an effective upper/QL → lower/QR reduction and back-transformation change inside the high-level solver:
hetrd(U)andhetrd(L)each return bitwise-identical results across the two versions. After a common Cholesky transformation, oldheevd(U)matches the explicit upper-triangle path up to signs; newheevd(U)matches the lower-triangle path up to signs.hegvdandheevdchange fromormql_cta_kerneltoormqr_cta_kernel, with a corresponding tridiagonalization-kernel change. Both still usesteqr_ker.B=UᴴUand the transformed eigenvectory=Uv, the two paths leave respectively the last or first component ofyreal. This predicts all six observed phase shifts within5e-13degrees modulo 180°.ABACUS's PW GPU call still requests the upper input triangle. The cuSOLVER API does not promise a particular eigenvector phase. These observations concern this matrix and execution path, rather than every matrix size or NVIDIA's implementation intent.
CPU LAPACK and old cuSOLVER already differ by signs on this same input. The collector's separate absolute-real/imaginary maxima hide those signs but change under general complex phase rotations.
As a causal check, I kept the new library and applied only a whole-vector phase rotation to each returned subspace eigenvector, making its last component real and positive. Applying this after all 27 solver calls restores all six current references at four decimals; applying it only after the first call still fails. Both full calculations converge, with a total-energy difference of
2.7e-11 eV. This is a diagnostic intervention: a fixed component can be nearly zero, making that convention unsuitable as a general fix.The failure timeline has a separate trigger. #8043 added
stp.sync_cpu()before wavefunction output and updated the references. Removing only that synchronization reproduces all six historical values from stale, nonorthonormal host initialization data. An earlier passing run already reports CUDA 12.9.1; the failure date therefore does not establish a toolkit upgrade. The output fix exposed the solver phase difference.These checks support valid eigenstates in this case, while confirming a change in raw-coefficient reproducibility. I suggest making this output check phase-insensitive. Degenerate-subspace invariance remains a separate consideration for the tighter-convergence comparisons above. Is there an intended ABACUS output-phase convention that this test should instead enforce?