Skip to content

Commit eeb18c5

Browse files
aboys-cbdyzheng
andcommitted
feat(xc): add gga_grad 1 and 2 with discrete variational potentials
Based-on: deepmodeling#7758 Co-authored-by: dyzheng <zhengdy@aisi.ac.cn>
1 parent 0f95611 commit eeb18c5

27 files changed

Lines changed: 2984 additions & 179 deletions

docs/advanced/input_files/input-main.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
- [pseudo\_rcut](#pseudo_rcut)
9595
- [pseudo\_mesh](#pseudo_mesh)
9696
- [nspin](#nspin)
97+
- [gga\_grad](#gga_grad)
9798
- [smearing\_method](#smearing_method)
9899
- [smearing\_sigma](#smearing_sigma)
99100
- [smearing\_sigma\_temp](#smearing_sigma_temp)
@@ -1326,6 +1327,17 @@
13261327
- 4: Noncollinear or spin-orbit calculations. Set nspin to 4 explicitly when noncolin or lspinorb is enabled.
13271328
- **Default**: 1
13281329

1330+
### gga_grad
1331+
1332+
- **Type**: Integer
1333+
- **Description**: Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations.
1334+
- 0: preserves the original algorithm (default).
1335+
- 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.
1336+
- 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.
1337+
For r = |m| and x = r/eta, S_eta = eta*x^3*(3*x^2 - 8*x + 6) for r &lt; eta, and S_eta = r otherwise. The regularization is part of the functional definition, including its first and second derivatives.
1338+
Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior.
1339+
- **Default**: 0
1340+
13291341
### smearing_method
13301342

13311343
- **Type**: String

docs/parameters.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,19 @@ parameters:
686686
default_value: "1"
687687
unit: ""
688688
availability: ""
689+
- name: gga_grad
690+
category: Electronic structure
691+
type: Integer
692+
description: |
693+
Selects the local spin mapping for LDA/GGA functionals in magnetic nspin=4 calculations.
694+
* 0: preserves the original algorithm (default).
695+
* 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.
696+
* 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.
697+
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.
698+
Mode 2 also uses this local map for the LDA contribution. Other spin configurations retain their existing behavior.
699+
default_value: "0"
700+
unit: ""
701+
availability: ""
689702
- name: smearing_method
690703
category: Electronic structure
691704
type: String

source/source_estate/module_pot/pot_xc.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ namespace elecstate
1414

1515
void PotXC::cal_v_eff(const Charge*const chg, const UnitCell*const ucell, ModuleBase::matrix& v_eff)
1616
{
17+
const Parameter& parameters = PARAM;
1718
ModuleBase::TITLE("PotXC", "cal_veff");
1819
ModuleBase::timer::start("PotXC", "cal_veff");
1920
const int nrxx_current = chg->nrxx;
21+
const int nspin = parameters.inp.nspin;
2022

2123
//----------------------------------------------------------
2224
// calculate the exchange-correlation potential
@@ -33,7 +35,7 @@ void PotXC::cal_v_eff(const Charge*const chg, const UnitCell*const ucell, Module
3335
#endif
3436
const std::tuple<double, double, ModuleBase::matrix, ModuleBase::matrix> etxc_vtxc_v
3537
= XC_Functional_Libxc::v_xc_meta(XC_Functional::get_func_id(), nrxx_current, ucell->omega, ucell->tpiba, chg,
36-
PARAM.inp.nspin, hybrid_alpha, hse_omega);
38+
nspin, hybrid_alpha, hse_omega);
3739
*(this->etxc_) = std::get<0>(etxc_vtxc_v);
3840
*(this->vtxc_) = std::get<1>(etxc_vtxc_v);
3941
v_eff += std::get<2>(etxc_vtxc_v);
@@ -52,9 +54,10 @@ void PotXC::cal_v_eff(const Charge*const chg, const UnitCell*const ucell, Module
5254
#endif
5355
const std::tuple<double, double, ModuleBase::matrix> etxc_vtxc_v
5456
= XC_Functional::v_xc(nrxx_current, chg, ucell,
55-
PARAM.inp.nspin,
56-
PARAM.globalv.domag,
57-
PARAM.globalv.domag_z,
57+
nspin,
58+
parameters.globalv.domag,
59+
parameters.globalv.domag_z,
60+
parameters.inp.gga_grad,
5861
hybrid_alpha,
5962
hse_omega);
6063
*(this->etxc_) = std::get<0>(etxc_vtxc_v);

source/source_estate/module_pot/pot_xc_fdm.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ PotXC_FDM::PotXC_FDM(
1616
const UnitCell*const ucell)
1717
: chg_0(chg_0_in)
1818
{
19+
const Parameter& parameters = PARAM;
1920
this->rho_basis_ = rho_basis_in;
2021
this->dynamic_mode = true;
2122
this->fixed_mode = false;
@@ -28,9 +29,10 @@ PotXC_FDM::PotXC_FDM(
2829
#endif
2930
const std::tuple<double, double, ModuleBase::matrix> etxc_vtxc_v_0
3031
= XC_Functional::v_xc(this->chg_0->nrxx, this->chg_0, ucell,
31-
PARAM.inp.nspin,
32-
PARAM.globalv.domag,
33-
PARAM.globalv.domag_z,
32+
parameters.inp.nspin,
33+
parameters.globalv.domag,
34+
parameters.globalv.domag_z,
35+
parameters.inp.gga_grad,
3436
hybrid_alpha,
3537
hse_omega);
3638
this->v_xc_0 = std::get<2>(etxc_vtxc_v_0);
@@ -41,6 +43,7 @@ void PotXC_FDM::cal_v_eff(
4143
const UnitCell*const ucell,
4244
ModuleBase::matrix& v_eff)
4345
{
46+
const Parameter& parameters = PARAM;
4447
ModuleBase::TITLE("PotXC_FDM", "cal_veff");
4548
ModuleBase::timer::start("PotXC_FDM", "cal_veff");
4649

@@ -66,9 +69,10 @@ void PotXC_FDM::cal_v_eff(
6669
#endif
6770
const std::tuple<double, double, ModuleBase::matrix> etxc_vtxc_v_01
6871
= XC_Functional::v_xc(chg_01.nrxx, &chg_01, ucell,
69-
PARAM.inp.nspin,
70-
PARAM.globalv.domag,
71-
PARAM.globalv.domag_z,
72+
parameters.inp.nspin,
73+
parameters.globalv.domag,
74+
parameters.globalv.domag_z,
75+
parameters.inp.gga_grad,
7276
hybrid_alpha,
7377
hse_omega);
7478
const ModuleBase::matrix &v_xc_01 = std::get<2>(etxc_vtxc_v_01);

source/source_hamilt/module_xc/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
add_library(
22
xc_
33
OBJECT
4-
xc_ncgga_radial.cpp
54
xc_functional.cpp
5+
xc_functional_ncgga_sf.cpp
6+
xc_ncgga_radial.cpp
67
xc_pot.cpp
78
xc_grad.cpp
89
xc_grad_prepare.cpp

source/source_hamilt/module_xc/libxc_abacus.h

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
#include "source_base/matrix.h"
77
#include "source_base/vector3.h"
8+
#include "xc_ncgga_radial.h"
89

910
#include <xc.h>
1011
#include <xc_funcs.h>
1112

13+
#include <array>
1214
#include <tuple>
1315
#include <vector>
1416

@@ -26,29 +28,41 @@ namespace XC_Functional_Libxc
2628
std::vector<double> dsigma;
2729
};
2830

31+
// Complete forward data for the gga_grad=2 noncollinear Libxc graph:
32+
// rho_s = N_s(x),
33+
// g_s = sum_A (d N_s / d x_A) G_h x_A.
34+
// Keeping the local map and all input gradients together lets the reverse
35+
// use the exact same branch choices and radial Hessian as the forward.
36+
struct NclSfDiscreteData
37+
{
38+
std::vector<ModuleXC::NcggaSpinMapPoint> spin_map;
39+
std::vector<double> rho;
40+
std::vector<std::vector<ModuleBase::Vector3<double>>> spin_gradient;
41+
std::array<std::vector<ModuleBase::Vector3<double>>, 3> grad_m;
42+
};
2943

3044
//-------------------
3145
// libxc_setup.cpp
3246
//-------------------
3347

3448
// sets functional type, which allows combination of LIBXC keyword connected by "+"
35-
// for example, "XC_LDA_X+XC_LDA_C_PZ"
49+
// for example: "XC_LDA_X+XC_LDA_C_PZ"
3650
extern std::pair<int, std::vector<int>> set_xc_type_libxc(const std::string& xc_func_in);
3751

3852
/**
3953
* @brief instantiate the XC functional by its ID, and set the external parameters if provided.
40-
*
54+
*
4155
* @param func_id libxc ID of functional, see https://libxc.gitlab.io/functionals/ for details
4256
* @param xc_polarized 0: unpolarized, 1: spin-polarized
43-
* @return std::vector<xc_func_type>
44-
*
57+
* @return std::vector<xc_func_type>
58+
*
4559
* @note the functionality of this method is extended by supporting the user-defined
46-
* external parameters of xc. However, there are several functionals' external
47-
* parameters are pre-defined in the code, which herein we call those are
48-
* "in-built" parameters. If the same functional ID is found in both in-built
60+
* external parameters of xc. However, there are several functionals' external
61+
* parameters are pre-defined in the code, which herein we call those are
62+
* "in-built" parameters. If the same functional ID is found in both in-built
4963
* and external parameters, the external parameters will overwrite the in-built ones.
5064
* The external parameters can be passed here by keywords xc_exch_ext and
51-
* xc_corr_ext in the input file. The expected format would be an XC ID
65+
* xc_corr_ext in the input file. The expected format would be an XC ID
5266
* followed by a list of parameters.
5367
*/
5468
extern std::vector<xc_func_type> init_func(
@@ -73,10 +87,24 @@ namespace XC_Functional_Libxc
7387
const int nspin,
7488
const bool domag,
7589
const bool domag_z,
90+
const int gga_grad,
7691
const std::map<int, double>* scaling_factor,
7792
const double hybrid_alpha,
7893
const double hse_omega);
7994

95+
// Reciprocal-metric derivative of the exact gga_grad=2 Libxc energy
96+
// graph. The returned lower-triangular tensor is the unnormalized local
97+
// grid sum; Stress_Func performs the pool reduction and divides by nxyz.
98+
extern void gradcorr_ncgga_sf_libxc(
99+
const std::vector<int>& func_id,
100+
const std::size_t nrxx,
101+
const double tpiba,
102+
const Charge* const chr,
103+
const std::map<int, double>* scaling_factor,
104+
const double hybrid_alpha,
105+
const double hse_omega,
106+
std::vector<double>& stress_gga);
107+
80108
// for mGGA functional
81109
extern std::tuple<double, double, ModuleBase::matrix, ModuleBase::matrix> v_xc_meta(
82110
const std::vector<int> &func_id,
@@ -105,6 +133,25 @@ namespace XC_Functional_Libxc
105133
const std::size_t nrxx,
106134
const Charge* const chr);
107135

136+
// Build the exact gga_grad=2 local spin map and, when requested, its
137+
// projected FFT-gradient graph. LDA-only callers set need_gradient=false.
138+
extern NclSfDiscreteData make_ncl_sf_discrete_data(
139+
const std::size_t nrxx,
140+
const double tpiba,
141+
const Charge* const chr,
142+
const bool need_gradient);
143+
144+
// Reverse one aggregate of all scaled Libxc components. The returned
145+
// potential is already in (n,mx,my,mz) representation. An empty dsigma
146+
// selects the LDA-only local reverse and performs no FFT divergence.
147+
extern ModuleBase::matrix reverse_ncl_sf_discrete(
148+
const std::size_t nrxx,
149+
const NclSfDiscreteData& data,
150+
const std::vector<double>& drho,
151+
const std::vector<double>& dsigma,
152+
const double tpiba,
153+
const Charge* const chr);
154+
108155
// calculating grho
109156
extern std::vector<std::vector<ModuleBase::Vector3<double>>> cal_gdr(
110157
const int nspin,
@@ -159,7 +206,7 @@ namespace XC_Functional_Libxc
159206
const std::vector<double> &vrho,
160207
const std::vector<double> &vsigma);
161208

162-
// converting vtxc and v from vrho and vsigma (libxc=>abacus)
209+
// Convert collinear LibXC derivatives to the potential.
163210
extern std::pair<double, ModuleBase::matrix> convert_vtxc_v(
164211
const xc_func_type &func,
165212
const int nspin,
@@ -183,12 +230,14 @@ namespace XC_Functional_Libxc
183230
const Charge* const chr);
184231

185232
// convert v for NSPIN=4
233+
// has_mag: whether the calculation has (noncollinear) magnetization,
234+
// i.e. domag || domag_z
186235
extern ModuleBase::matrix convert_v_nspin4(
187236
const std::size_t nrxx,
188237
const Charge* const chr,
189238
const std::vector<double> &amag,
190-
const ModuleBase::matrix &v);
191-
239+
const ModuleBase::matrix &v,
240+
const bool has_mag);
192241

193242
//-------------------
194243
// libxc_lda_wrap.cpp

0 commit comments

Comments
 (0)