feat(xc): add gga_grad 1/2 with variationally consistent mode 2 - #7924
feat(xc): add gga_grad 1/2 with variationally consistent mode 2#7924MagTheoryLab wants to merge 16 commits into
Conversation
Based-on: deepmodeling#7758 Co-authored-by: dyzheng <zhengdy@aisi.ac.cn>
Based-on: deepmodeling#7758 Co-authored-by: dyzheng <zhengdy@aisi.ac.cn>
Project multi-k density matrices before star restoration to preserve the symmetry assumed by reduced EXX contractions. Add complex-density and spin-channel regressions and update the Si HSE reference after independent solver and full-contraction checks. (cherry picked from commit b0441a9)
Add the builtin NCGGA implementation and radial helper to the legacy XC object list and both solvation test targets that compile xc_grad.cpp directly. This resolves the undefined NCGGA_SF_Builtin symbols in the CPU/CUDA test links and the Intel Makefile build. Validation: both MODULE_HAMILT_surchem_cal_vcav and MODULE_HAMILT_surchem_cal_vel rebuilt and passed CTest on Sai DSPRHBM; Makefile OBJS_XC expansion includes both objects. Full CUDA and Intel Makefile builds remain covered by CI.
(cherry picked from commit 8d632aa)
Use the same finite omega for energy and stress evaluations. LibXC 5.1.7 reproduces NaN derivatives at zero omega; the finite-omega fixture passes all 32 tests in serial and MPI2 with LibXC 5.1.7 and 7.0.0. Keep production behavior and test tolerances unchanged.
mohanchen
left a comment
There was a problem hiding this comment.
I will handle this PR later.
Preserve the gga_grad discrete reverse path and explicit has_mag conversion while incorporating upstream removal of global dependencies. Validated five XC CTest targets, including serial and MPI2 finite differences, on Sai DSPRHBM (job 1194715). Regenerated input Markdown matches the tracked documentation.
| const bool* numeric, | ||
| UnitCell& ucell_in) | ||
| { | ||
| const Parameter& parameters = PARAM; |
There was a problem hiding this comment.
I'd recommend not modifying the code this way. It would be better to pass the required variables directly as function input parameters, rather than using PARAMETERS/PARAM in any form.
| const bool *numeric, | ||
| const Charge* const chr) | ||
| { | ||
| const Parameter& parameters = PARAM; |
There was a problem hiding this comment.
I'd recommend not modifying the code this way. It would be better to pass the required variables directly as function input parameters, rather than using PARAMETERS/PARAM in any form.
| ModulePW::PW_Basis* rho_basis, | ||
| const Charge* const chr) | ||
| { | ||
| const Parameter& parameters = PARAM; |
There was a problem hiding this comment.
I'd recommend not modifying the code this way. It would be better to pass the required variables directly as function input parameters, rather than using PARAMETERS/PARAM in any form.
| double hse_omega = 0.0; | ||
| XC_Functional::gradcorr(et1,vt1,v1,&chr,&rhopw,&ucell,stress1,false,nspin1,domag,domag_z, hybrid_alpha, hse_omega); | ||
| XC_Functional::gradcorr(et1,vt1,v1,&chr,&rhopw,&ucell,stress1,true,nspin1,domag,domag_z, hybrid_alpha, hse_omega); | ||
| XC_Functional::gradcorr(et1,vt1,v1,&chr,&rhopw,&ucell,stress1,false,nspin1,domag,domag_z,0, hybrid_alpha, hse_omega); |
There was a problem hiding this comment.
I would suggest not using the number 0 directly, because other developers will not know what it stands for, I would suggest using a local variable (for example xxx=0 and then use xxx) here.
Address review feedback by removing PARAM reads from cal_force_cc, stress_cc and stress_gga and updating PW, LCAO, SDFT and OFDFT callers. Name the legacy gga_grad test input explicitly. Production parameter values and numerical formulas are unchanged; no INPUT documentation changes are required. Validation: Sai DSPRHBM job 1196207 rebuilt abacus_basic_para and four XC test executables. Five CTest entries passed, including serial and MPI2 NCGGA finite differences. CUDA validation remains for CI.
Reminder
AGENTS.mdanddocs/developers_guide/agent_governance.md.source/changes.Linked Issue
Related to #7730. This PR supersedes the modes 1/2 implementation in #7758, with the original author's agreement to withdraw that PR and have this work submitted here. It builds on the original proposal by @dyzheng. This PR carries forward the
gga_gradinterface, the local-magnitude option, the projected-gradient construction, and the associated builtin/LibXC integration from that work. These are prior contributions, not features independently originated by this PR's submitter.This submission covers modes 1 and 2 only. Mode 3 from the earlier proposal is outside this PR's scope; the handoff does not imply that its functionality is included here. In particular, it does not claim to implement or disprove the complete Scalmani–Frisch functional. The additional work here is the C2 radial map, the exact reverse of the specified discrete energy, the density/sigma sanitizer derivatives, consistent XC stress/bookkeeping, and the accompanying verification.
Dependency attribution: the current branch also includes TaoXia's
genelpaand Pauli/y corrections from #7914, with original authorship and cherry-pick trailers preserved, plus Chen Chengbing's native ELPA/cuSolver upper-triangle fixes. These dependency changes must be separated from the GGA contribution during review. Once their upstream equivalents merge, the feature branch should be rebased to avoid submitting them twice. No separate issue is needed for the implementation and verification of the modes already proposed in #7758.What's changed?
For magnetic
nspin=4calculations, add an explicit choice of local spin mapping:gga_grad=0remains the default and selects the existing algorithm.gga_grad=1carries forward Feature: add gga_grad parameter for noncollinear spin GGA functional #7758's local-magnitude option for the builtin GGA path, independent of the initial global quantization axis. For LibXC, modes 0 and 1 retain the same path.gga_grad=2evaluates LDA/GGA using a C2-regularized local spin map and differentiates the same discrete energy used in the forward evaluation. The potential, gradient stress, andvtxcuse that common definition.gga_grad=3is rejected. Other spin configurations retain their existing behavior.Problem in #7758 addressed by this PR
The reviewed #7758 snapshot is
e641dba50e4ea86a03d126191dd271695fda9276. Its mode-2 implementation constructs projected spin gradients from the FFT gradients of the four density channels, then computes the magnetic divergence contribution by applyinggrad_dotto the spin-difference flux and multiplying the result by the local magnetization direction. See the builtin implementation at that snapshot and the commit describing the projected/full divergence distinction.The resulting mode-2 potential is generally not the exact derivative of its own energy on a fixed FFT grid. In the smooth, unsaturated unregularized case, write$p_\mu=m_\mu/|m|$ , $Q_{\nu\mu}=\partial p_\nu/\partial m_\mu$ , $A=(a_+-a_-)/2$ , and $H=(h_+-h_-)/2$ , with the energy derivatives $a_s,h_s$ defined below. The distinction is
Equivalently, the missing fixed-grid correction is
The C2 map is an additional, explicitly documented change to the functional near zero magnetization. It is not presented as an algebraically equivalent rewrite of #7758. Its first and second derivatives, and the active density/sigma branches, must then be propagated consistently as described below. Likewise, this PR does not carry forward the assertion that retaining a full divergence alone makes mode 3 more accurate; it implements and validates mode 2 only.
The numerical evidence is separated accordingly: the FFT example establishes the discrete formula mismatch, the ABACUS real-PW tests validate the new implementation, and the Fe2 table compares SCF convergence against develop and common-fix controls. The Fe2 results are not a direct before/after run of #7758, and do not independently prove that the formula mismatch caused its SCF behavior. The default develop algorithm remains available as mode 0.
1. Differentiate the energy that is actually evaluated
Let$x=(n+n_{\mathrm{core}},m_x,m_y,m_z)$ , let $N_s(x)$ be the local spin density for $s\in{+,-}$ , and define
For the discrete FFT gradient$G_h$ , mode 2 uses the projected gradient and grid energy
Write$a_s=\partial f/\partial N_s$ and $h_s=\partial f/\partial g_s$ . On a fixed differentiable branch,
Using the grid inner-product adjoint$G_h^\dagger=-D_h$ , substitution into $\delta E_h=w\sum_{i,B}v_B(i)\delta x_B(i)$ gives
The middle term is the response of the local-map Jacobian itself. Dropping it, or moving a spatially varying Jacobian outside the discrete divergence without the corresponding discrete identity, generally changes the derivative while leaving the forward energy unchanged. Also,$G_hN_s(x)$ and $\sum_AJ_{sA}G_hx_A$ need not be equal on a finite grid; replacing one by the other changes the discrete functional.
To see why the continuum formula alone is insufficient, consider the unsaturated positive-density map$N_\pm=(n\pm|m|)/2$ . Put $p_\mu=m_\mu/|m|$ , $A=(a_+-a_-)/2$ , and $H=(h_+-h_-)/2$ . In the continuum,
Thus the projected expression is consistent with this continuum energy after the two cross terms cancel. Keeping only the full divergence is not, by itself, a more complete derivative of the same energy. On a finite FFT grid, however, the continuum product/chain rules cannot simply be assumed. The implementation therefore evaluates the boxed discrete reverse, including the Hessian contribution. This is the precise scope of the formula correction relative to the projected/full-divergence distinction described in #7758.
Code:
xc_functional_ncgga_sf.cppimplements the builtin reverse;reverse_ncl_sf_discreteinlibxc_tools.cppimplements its LibXC counterpart. Real-PW tests exercise the actual gradient/divergence operators rather than a pointwise FFT mock.A small, reproducible discrete counterexample
This is a dimensionless toy functional illustrating the algebra, not a PBE/ABACUS benchmark or a measured failure of the #7758 executable. On five periodic points$t_j=2\pi j/5$ , take the real spectral derivative
Let$q=p\cdot G_hm$ , $p=m/|m|$ , and $E_h=\tfrac12\sum_jq_j^2$ . This is obtained from the projected-spin-gradient energy with $f=\tfrac12|g_+-g_-|^2$ on an unsaturated branch. Here $H=q$ and $A=0$ . The exact discrete directional derivative is 0.006394957429, whereas using only $-pG_hq$ gives 0.149387398889.
The exact reverse approaches the energy difference at second order. The shortcut's error remains finite as the perturbation decreases at fixed grid size. This establishes the fixed-grid derivative mismatch; it does not assert failure of a continuum limit under grid refinement.
Reproduce with Python 3 (standard library only)
The script was run successfully; the decreasing-step and residual-error assertions passed.
2. C2 regularization must propagate through both derivatives
With$r=|m|$ , $t=r/\eta$ , and fixed $\eta=10^{-3}$ in atomic density units, define
Inside the regularized interval,
At$r=\eta$ , the value/first/second derivatives are $(\eta,1,0)$ , matching the outer branch. As $r\to0$ , both $S_\eta'/r$ and $S_\eta''$ vanish. Consequently the Cartesian gradient and Hessian have finite, continuous limits:
The code uses this$Q$ in the middle term of the discrete reverse. Replacing only the forward $r$ by $S_\eta(r)$ while retaining an unregularized magnetic derivative would define a different potential.
The actual spin map additionally uses
Its Jacobian follows the selected abs/saturation branch. C2 regularity of the radial function does not make abs/min or all LibXC clipping boundaries globally smooth; tests distinguish branch interiors and radial joins, and the implementation specifies branch choices at the boundaries.
3. LibXC energy weights and clipping belong to the derivative
For one active density branch, let$y_s=\max(T,\rho_s)$ , $Y=\sum_sy_s$ , and $M=\sum_sb_s\rho_s$ , where $b_s$ is the fixed mask on that branch. ABACUS accumulates $M\epsilon$ , whereas LibXC's $Y\epsilon$ . Therefore
vrhodifferentiatesFor sanitized sigma variables$\widetilde\sigma=C(\sigma)$ ,
For example, when the cross component is clipped at$\pm(\widetilde\sigma_{++}+\widetilde\sigma_{--})/2$ , its derivative transfers to the diagonal components with weights $\pm1/2$ ; it is not sufficient to zero only the cross derivative.
make_libxc_weighted_derivativesaccounts for these density and sigma branches before the reverse above. The inactive total-density branch has zero energy and derivative under the implemented threshold convention.Finally, bookkeeping uses the completed returned four-component potential:
The frozen core participates in XC evaluation but is not added to the valence-density contraction in this ledger.
4. Stress uses the same gradient graph
For a homogeneous infinitesimal strain$\varepsilon$ with grid field values held fixed, $\delta g_{s,i}=-\varepsilon_{ji}g_{s,j}$ . Hence
This gives the gradient-metric contribution used by the stress assembly, with the same map and sanitized derivatives as the energy. Volume, density-rescaling, local-XC and core terms must be included separately for the full stress. The tests below distinguish metric-only, frozen-field full-XC, and total self-consistent stress; those are different verification scopes.
Formula contracts of the imported dependencies (credited to their own changes)
For Hermitian$H,S$ with authoritative upper triangles, the lower entries must obey $A_{ji}=\overline{A_{ij}}$ . The generalized eigenproblem $HC=SC\Lambda$ must not depend on arbitrary unused lower-buffer contents. Native ELPA reconstructs private Hermitian inputs and cuSolver selects the upper triangle. This belongs to the separate solver fix, not to the GGA derivation.
For the standard Pauli convention,
$$
\lambda\cdot\sigma=
\begin{pmatrix}
\lambda_z&\lambda_x-i\lambda_y\
\lambda_x+i\lambda_y&-\lambda_z
\end{pmatrix},\qquad
m_y=\operatorname{Tr}(\rho\sigma_y)=-2\operatorname{Im}\rho_{\uparrow\downarrow}.
$$
The operator and moment must use the same y convention. TaoXia's #7914 correction supplies this mapping; it is not a new correction claimed by this GGA PR.
Unit Tests and/or Case Tests for my changes
Derivative evidence: the real-PW suite passed 32/32 in serial and 32/32 with two MPI ranks. It covers the discrete adjoint, density-channel derivatives, radial/saturation branches, core response and translation, local rotation torque, XC bookkeeping, and stress. The density-direction checks include a decreasing-step error test, not just one favorable finite difference.
Here the scaled error is$|a-d|/\max(1,|a|,|d|)$ in the test's atomic-unit convention, and the best value is selected within each tested step sequence. The density-direction threshold is 3e-8 with additional step-decrease gates. These are current implementation results; this table is not a measured failing-then-passing A/B against the head of #7758. Such a #7758-head comparison has not been run in this validation campaign.
Self-consistent Fe2 comparison: use the same two-atom bcc Fe LCAO/SOC case, 100 Ry cutoff,
kspacing=0.4, Gaussian smearing 0.01 Ry, Broyden mixing beta 0.2/ndim 30,scf_thr=scf_ene_thr=1e-6, and a 200-step limit. CPU/GPU use the same CUDA-enabled binary withdeviceswitched, nativeelpa, andOMP_NUM_THREADS=1. Environment: Tesla V100-SXM2-32GB, CUDA 12.9.1, OpenMPI 5.0.10, ELPA 2026.02.001, LibXC 7.0.0.The common-fix control separates GGA effects from eigensolver dependencies. The CPU mode-0 printed trajectory and final energy/forces/stress match the common-fix control exactly; the GPU mode-0 unconverged trajectories are not identical and are not claimed as a converged parity result. Convergence on one case does not prove a general convergence guarantee or determine the correctness of a different functional.
All meet the declared 1e-5 eV / 1e-4 eV/Angstrom / 0.01 kbar energy/force/stress tolerances. Forces are zero at the reported precision in this symmetric case; their agreement is not a nonzero-force derivative test. The four-rank mode-2 run also converged in 17 steps.
Commands run:
$CPU_BUILDand$GPU_BUILDdenote the configured CPU and CUDA build directories;$SOURCE_DIRis the verified source snapshot. Expanded build/job scripts and input/output evidence are retained in the validation record.CPU CTest 7/7 passed; GPU-build CTest 4/4 passed. The CUDA-build real-PW derivative test still exercises host-side FFT/density code; actual GPU SCF coverage comes from the case comparison. CLI accepted 0/1/2 and rejected 3; version v3.11.0-beta9; the generated
gga_graddocumentation matches the tracked metadata. A separateENABLE_LIBXC=OFFconfiguration compiled targetxc_; a complete no-LibXC executable was not built in that check. The final native ELPA regressions passed 3/3 on one and four ranks, and the cuSolver/ScaLAPACK group passed 6/6.Limitations and checks not accepted:
elpa. No blanketgenelpaMPI pass is claimed.Governance Notes
gga_grad, default 0, accepted 0/1/2; fixed mode-2 eta=1e-3, not a new user parameter. C++ registration and generateddocs/parameters.yaml/docs/advanced/input_files/input-main.mdare updated.