Repository navigation
Conversation
grad_wfc mapped gcar/kvec_c as DT_DOUBLE but accessed them with data<Real>() (float in single precision), which triggers the Tensor data type check and aborts single-precision meta-GGA stress. Build Real-precision host copies from the PW_Basis_K vectors and upload them, consistent with the SCF meta-GGA operator. Also instantiate grad_wfc<complex<float>, GPU, float>. Validation: precision single + mGGA stress, CPU/GPU.
Use a double scalar for the NLCC diagonal stress reduction to avoid single-precision accumulation error in the isotropic contribution. Previously compiled and validated on POSCAR 0224272 against CPU double; pressure error fell from approximately 0.403 to 0.00099 kbar, with essentially unchanged energy, forces and observed runtime. Additional 11 MPI x 1 OMP checks on POSCAR 0743323 and 0251308 reduced stress and pressure errors while preserving the original scientific inputs. This commit records the tested one-line source change only.
Keep the nine kinetic-stress accumulators in double precision to avoid rounding loss when summing contributions over bands and k-points. Wavefunctions and per-band GPU dot products retain their chosen precision. Validated POSCAR 0159503 with DAV, GPU 1 MPI x 1 OMP and unchanged INPUT, using the converged CPU-double 11 MPI x 1 OMP result as the reference. Maximum stress error decreases from 1.31174 to 0.14036 kbar and pressure error from 0.37485 to 0.13039 kbar. The SCF energy/density history and final energy are identical. Both runs converge in 24 steps; wall time is 522.92 versus 518.23 seconds, with no observed performance regression. Rebuilt all three consumers of the changed header before runtime validation.
Accumulate per-k-point rho and kinetic density into the existing double host fields for GPU single precision. Keep wavefunctions, FFTs and each k-point density in single precision, reuse one host buffer and clear the device density workspace after each k point. Validated structure 0317955 with unchanged INPUT and solver stopping conditions, GPU 1 MPI x 1 OMP, 18 converged SCF steps and all 100 k points free of occupied zero states. Reuse the converged CPU-double reference. Maximum stress error decreases from 0.56409 to 0.10767 kbar and pressure error from 0.52878 to 0.09912 kbar. Energy and forces remain comparable. Wall time is effectively unchanged (483.15 to 483.49 s), about 12.1x the recorded CPU-double speed. Saved-density electron-count error improves about 72x; rho/tau L2 differences against auxiliary GPU double improve about 6.7x/20.9x.
Split complex<float> GPU CGEMM A^H B reductions longer than 2048 into blocks, preserving alpha and the original beta on the first block. Subsequent blocks accumulate with beta=1. Other paths retain their existing call and single-precision storage is unchanged. Validated with a complete 17-step SCF run of 1762323 on L20 using 1 MPI x 1 OMP, dav and unchanged INPUT/stopping criteria. No occupied anomalous zero states were found. Reused the converged CPU-double 11 MPI reference. Against CPU double, energy error falls from 3.0136 to 0.0376 meV/atom and maximum stress error from 0.02996 to 0.01653 kbar. Force improves slightly and pressure error stays approximately unchanged. Wall time rises from 315.3 to 345.9 s (+9.7%), retaining 23.3x CPU-double speed.
Solve non-USPP GPU-float reduced matrices once in double precision and return the requested eigenpairs in single precision. Large wavefunction operations and stopping thresholds retain their existing precision policy. Replace the float-prefix Jacobi policy while retaining the preceding six validated repairs. The previous dav tip is retained on a protection branch. Validated on L20 with GPU 1 MPI x 1 OMP, unchanged INPUT and reused CPU double references (11 MPI x 1 OMP): - 0056851: recover convergence in 68 SCF steps, 1140.5 s, ~14.0x CPU. - 0186922: 73 -> 33 steps, 1080.2 -> 566.3 s, ~16.7x CPU. - 1729347: 22 -> 21 steps, 262.9 -> 279.2 s, ~8.9x CPU. CPU-relative energy errors are 0.04733, 0.07405 and 0.09601 meV/atom, respectively. Force, stress and pressure were independently checked against native CPU output. This is a local precision-policy correction; it does not establish a defect in the vendor's single-precision algorithm. Measured binary SHA256: 7aec892171fb7e401b572d17ae372c6922461c279cf54ac6fc1eb51ecc7211f1
Replace the initial and expansion Schmidt normalization paths with the existing float Householder QR kernel for norm-conserving CUDA float calculations with one rank per diagonalization pool. A frozen 0058587 projection exposed a 3.53e-5 relative error in the subtracted norm estimate versus 3.15e-8 in the direct float norm. Native float replay and complete GPU 1-MPI tests validate the replacement without an added orthogonalization pass or double reduced eigensolve. 0058587 converges in 39 SCF / 348.6 s, 9.6% less time than the prior converged extra-orthogonalization version. CPU-relative energy/force/stress/pressure errors are 0.05674 meV/atom, 0.004476 eV/A, 0.01737 kbar, 0.00894 kbar. 0030651 converges in 13 SCF / 295.8 s, 28.2% less than the retained-five-fix baseline; energy/stress/pressure errors rise slightly to 0.07688 meV/atom, 0.04274 kbar, 0.01662 kbar. Neither failed nor incomplete runs are used as timing denominators. INPUT, internal stopping and compiler flags stay fixed. CPU 11-MPI references are reused; actual GPU tests use 1 MPI x 1 OMP. CUDA preprocessor guards preserve the existing CPU/ROCm code paths. A recompile of this guarded source produces the byte-identical executable used in both completed tests. Incremental build, not a clean full build. Multi-pool/ROCm runtime and 1729347 coverage are not established here.
The accel branch supports `precision single` on GPU, but several
explicit `<float, base_device::DEVICE_GPU>` instantiations were missing
and the DeltaSpin device kernels used `double*` for the lambda array,
so a GPU build failed to compile/link.
- stress_op.{cu,hip.cu}: use FPTYPE* for the DeltaSpin lambda argument
- cal_mw_from_lambda.cpp: diagonalize into a temporary Real buffer and
copy back to the double-precision pelec->ekb (both GPU paths)
- onsite_proj.cpp / onsite_proj_tools.cpp: instantiate the float GPU
OnsiteProjector / Onsite_Proj_tools
- force_op.{cu,hip.cu}: instantiate saveVkbValues<float> and
revertVkbValues<float>
- xc_grad.cpp: instantiate grad_wfc<complex<float>, GPU, float>
The single-precision residual H*c - lambda*S*c suffers catastrophic cancellation and collapses to numerical noise with a zero/negative norm. DiagoDavid::SchmidtOrth and DavSubspace::normalize_op (CPU/CUDA/ROCm) asserted psi_norm > 0.0, aborting single-precision non-collinear (nspin=4) calculations. Treat such directions as converged and skip normalization instead of aborting.
The subspace eigenvectors/eigenvalues broadcast in diag_zhegvx used hardcoded MPI_DOUBLE_COMPLEX / MPI_DOUBLE, which for single-precision (complex<float>/float) read and write past the buffer (16 vs 8 bytes per element) and corrupt the eigenvectors. Use Parallel_Reduce::MPI_Type<T> / MPI_Type<Real> so float uses MPI_C_FLOAT_COMPLEX / MPI_FLOAT.
In single precision (has_float_data only), z_deeq_nc and z_qq_so were left as nullptr, but the force/stress driver (Forces<double> / Stress_PW<double>) always reads the double-precision deeq_nc via get_deeq_nc_data<double>(). Point them at deeq_nc.ptr / qq_so.ptr unconditionally (mirroring d_deeq and d_qq_nt) so the double force/stress path does not segfault under precision single.
The single-pass QR path was written against the older spsi_func callable. Develop now passes an HSOperator, so use op.spsi() for the batched basis update.
- Use FPTYPE* for the DeltaSpin stress lambda in the kernel declarations, matching the FPTYPE lambda buffers built by Onsite_Proj_tools. - Do not instantiate float GPU OnsiteProjector/Onsite_Proj_tools: that path is still double-typed in develop and fails to compile.
The develop VNL initialization only allocated and filled the double deeq_nc/qq_so buffers when has_double_data was set. Single-precision GPU runs therefore passed null device pointers to the double force/stress kernel. Allocate and synchronize those buffers unconditionally on GPU, and keep the CPU path's host pointers valid as before.
dyzheng
force-pushed
the
develop-single-precision-fixes
branch
from
October 23, 2026 03:58
693b7b7 to
de17ec2
Compare
This branch has not been deployed
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.
Summary
Fix GPU single-precision DAV restart failures, unstable basis orthogonalization, insufficient reduced-eigensolve accuracy, and rounding errors in density and stress accumulation. Also correct omitted meta-GGA XC contributions in the shared CPU/GPU path.
This PR contains 8 commits across 6 source files, with 101 insertions and 6 deletions. Wavefunctions and FFTs remain single precision; selected accumulations and the existing reduced eigensolve use double precision. No failure-triggered rerun is added, and scientific INPUT settings and convergence criteria are unchanged.
Overall results
Of the original 500 structures, 472 have converged CPU-double references. The 75 structures with anomalous GPU DAV results were retested; previously passing structures retain their original results.
68 of the 75 anomalous structures now meet all four accuracy criteria against the original CPU references. Four additional structures meet the criteria against corrected candidate CPU references after addressing the shared XC omission, bringing the cumulative count to 469/472 (99.36%). These four are reference corrections, not evidence of improved GPU accuracy alone.
The screening criteria used in this campaign are energy error ≤1 meV/atom, maximum per-atom force-vector error ≤0.05 eV/Å, maximum stress-component error ≤0.5 kbar, and absolute pressure error ≤0.5 kbar. These are campaign screening criteria, not universal physical-accuracy guarantees.
Changes and measured effects
The following are per-change validation results. Each timing change uses its stated comparator; the percentages are not additive and the intermediate results should not be interpreted as measurements of the final combined version.
Overall performance
CPU references use 11 MPI ranks × 1 OMP thread. GPU runs use one NVIDIA L20, 1 MPI rank × 1 OMP thread. CPU references generally use
dav_subspace, while GPU runs usedav; the ratios describe these execution configurations, not a pure hardware or cost comparison.Build, validation scope, and remaining issues
The final commit was clean-built on L20; the archived executable and recorded source files match the submitted source. The principal validated configuration is CUDA, GPU single-precision DAV, non-USPP, and one MPI rank. Block QR is restricted to that configuration. The restart reset, stress accumulator types, and XC correction also touch shared code; comprehensive regression coverage of other execution paths is not established by these records.
Residual accuracy issues remain for three structures: stress in POSCAR0955272 and POSCAR0131516, and forces in POSCAR1574549.
The original 397 passing structures were not rerun with the final executable, so the overall figures are cumulative validation results rather than a full final-version rerun. The four corrected CPU references remain candidate references without independent external numerical certification. The results demonstrate the combined effect of the fixes, not a full per-commit ablation study.