From d18f769ddfd6a300c5717382e1faee3e6d7a48fa Mon Sep 17 00:00:00 2001 From: Chen Chengbing <1747193328@qq.com> Date: Tue, 13 Oct 2026 10:39:00 +0800 Subject: [PATCH 1/5] Use mapped-density FFT gradients for noncollinear gga_grad=2 Reverse the spin-channel FFT gradients before the local-map Jacobian in built-in and LibXC paths, and use the same mapped gradients for GGA metric stress. Add local-rotation and clipping-continuity regressions and regenerate INPUT documentation. --- docs/advanced/input_files/input-main.md | 2 +- docs/parameters.yaml | 2 +- source/source_hamilt/module_xc/libxc_abacus.h | 9 +- .../source_hamilt/module_xc/libxc_tools.cpp | 101 +++----------- .../test/test_xc_functional_ncgga_sf.cpp | 69 ++++++++++ .../module_xc/xc_functional_ncgga_sf.cpp | 129 +++++------------- .../module_parameter/input_parameter.h | 2 +- .../module_parameter/read_inp_estruc.cpp | 4 +- 8 files changed, 127 insertions(+), 191 deletions(-) diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index 366c98bbd43..6dfb526036f 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -1387,7 +1387,7 @@ - **Description**: Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations. - 0: preserves the original algorithm (default). - 1: uses the local magnetization magnitude instead of the global quantization axis in the built-in GGA gradient correction. For LIBXC functionals, 0 and 1 are equivalent. - - 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the local-map Jacobian applied to the FFT gradients of the four density channels. The potential reverses this same discrete energy graph, including the radial Hessian and density/sigma clipping branches; the GGA stress uses the corresponding metric derivative. + - 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the FFT gradients of these mapped spin densities. The potential reverses this same discrete energy graph: apply the FFT divergence to each spin-channel flux, then apply the local-map Jacobian. Density/sigma clipping branches and the GGA metric stress derivative use the same mapped densities. This changes the finite-grid functional relative to projecting the four density-channel gradients; converged energies can therefore change. For r = |m| and x = r/eta, S_eta = eta*x^3*(3*x^2 - 8*x + 6) for r < eta, and S_eta = r otherwise. The regularization is part of the functional definition, including its first and second derivatives. Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior. - **Default**: 0 diff --git a/docs/parameters.yaml b/docs/parameters.yaml index a6d202867be..64c3f1646f7 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -733,7 +733,7 @@ parameters: Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations. * 0: preserves the original algorithm (default). * 1: uses the local magnetization magnitude instead of the global quantization axis in the built-in GGA gradient correction. For LIBXC functionals, 0 and 1 are equivalent. - * 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the local-map Jacobian applied to the FFT gradients of the four density channels. The potential reverses this same discrete energy graph, including the radial Hessian and density/sigma clipping branches; the GGA stress uses the corresponding metric derivative. + * 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the FFT gradients of these mapped spin densities. The potential reverses this same discrete energy graph: apply the FFT divergence to each spin-channel flux, then apply the local-map Jacobian. Density/sigma clipping branches and the GGA metric stress derivative use the same mapped densities. This changes the finite-grid functional relative to projecting the four density-channel gradients; converged energies can therefore change. For r = |m| and x = r/eta, S_eta = eta*x^3*(3*x^2 - 8*x + 6) for r < eta, and S_eta = r otherwise. The regularization is part of the functional definition, including its first and second derivatives. Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior. default_value: "0" diff --git a/source/source_hamilt/module_xc/libxc_abacus.h b/source/source_hamilt/module_xc/libxc_abacus.h index d724837db00..7a5167a891c 100644 --- a/source/source_hamilt/module_xc/libxc_abacus.h +++ b/source/source_hamilt/module_xc/libxc_abacus.h @@ -30,15 +30,14 @@ namespace XC_Functional_Libxc // Complete forward data for the gga_grad=2 noncollinear Libxc graph: // rho_s = N_s(x), - // g_s = sum_A (d N_s / d x_A) G_h x_A. - // Keeping the local map and all input gradients together lets the reverse - // use the exact same branch choices and radial Hessian as the forward. + // g_s = G_h N_s(x). + // Reverse the FFT gradient before applying the local map Jacobian; + // this uses the same clipping branches as the forward energy. struct NclSfDiscreteData { std::vector spin_map; std::vector rho; std::vector>> spin_gradient; - std::array>, 3> grad_m; }; //------------------- @@ -133,7 +132,7 @@ namespace XC_Functional_Libxc const Charge* const chr); // Build the exact gga_grad=2 local spin map and, when requested, its - // projected FFT-gradient graph. LDA-only callers set need_gradient=false. + // mapped-density FFT-gradient graph. LDA-only callers set need_gradient=false. extern NclSfDiscreteData make_ncl_sf_discrete_data( const std::size_t nrxx, const double tpiba, diff --git a/source/source_hamilt/module_xc/libxc_tools.cpp b/source/source_hamilt/module_xc/libxc_tools.cpp index 579fd1409e0..031c2b4d44a 100644 --- a/source/source_hamilt/module_xc/libxc_tools.cpp +++ b/source/source_hamilt/module_xc/libxc_tools.cpp @@ -87,50 +87,9 @@ XC_Functional_Libxc::make_ncl_sf_discrete_data( return data; } - std::vector> grad_total(nrxx); - std::vector real_field(nrxx); - std::vector> reciprocal(chr->rhopw->npw); - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 1024) - #endif - for (std::size_t ir = 0; ir < nrxx; ++ir) - { - real_field[ir] = chr->rho[0][ir] + chr->rho_core[ir]; - } - chr->rhopw->real2recip(real_field.data(), reciprocal.data()); - XC_Functional::grad_rho( - reciprocal.data(), grad_total.data(), chr->rhopw, tpiba); - - for (int mu = 0; mu < 3; ++mu) - { - data.grad_m[mu].resize(nrxx); - chr->rhopw->real2recip(chr->rho[mu + 1], reciprocal.data()); - XC_Functional::grad_rho( - reciprocal.data(), data.grad_m[mu].data(), chr->rhopw, tpiba); - } - - data.spin_gradient.resize(nspin); - for (int spin = 0; spin < nspin; ++spin) - { - data.spin_gradient[spin].resize(nrxx); - } - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 512) - #endif - for (std::size_t ir = 0; ir < nrxx; ++ir) - { - for (int spin = 0; spin < nspin; ++spin) - { - ModuleBase::Vector3 gradient - = data.spin_map[ir].jacobian(spin, 0) * grad_total[ir]; - for (int mu = 0; mu < 3; ++mu) - { - gradient += data.spin_map[ir].jacobian(spin, mu + 1) - * data.grad_m[mu][ir]; - } - data.spin_gradient[spin][ir] = gradient; - } - } + // Differentiate the mapped spin densities with the actual FFT operator. + // The reverse must apply its adjoint before the local map Jacobian. + data.spin_gradient = cal_gdr(nspin, nrxx, data.rho, tpiba, chr); return data; } @@ -176,12 +135,9 @@ ModuleBase::matrix XC_Functional_Libxc::reverse_ncl_sf_discrete( { assert(data.spin_gradient[spin].size() == nrxx); } - for (int mu = 0; mu < 3; ++mu) - { - assert(data.grad_m[mu].size() == nrxx); - } - std::vector> h_up(nrxx), h_down(nrxx); + std::vector> h_up(nrxx); + std::vector> h_down(nrxx); #ifdef _OPENMP #pragma omp parallel for schedule(static, 512) #endif @@ -198,43 +154,20 @@ ModuleBase::matrix XC_Functional_Libxc::reverse_ncl_sf_discrete( + dsigma[sigma_index + 1] * data.spin_gradient[0][ir]); } - std::vector> flux(nrxx); - std::vector divergence(nrxx); - for (int channel = 0; channel < nchannel; ++channel) + std::vector divergence_up(nrxx); + std::vector divergence_down(nrxx); + XC_Functional::grad_dot(h_up.data(), divergence_up.data(), chr->rhopw, tpiba); + XC_Functional::grad_dot(h_down.data(), divergence_down.data(), chr->rhopw, tpiba); + #ifdef _OPENMP + #pragma omp parallel for schedule(static, 512) + #endif + for (std::size_t ir = 0; ir < nrxx; ++ir) { - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 512) - #endif - for (std::size_t ir = 0; ir < nrxx; ++ir) - { - flux[ir] - = data.spin_map[ir].jacobian(0, channel) * h_up[ir] - + data.spin_map[ir].jacobian(1, channel) * h_down[ir]; - } - XC_Functional::grad_dot( - flux.data(), divergence.data(), chr->rhopw, tpiba); - - #ifdef _OPENMP - #pragma omp parallel for schedule(static, 512) - #endif - for (std::size_t ir = 0; ir < nrxx; ++ir) + for (int channel = 0; channel < nchannel; ++channel) { - potential(channel, ir) -= divergence[ir]; - if (channel == 0 || data.spin_map[ir].saturated) - { - continue; - } - - const ModuleBase::Vector3 spin_flux - = 0.5 * (h_up[ir] - h_down[ir]); - double local_response = 0.0; - for (int nu = 0; nu < 3; ++nu) - { - local_response - += data.spin_map[ir].radial.jacobian(nu, channel - 1) - * (spin_flux * data.grad_m[nu][ir]); - } - potential(channel, ir) += local_response; + potential(channel, ir) + -= data.spin_map[ir].jacobian(0, channel) * divergence_up[ir] + + data.spin_map[ir].jacobian(1, channel) * divergence_down[ir]; } } return potential; diff --git a/source/source_hamilt/module_xc/test/test_xc_functional_ncgga_sf.cpp b/source/source_hamilt/module_xc/test/test_xc_functional_ncgga_sf.cpp index 3166ec625fa..4f6fc2bab16 100644 --- a/source/source_hamilt/module_xc/test/test_xc_functional_ncgga_sf.cpp +++ b/source/source_hamilt/module_xc/test/test_xc_functional_ncgga_sf.cpp @@ -274,6 +274,75 @@ TEST_P(RealPwNcgga, ZeroMagnetizationIsFinite) EXPECT_NEAR(std::get<2>(result)(c, ir), 0.0, 1e-13); } +// A local rotation preserves both mapped spin densities pointwise. This is +// stronger than global spin covariance and fails for J(x) G_h(x) at finite cutoff. +TEST_P(RealPwNcgga, LocalSpinRotationPreservesEnergyAndCovariesPotential) +{ + const VxcResult reference = evaluate(); + std::vector cosine(pw.nrxx); + std::vector sine(pw.nrxx); + for (int ir = 0; ir < pw.nrxx; ++ir) + { + const double angle = 0.7 * std::sin(0.31 * ir); + cosine[ir] = std::cos(angle); + sine[ir] = std::sin(angle); + const double mx = density[1][ir]; + const double my = density[2][ir]; + density[1][ir] = cosine[ir] * mx - sine[ir] * my; + density[2][ir] = sine[ir] * mx + cosine[ir] * my; + } + const VxcResult rotated = evaluate(); + EXPECT_NEAR(std::get<0>(reference), std::get<0>(rotated), 1e-10); + const ModuleBase::matrix& before = std::get<2>(reference); + const ModuleBase::matrix& after = std::get<2>(rotated); + for (int ir = 0; ir < pw.nrxx; ++ir) + { + const double expected_x = cosine[ir] * before(1, ir) - sine[ir] * before(2, ir); + const double expected_y = sine[ir] * before(1, ir) + cosine[ir] * before(2, ir); + EXPECT_NEAR(after(0, ir), before(0, ir), 1e-11); + EXPECT_NEAR(after(1, ir), expected_x, 1e-11); + EXPECT_NEAR(after(2, ir), expected_y, 1e-11); + EXPECT_NEAR(after(3, ir), before(3, ir), 1e-11); + } +} + +TEST_P(RealPwNcgga, ClippingBoundaryEnergyIsContinuous) +{ + // Each point reaches |m|=|n+core| together, while the spin direction varies. + const std::array, 4> original = density; + double previous_jump = 0.0; + for (int level = 0; level < 4; ++level) + { + const double epsilon = 1e-5 / (1 << level); + double energies[2]; + for (int side = 0; side < 2; ++side) + { + const double factor = side == 0 ? 1.0 - epsilon : 1.0 + epsilon; + for (int ir = 0; ir < pw.nrxx; ++ir) + { + const double mx = original[1][ir]; + const double my = original[2][ir]; + const double mz = original[3][ir]; + const double magnitude = std::sqrt(mx * mx + my * my + mz * mz); + const double target = factor * std::abs(density[0][ir] + core[ir]); + for (int c = 1; c < noncollinear_spin; ++c) + { + density[c][ir] = original[c][ir] * target / magnitude; + } + } + const VxcResult result = evaluate(); + energies[side] = std::get<0>(result); + } + const double jump = std::abs(energies[0] - energies[1]); + if (level > 0) + { + EXPECT_LE(jump, 0.6 * previous_jump + 1e-10); + } + previous_jump = jump; + } +} + + INSTANTIATE_TEST_SUITE_P(ProductionBranches, RealPwNcgga, testing::Combine(testing::Bool(), testing::Values(Smooth, Negative, Saturated, Radial))); } // namespace diff --git a/source/source_hamilt/module_xc/xc_functional_ncgga_sf.cpp b/source/source_hamilt/module_xc/xc_functional_ncgga_sf.cpp index 92808791ca9..8dd831a3eb2 100644 --- a/source/source_hamilt/module_xc/xc_functional_ncgga_sf.cpp +++ b/source/source_hamilt/module_xc/xc_functional_ncgga_sf.cpp @@ -25,9 +25,9 @@ std::tuple v_xc_ncgga_sf_builtin(const int& ModuleBase::TITLE("XC_Functional", "v_xc_ncgga_sf_builtin"); ModuleBase::timer::start("XC_Functional", "v_xc_ncgga_sf_builtin"); - // Regularized projected local-collinear energy: rho_s = N_s(n + rho_core, m), - // g_s = sum_A J_sA G_h x_A. Reverse the same discrete graph, including - // both -D_h(sum_s J_sA h_s) and the local Hessian response of N_s. + // Mapped local-collinear energy: rho_s = N_s(n + rho_core, m), + // g_s = G_h(rho_s). Reverse the FFT gradient before the local Jacobian: + // v_A = sum_s J_sA [f_rho_s - D_h(h_s)]. No discrete product rule is used. ModulePW::PW_Basis* rhopw = chr->rhopw; const int npw = rhopw->npw; const double e2 = ModuleBase::e2; @@ -52,42 +52,13 @@ std::tuple v_xc_ncgga_sf_builtin(const int& rhotmp2[ir] = spin_map[ir].spin_density[1]; } - std::vector> rhogsum1(npw); - std::vector> tmp_recip(npw); - rhopw->real2recip(chr->rho[0], rhogsum1.data()); - for (int ig = 0; ig < npw; ++ig) - rhogsum1[ig] += chr->rhog_core[ig]; - + std::vector> reciprocal(npw); std::vector> gdr1(nrxx); std::vector> gdr2(nrxx); - std::vector> grad_rho(nrxx); - std::array>, 3> grad_m; - for (int mu = 0; mu < 3; ++mu) - { - grad_m[mu].resize(nrxx); - } - std::vector> gdr_mag(nrxx); - XC_Functional::grad_rho(rhogsum1.data(), gdr1.data(), rhopw, tpiba); - - for (int ir = 0; ir < nrxx; ++ir) - { - grad_rho[ir] = gdr1[ir]; - - gdr1[ir] = spin_map[ir].jacobian(0, 0) * grad_rho[ir]; - gdr2[ir] = spin_map[ir].jacobian(1, 0) * grad_rho[ir]; - } - for (int is = 1; is <= 3; ++is) - { - rhopw->real2recip(chr->rho[is], tmp_recip.data()); - XC_Functional::grad_rho(tmp_recip.data(), gdr_mag.data(), rhopw, tpiba); - grad_m[is - 1] = gdr_mag; - for (int ir = 0; ir < nrxx; ++ir) - { - - gdr1[ir] += spin_map[ir].jacobian(0, is) * gdr_mag[ir]; - gdr2[ir] += spin_map[ir].jacobian(1, is) * gdr_mag[ir]; - } - } + rhopw->real2recip(rhotmp1.data(), reciprocal.data()); + XC_Functional::grad_rho(reciprocal.data(), gdr1.data(), rhopw, tpiba); + rhopw->real2recip(rhotmp2.data(), reciprocal.data()); + XC_Functional::grad_rho(reciprocal.data(), gdr2.data(), rhopw, tpiba); double etxc = 0; double vtxc = 0; @@ -180,33 +151,16 @@ std::tuple v_xc_ncgga_sf_builtin(const int& } } - std::vector dh(nrxx); - std::vector> tmp_h(nrxx); - - // Exact reverse of g_s=sum_A J_sA G_h(x_A): - // v_B = -D_h(sum_s J_sB h_s) - // + sum_s,A dJ_sA/dx_B h_s.G_h(x_A). - for (int channel = 0; channel < 4; ++channel) + std::vector divergence_up(nrxx); + std::vector divergence_down(nrxx); + XC_Functional::grad_dot(h1.data(), divergence_up.data(), rhopw, tpiba); + XC_Functional::grad_dot(h2.data(), divergence_down.data(), rhopw, tpiba); + for (int ir = 0; ir < nrxx; ++ir) { - for (int ir = 0; ir < nrxx; ++ir) - { - tmp_h[ir] = spin_map[ir].jacobian(0, channel) * h1[ir] + spin_map[ir].jacobian(1, channel) * h2[ir]; - } - XC_Functional::grad_dot(tmp_h.data(), dh.data(), rhopw, tpiba); - for (int ir = 0; ir < nrxx; ++ir) + for (int channel = 0; channel < 4; ++channel) { - v(channel, ir) -= dh[ir]; - if (channel == 0 || spin_map[ir].saturated) - { - continue; - } - const ModuleBase::Vector3 spin_flux = 0.5 * (h1[ir] - h2[ir]); - double local_response = 0.0; - for (int nu = 0; nu < 3; ++nu) - { - local_response += spin_map[ir].radial.jacobian(nu, channel - 1) * (spin_flux * grad_m[nu][ir]); - } - v(channel, ir) += local_response; + v(channel, ir) -= spin_map[ir].jacobian(0, channel) * divergence_up[ir] + + spin_map[ir].jacobian(1, channel) * divergence_down[ir]; } } @@ -214,7 +168,7 @@ std::tuple v_xc_ncgga_sf_builtin(const int& } // vtxc uses the same completed four-component potential returned to the - // caller. This unifies the bookkeeping for both modes. + // caller, including all four density channels. vtxc = 0.0; for (int ir = 0; ir < nrxx; ++ir) { @@ -247,49 +201,30 @@ void gradcorr_ncgga_lca_builtin(const Charge* const chr, const double e2 = ModuleBase::e2; constexpr double epsr = 1.0e-6; - // Rebuild the same complete local map used by the gga_grad=2 energy: - // rho_s = N_s(n + rho_core, m), - // g_s = sum_A dN_s/dx_A G_h x_A. - // Metric differentiation keeps the real-grid values x_A fixed, so the - // map Jacobian is unchanged and every G_h x_A transforms covariantly. + // Use exactly the spin-density gradients in the discrete XC energy. + // For a metric variation, fixed real-grid spin densities remain fixed. std::vector spin_map(nrxx); - std::array>, 4> field_gradient; - for (int channel = 0; channel < 4; ++channel) + for (int ir = 0; ir < nrxx; ++ir) { - field_gradient[channel].resize(nrxx); + const std::array magnetization + = {{chr->rho[1][ir], chr->rho[2][ir], chr->rho[3][ir]}}; + const double eta = ncgga_lca_radial_eta(); + const NcggaRadialPoint radial = make_ncgga_radial_point(magnetization, eta); + const double total_density = chr->rho[0][ir] + chr->rho_core[ir]; + spin_map[ir] = make_ncgga_spin_map_point(total_density, radial); } std::array>, 2> spin_gradient; + std::vector spin_density(nrxx); + std::vector> reciprocal(npw); for (int spin = 0; spin < 2; ++spin) { spin_gradient[spin].resize(nrxx); - } - - std::vector> reciprocal(npw); - rhopw->real2recip(chr->rho[0], reciprocal.data()); - for (int ig = 0; ig < npw; ++ig) - { - reciprocal[ig] += chr->rhog_core[ig]; - } - XC_Functional::grad_rho(reciprocal.data(), field_gradient[0].data(), rhopw, tpiba); - - for (int channel = 1; channel < 4; ++channel) - { - rhopw->real2recip(chr->rho[channel], reciprocal.data()); - XC_Functional::grad_rho(reciprocal.data(), field_gradient[channel].data(), rhopw, tpiba); - } - - for (int ir = 0; ir < nrxx; ++ir) - { - const std::array magnetization = {{chr->rho[1][ir], chr->rho[2][ir], chr->rho[3][ir]}}; - spin_map[ir] = make_ncgga_spin_map_point(chr->rho[0][ir] + chr->rho_core[ir], - make_ncgga_radial_point(magnetization, ncgga_lca_radial_eta())); - for (int spin = 0; spin < 2; ++spin) + for (int ir = 0; ir < nrxx; ++ir) { - for (int channel = 0; channel < 4; ++channel) - { - spin_gradient[spin][ir] += spin_map[ir].jacobian(spin, channel) * field_gradient[channel][ir]; - } + spin_density[ir] = spin_map[ir].spin_density[spin]; } + rhopw->real2recip(spin_density.data(), reciprocal.data()); + XC_Functional::grad_rho(reciprocal.data(), spin_gradient[spin].data(), rhopw, tpiba); } for (int ir = 0; ir < nrxx; ++ir) diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index f6465f89293..b1a78a1b5f9 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -87,7 +87,7 @@ struct Input_para double nelec_delta = 0.0; ///< change in the number of total electrons double nupdown = 0.0; std::string dft_functional = "default"; ///< input DFT functional. - int gga_grad = 0; ///< Noncollinear GGA: 0 original, 1 local axis, 2 regularized projected LCA. + int gga_grad = 0; ///< Noncollinear GGA: 0 original, 1 local axis, 2 regularized mapped-density LCA. double xc_temperature = 0.0; ///< only relevant if finite temperature functional is used double pseudo_rcut = 15.0; ///< cut-off radius for calculating msh bool pseudo_mesh = false; ///< 0: use msh to normalize radial wave functions; 1: diff --git a/source/source_io/module_parameter/read_inp_estruc.cpp b/source/source_io/module_parameter/read_inp_estruc.cpp index 5da535085ca..b5841a81e31 100644 --- a/source/source_io/module_parameter/read_inp_estruc.cpp +++ b/source/source_io/module_parameter/read_inp_estruc.cpp @@ -492,13 +492,13 @@ The other way is only available when compiling with LIBXC, and it allows for sup } { Input_Item item("gga_grad"); - item.annotation = "Noncollinear GGA gradient method: 0 original, 1 local axis, 2 regularized projected LCA"; + item.annotation = "Noncollinear GGA gradient method: 0 original, 1 local axis, 2 regularized mapped-density LCA"; item.category = "Electronic structure"; item.type = "Integer"; item.description = R"(Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations. * 0: preserves the original algorithm (default). * 1: uses the local magnetization magnitude instead of the global quantization axis in the built-in GGA gradient correction. For LIBXC functionals, 0 and 1 are equivalent. -* 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the local-map Jacobian applied to the FFT gradients of the four density channels. The potential reverses this same discrete energy graph, including the radial Hessian and density/sigma clipping branches; the GGA stress uses the corresponding metric derivative. +* 2: uses a C2-regularized magnetization magnitude with eta = 1e-3 in atomic density units. The spin densities are (abs(n + rho_core) +/- min(S_eta(m), abs(n + rho_core)))/2. GGA gradients are the FFT gradients of these mapped spin densities. The potential reverses this same discrete energy graph: apply the FFT divergence to each spin-channel flux, then apply the local-map Jacobian. Density/sigma clipping branches and the GGA metric stress derivative use the same mapped densities. This changes the finite-grid functional relative to projecting the four density-channel gradients; converged energies can therefore change. For r = |m| and x = r/eta, S_eta = eta*x^3*(3*x^2 - 8*x + 6) for r < eta, and S_eta = r otherwise. The regularization is part of the functional definition, including its first and second derivatives. Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior.)"; item.default_value = "0"; From 67b0e1914adbaaeb38a73375e7aed9da94ff4c44 Mon Sep 17 00:00:00 2001 From: Chen Chengbing <1747193328@qq.com> Date: Tue, 13 Oct 2026 11:24:29 +0800 Subject: [PATCH 2/5] test: stabilize weak-moment gga_grad=2 SCF reference --- tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT | 10 +++++----- tests/01_PW/038_PW_NC_GGA_GRAD2/README | 23 +++++++++++++++++++++- tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref | 10 +++++----- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT b/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT index 0cd42b8d630..5e1566fd736 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT @@ -15,7 +15,8 @@ cal_stress 1 # plane wave and scf ecutwfc 20 pw_seed 1 -scf_thr 1.0e-10 +# Tight charge convergence stabilizes force/stress in the weak-moment limit. +scf_thr 1.0e-14 scf_nmax 150 out_chg 0 @@ -28,10 +29,9 @@ mixing_type broyden mixing_beta 0.2 mixing_ndim 10 -# diagonalizaiton -ks_solver dav_subspace -diago_smooth_ethr true -pw_diag_ndim 2 +# diagonalization +# BPCG avoids Davidson near-null residual failures at this tight SCF threshold. +ks_solver bpcg # directories pseudo_dir ../../PP_ORB diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/README b/tests/01_PW/038_PW_NC_GGA_GRAD2/README index 93236854c77..cbe27256948 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/README +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/README @@ -1,7 +1,7 @@ PBE noncollinear Fe2 regression for gga_grad=2, including forces and stress. Derived from 038_PW_NC with different initial spin directions on the two atoms, -explicit PBE/gga_grad settings, and scf_thr=1e-10. +explicit PBE/gga_grad settings, BPCG, and scf_thr=1e-14. The initial moments point in different directions and decay towards zero during SCF. This case exercises the noncollinear path including its weak-moment limit; it is not a regression for a stable magnetic ground state. @@ -14,3 +14,24 @@ result.ref is generated with one MPI rank using the same command with -n 1 -g. The reference covers energy per atom, the force summary, and the stress summary. Default Autotest tolerances apply; no case-specific threshold overrides are used. This SCF regression complements the XC module's density/stress derivative tests. + +Reference uses the mapped-density FFT definition of gga_grad=2. At the previous +scf_thr=1e-10, changing the XC iteration trajectory left force/stress differences +larger than the regression tolerances even though total energies agreed within +1e-9 eV. Using BPCG with scf_thr=1e-14 reduces that terminal-state sensitivity; +the energy/force/stress comparison tolerances remain unchanged. + +The reference was regenerated with one CPU MPI rank. CPU four-rank and GPU +one-rank runs agree within the default tolerances. These are reproducibility +checks of the converged SCF output, not absolute force/stress accuracy bounds. + +BPCG is used because tight-threshold Davidson probes stopped with psi_norm <= 0 +on CPU and GPU. No eigensolver implementation or production default is changed. +At these settings, upstream and mapped-density CPU references have identical +energy/force/stress fingerprints at the reported precision. All eight displaced +and strained corners converged for each XC implementation. Force finite-difference +errors are 2.80e-5 and 4.24e-5 eV/Angstrom for displacements of 0.002 and 0.001 +Angstrom; xx stress errors are 0.0168 and 0.0171 kbar for strains of 1e-4 and 5e-5. +These residual errors are the same for both XC implementations: this weak-moment, +20-Ry SCF fixture does not establish absolute stress derivative closure or replace +the finite-magnetization XC module derivative tests. diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref b/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref index b21347b5a09..8f408788549 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref @@ -1,5 +1,5 @@ -etotref -6178.4040535332069339 -etotperatomref -3089.2020267666 -totalforceref 18.267150 -totalstressref 73803.586958 -totaltimeref 1.47 +etotref -6178.4040535320500567 +etotperatomref -3089.2020267660 +totalforceref 18.270388 +totalstressref 73803.529922 +totaltimeref 3.70 From 0e6337bf489ac1aa6b3b2d5ef8083ef9a80b3eca Mon Sep 17 00:00:00 2001 From: Chen Chengbing <1747193328@qq.com> Date: Tue, 13 Oct 2026 12:01:10 +0800 Subject: [PATCH 3/5] test: refresh LCAO references for mapped-density XC --- tests/03_NAO_multik/scf_deltaspin4/README | 15 +++++++++++++++ tests/03_NAO_multik/scf_deltaspin4/result.ref | 10 +++++----- tests/03_NAO_multik/scf_gga_grad2_spin4/README | 11 +++++++++++ .../03_NAO_multik/scf_gga_grad2_spin4/result.ref | 8 ++++---- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/tests/03_NAO_multik/scf_deltaspin4/README b/tests/03_NAO_multik/scf_deltaspin4/README index a558c307f4f..64c41c8fca1 100644 --- a/tests/03_NAO_multik/scf_deltaspin4/README +++ b/tests/03_NAO_multik/scf_deltaspin4/README @@ -1,2 +1,17 @@ Test LCAO DeltaSpin with SOC and nonparallel xyz target moments of magnitude 3 mu_B (nspin=4). Check the two-overlap product-rule force regression at 12 Ry with at most 10 SCF steps. + +This is a fixed-budget trajectory regression: scf_nmax=10 is intentional, and +neither the upstream nor mapped-density XC run reaches SCF convergence. Its +energy, force, and stress fingerprints must not be presented as converged-state +values or finite-difference validation. + +The reference uses the mapped-density FFT definition of gga_grad=2. Rebuilding +only the upstream XC files reproduces the previous projected-gradient reference. +At step 10, the mapped trajectory changes the two-atom energy by -0.1827584227 eV, +the absolute-component force sum from 99.992332 to 93.374790 eV/Angstrom, and the +stress sum from 30048.363075 to 30504.021979 kbar. These changes include the +self-consistent density/constraint trajectory response, not just a direct XC +term at fixed density. One- and four-rank CPU results pass the default comparison +tolerances. INPUT, iteration budget, constraint settings, force implementation, +and comparison tolerances are unchanged. diff --git a/tests/03_NAO_multik/scf_deltaspin4/result.ref b/tests/03_NAO_multik/scf_deltaspin4/result.ref index 72f041c4738..893408a71a9 100644 --- a/tests/03_NAO_multik/scf_deltaspin4/result.ref +++ b/tests/03_NAO_multik/scf_deltaspin4/result.ref @@ -1,5 +1,5 @@ -etotref -6807.6151554089874480 -etotperatomref -3403.8075777045 -totalforceref 99.992332 -totalstressref 30048.363075 -totaltimeref 27.24 +etotref -6807.7979138316131866 +etotperatomref -3403.8989569158 +totalforceref 93.374790 +totalstressref 30504.021979 +totaltimeref 20.14 diff --git a/tests/03_NAO_multik/scf_gga_grad2_spin4/README b/tests/03_NAO_multik/scf_gga_grad2_spin4/README index 82b3862c15d..4db3cc56d27 100644 --- a/tests/03_NAO_multik/scf_gga_grad2_spin4/README +++ b/tests/03_NAO_multik/scf_gga_grad2_spin4/README @@ -7,3 +7,14 @@ From tests/03_NAO_multik, run: Generate result.ref with the same command using -n 1 -g. Default energy, force and stress tolerances apply; no threshold overrides are used. + +The reference uses the mapped-density FFT definition of gga_grad=2. A matched +rebuild with the upstream projected-gradient XC reproduces the previous reference; +the mapped definition raises the converged two-atom energy by 0.1075335933 eV +(53.7668 meV/atom) at this deliberately low 15-Ry cutoff. Its absolute-component +stress sum changes from 3941.148224 to 3873.105155 kbar; this sum is a regression +fingerprint, not a stress-component error or an accuracy bound. Both definitions +converge with the unchanged INPUT. One- and four-rank CPU results agree within +the default tolerances, without solver, SCF, or comparison-threshold changes. +This low-cutoff finite-grid difference should not be generalized to converged +cutoffs or interpreted as a uniform energy offset across materials. diff --git a/tests/03_NAO_multik/scf_gga_grad2_spin4/result.ref b/tests/03_NAO_multik/scf_gga_grad2_spin4/result.ref index d7fc08c4f23..9f96fddeb04 100644 --- a/tests/03_NAO_multik/scf_gga_grad2_spin4/result.ref +++ b/tests/03_NAO_multik/scf_gga_grad2_spin4/result.ref @@ -1,5 +1,5 @@ -etotref -6267.5006750326140000 -etotperatomref -3133.7503375163 +etotref -6267.3931414394364765 +etotperatomref -3133.6965707197 totalforceref 0.000000 -totalstressref 3941.148224 -totaltimeref 5.57 +totalstressref 3873.105155 +totaltimeref 3.05 From c9e6aa8dad5e76e917b5cdcc524dccc8956a7bdc Mon Sep 17 00:00:00 2001 From: Chen Chengbing <1747193328@qq.com> Date: Tue, 13 Oct 2026 16:42:02 +0800 Subject: [PATCH 4/5] Use finite-moment distorted bcc Fe for the NC GGA regression --- tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT | 64 +++++++++------------ tests/01_PW/038_PW_NC_GGA_GRAD2/KPT | 2 +- tests/01_PW/038_PW_NC_GGA_GRAD2/README | 65 +++++++++++----------- tests/01_PW/038_PW_NC_GGA_GRAD2/STRU | 17 +++--- tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref | 10 ++-- 5 files changed, 76 insertions(+), 82 deletions(-) diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT b/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT index 5e1566fd736..bb7c38e93d8 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/INPUT @@ -1,38 +1,28 @@ INPUT_PARAMETERS - -init_wfc random -# PBE noncollinear GGA gradient regression -basis_type pw -calculation scf -noncolin 1 -nspin 4 -dft_functional pbe -gga_grad 2 -symmetry 0 -cal_force 1 -cal_stress 1 - -# plane wave and scf -ecutwfc 20 -pw_seed 1 -# Tight charge convergence stabilizes force/stress in the weak-moment limit. -scf_thr 1.0e-14 -scf_nmax 150 -out_chg 0 - -# smearing method -smearing_method gaussian -smearing_sigma 0.02 - -# charge mixing method -mixing_type broyden -mixing_beta 0.2 -mixing_ndim 10 - -# diagonalization -# BPCG avoids Davidson near-null residual failures at this tight SCF threshold. -ks_solver bpcg - -# directories -pseudo_dir ../../PP_ORB -suffix autotest +suffix autotest +calculation scf +basis_type pw +device cpu +init_wfc atomic +pw_seed 1 +noncolin 1 +nspin 4 +dft_functional pbe +gga_grad 2 +symmetry 0 +cal_force 1 +cal_stress 1 +ecutwfc 20 +scf_thr 1e-10 +scf_nmax 100 +out_chg 0 +smearing_method gaussian +smearing_sigma 0.01 +mixing_type broyden +mixing_beta 0.2 +mixing_ndim 10 +ks_solver dav +kpar 1 +pseudo_dir ../../PP_ORB +nbands 40 +lspinorb 0 diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/KPT b/tests/01_PW/038_PW_NC_GGA_GRAD2/KPT index b5b3bdb1ae2..f5f7f4ec34c 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/KPT +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/KPT @@ -1,4 +1,4 @@ K_POINTS 0 Gamma -1 1 2 0 0 0 +2 2 2 0 0 0 diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/README b/tests/01_PW/038_PW_NC_GGA_GRAD2/README index cbe27256948..2dff9d98e0f 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/README +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/README @@ -1,37 +1,40 @@ -PBE noncollinear Fe2 regression for gga_grad=2, including forces and stress. +Finite-moment ferromagnetic bcc Fe regression for PBE, nspin=4, gga_grad=2. -Derived from 038_PW_NC with different initial spin directions on the two atoms, -explicit PBE/gga_grad settings, BPCG, and scf_thr=1e-14. -The initial moments point in different directions and decay towards zero during -SCF. This case exercises the noncollinear path including its weak-moment limit; -it is not a regression for a stable magnetic ground state. -The pseudopotential is reused from tests/PP_ORB; no numerical orbitals are needed. +The two-atom cubic cell has a lattice constant of approximately 2.87 Angstrom. +The body-centre atom is displaced from (0.5, 0.5, 0.5) to (0.503, 0.502, 0.499) +so all three atomic-force components are nonzero. Both initial moments are +(1.32, 1.056, 1.408) uB: a common tilted FM direction, not magnetic constraints. +No DeltaSpin, onsite projection, numerical orbitals, or SOC is enabled. +The converged total moment is approximately (2.70, 2.16, 2.88) uB/cell, +with magnitude 4.5 uB (cell-average 2.25 uB/Fe, not an atom-projected moment). -From tests/01_PW, run: - OMP_NUM_THREADS=1 bash ../integrate/Autotest.sh -a /path/to/abacus -n 4 -r '^038_PW_NC_GGA_GRAD2$' +The existing Fe.upf contains PP_PSWFC data, allowing genuine atomic wavefunction +initialization. The previous Fe_ONCV_PBE-1.0.upf has no atomic wavefunctions and +would fall back to random initialization. No new pseudopotential is added. +The test uses 20 Ry, a 2x2x2 Gamma-centred k mesh, 40 spinor bands, Gaussian +smearing of 0.01 Ry, Davidson, and scf_thr=1e-10. The deliberately coarse basis +is for regression cost, not converged material energies, forces, or pressure. +In particular, the large coarse-basis pressure is not a physical bcc Fe result. -result.ref is generated with one MPI rank using the same command with -n 1 -g. -The reference covers energy per atom, the force summary, and the stress summary. -Default Autotest tolerances apply; no case-specific threshold overrides are used. -This SCF regression complements the XC module's density/stress derivative tests. +This replaces the previous near-zero-moment Fe2 fixture and its scf_thr=1e-14. +The new state is globally tilted and approximately collinear; it does not test +a spatially nonparallel spin texture. Weak-moment, clipping, local-rotation, +and density/metric-stress derivative coverage remains in the XC module tests. -Reference uses the mapped-density FFT definition of gga_grad=2. At the previous -scf_thr=1e-10, changing the XC iteration trajectory left force/stress differences -larger than the regression tolerances even though total energies agreed within -1e-9 eV. Using BPCG with scf_thr=1e-14 reduces that terminal-state sensitivity; -the energy/force/stress comparison tolerances remain unchanged. +From tests/01_PW, run: + OMP_NUM_THREADS=1 bash ../integrate/Autotest.sh -a /path/to/abacus -n 4 -o 1 -r '^038_PW_NC_GGA_GRAD2$' -The reference was regenerated with one CPU MPI rank. CPU four-rank and GPU -one-rank runs agree within the default tolerances. These are reproducibility -checks of the converged SCF output, not absolute force/stress accuracy bounds. +result.ref was generated with one CPU MPI rank, using -n 1 -g. CPU four-rank +and GPU one-rank runs pass against it with the unchanged default tolerances: +1e-7 eV for energy, 1e-4 eV/Angstrom for the force fingerprint, and 1e-3 kbar +for the stress fingerprint. Use device=gpu in a separate copy for the GPU run. +All three runs explicitly converge in 18 SCF steps. The full Autotest invocations +took 5.41, 3.67, and 7.69 seconds, respectively, on the tested V100 node (OMP=1). +These single-run times include launch/harness overhead, not queue/build time. -BPCG is used because tight-threshold Davidson probes stopped with psi_norm <= 0 -on CPU and GPU. No eigensolver implementation or production default is changed. -At these settings, upstream and mapped-density CPU references have identical -energy/force/stress fingerprints at the reported precision. All eight displaced -and strained corners converged for each XC implementation. Force finite-difference -errors are 2.80e-5 and 4.24e-5 eV/Angstrom for displacements of 0.002 and 0.001 -Angstrom; xx stress errors are 0.0168 and 0.0171 kbar for strains of 1e-4 and 5e-5. -These residual errors are the same for both XC implementations: this weak-moment, -20-Ry SCF fixture does not establish absolute stress derivative closure or replace -the finite-magnetization XC module derivative tests. +The force/stress fingerprints are sums of absolute components, not vector norms +or derivative-error bounds. Relative to CPU1, the largest fingerprint deviations +are 2e-6 eV/Angstrom and 1.7e-5 kbar. These are reproducibility checks, not new +end-to-end finite-difference validation. No test comparison tolerance is relaxed. +The reference must change because both the physical fixture and XC definition +have changed; it must not be compared directly with the retired Fe2 reference. diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/STRU b/tests/01_PW/038_PW_NC_GGA_GRAD2/STRU index 29ad1c21031..bfb2a7c486f 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/STRU +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/STRU @@ -1,18 +1,19 @@ ATOMIC_SPECIES -Fe 1.000 Fe_ONCV_PBE-1.0.upf +Fe 55.845 Fe.upf LATTICE_CONSTANT -6 +5.423505388 LATTICE_VECTORS -1.00 0.00 0.00 -0.00 1.00 0.00 -0.00 0.00 1.00 +1 0 0 +0 1 0 +0 0 1 + ATOMIC_POSITIONS Direct Fe -1.0 +0.0 2 -0.00 0.00 0.00 1 1 1 angle1 90 angle2 0 -0.51 0.52 0.53 1 1 1 angle1 70 angle2 60 +0 0 0 1 1 1 mag 1.32 1.056 1.408 +0.503 0.502 0.499 1 1 1 mag 1.32 1.056 1.408 diff --git a/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref b/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref index 8f408788549..759c3323cba 100644 --- a/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref +++ b/tests/01_PW/038_PW_NC_GGA_GRAD2/result.ref @@ -1,5 +1,5 @@ -etotref -6178.4040535320500567 -etotperatomref -3089.2020267660 -totalforceref 18.270388 -totalstressref 73803.529922 -totaltimeref 3.70 +etotref -6381.1849537505986518 +etotperatomref -3190.5924768753 +totalforceref 0.286246 +totalstressref 105523.013516 +totaltimeref 2.32 From bf2e862bc7da97d5cab28b858fdff471119440d1 Mon Sep 17 00:00:00 2001 From: Chen Chengbing <1747193328@qq.com> Date: Wed, 14 Oct 2026 14:32:57 +0800 Subject: [PATCH 5/5] docs(xc): align mapped-density graph comments with implementation --- source/source_hamilt/module_xc/libxc_abacus.h | 1 - source/source_hamilt/module_xc/libxc_pot.cpp | 17 +++++++++-------- .../module_xc/xc_functional_ncgga_sf.h | 4 ++-- source/source_hamilt/module_xc/xc_pot.cpp | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/source_hamilt/module_xc/libxc_abacus.h b/source/source_hamilt/module_xc/libxc_abacus.h index 7a5167a891c..b4541c8a9e0 100644 --- a/source/source_hamilt/module_xc/libxc_abacus.h +++ b/source/source_hamilt/module_xc/libxc_abacus.h @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/source/source_hamilt/module_xc/libxc_pot.cpp b/source/source_hamilt/module_xc/libxc_pot.cpp index 9dd5c84dc9e..eb4275cf5e3 100644 --- a/source/source_hamilt/module_xc/libxc_pot.cpp +++ b/source/source_hamilt/module_xc/libxc_pot.cpp @@ -40,7 +40,7 @@ void XC_Functional_Libxc::gradcorr_ncgga_sf_libxc(const std::vector& func_i } // This is the same forward graph used by v_xc_libxc: the local spin map, - // its projected FFT gradients, and the sigma invariants are constructed + // FFT gradients of the mapped densities, and the sigma invariants are constructed // once and shared by all Libxc components. const XC_Functional_Libxc::NclSfDiscreteData sf_data = XC_Functional_Libxc::make_ncl_sf_discrete_data(nrxx, tpiba, chr, true); @@ -105,10 +105,11 @@ void XC_Functional_Libxc::gradcorr_ncgga_sf_libxc(const std::vector& func_i } } -// For g_s=sum_A J_sA G_h x_A, a reciprocal deformation changes G_h but -// not the pointwise map J. Therefore the metric derivative is exactly -// sum_s h_s,l g_s,m, with h_s=dE/dg_s built from the sanitizer-reversed, -// component-scaled aggregate above. + // For g_s = G_h N_s(x), a reciprocal-metric variation at fixed real-grid + // density values changes G_h while holding N_s(x) fixed. The gradient-metric + // contribution is sum_s h_s,l g_s,m, with h_s = df/dg_s built from the + // sanitizer-reversed, component-scaled aggregate above. This is only the + // gradient-metric contribution, not the full cell-strain derivative. #ifdef _OPENMP #pragma omp parallel { @@ -200,7 +201,7 @@ std::tuple XC_Functional_Libxc::v_xc_libxc( const int nspin = (nspin_in == 1 || (nspin_in == 4 && !domag && !domag_z)) ? 1 : 2; // For nspin=4 with noncollinear magnetism, gga_grad=2 selects the - // regularized projected local-collinear graph; gga_grad=0/1 keeps the + // regularized mapped-density local-collinear graph; gga_grad=0/1 keeps the // original collinear algorithm. const bool has_mag = domag || domag_z; const bool use_lca = (nspin_in == 4) && has_mag && gga_grad == 2; @@ -246,7 +247,7 @@ std::tuple XC_Functional_Libxc::v_xc_libxc( else if (use_lca) { // gga_grad=2 uses one complete local map for both the Libxc density - // input and the projected FFT-gradient graph. LDA-only functionals + // input and the mapped-density FFT-gradient graph. LDA-only functionals // need the same local map but do not pay for gradients. sf_data = XC_Functional_Libxc::make_ncl_sf_discrete_data(nrxx, tpiba, chr, is_gga); rho = sf_data.rho; @@ -372,7 +373,7 @@ std::tuple XC_Functional_Libxc::v_xc_libxc( // Keep the established energy accumulation and reduction order. In // gga_grad=2, reverse every sanitizer now, apply the component scaling, - // and aggregate before traversing the shared projected graph once. + // and aggregate before reversing the shared mapped-density graph once. etxc += XC_Functional_Libxc::convert_etxc(nspin, nrxx, energy_mask, rho, exc) * factor; if (use_lca) { diff --git a/source/source_hamilt/module_xc/xc_functional_ncgga_sf.h b/source/source_hamilt/module_xc/xc_functional_ncgga_sf.h index c4d71a28ad7..5ae1372cd22 100644 --- a/source/source_hamilt/module_xc/xc_functional_ncgga_sf.h +++ b/source/source_hamilt/module_xc/xc_functional_ncgga_sf.h @@ -17,13 +17,13 @@ namespace ModuleXC namespace NCGGA_SF_Builtin { -// Exact discrete reverse of the regularized projected LCA graph (gga_grad=2). +// Exact discrete reverse of the regularized mapped-density LCA graph (gga_grad=2). std::tuple v_xc_ncgga_sf_builtin(const int& nrxx, const double& omega, const double tpiba, const Charge* const chr); -// Gradient-metric stress of the exact gga_grad=2 projected-LCA graph. The +// Gradient-metric stress of the exact gga_grad=2 mapped-density LCA graph. The // returned lower triangle is the unnormalised real-grid sum; Stress_Func // applies the existing pool reduction and 1/nxyz normalisation. void gradcorr_ncgga_lca_builtin(const Charge* const chr, diff --git a/source/source_hamilt/module_xc/xc_pot.cpp b/source/source_hamilt/module_xc/xc_pot.cpp index f8b54bde2dd..278de827546 100644 --- a/source/source_hamilt/module_xc/xc_pot.cpp +++ b/source/source_hamilt/module_xc/xc_pot.cpp @@ -53,7 +53,7 @@ std::tuple XC_Functional::v_xc( #endif } - // Evaluate the regularized projected local-collinear graph. + // Evaluate the regularized mapped-density local-collinear graph. if (nspin == 4 && (domag || domag_z) && gga_grad == 2) { return ModuleXC::NCGGA_SF_Builtin::v_xc_ncgga_sf_builtin(nrxx, ucell->omega, ucell->tpiba, chr);