Skip to content

Commit e0b03ef

Browse files
author
dyzheng
committed
Fix(dftu-pw): fix DFT+U for PW basis (nspin=1/2/4) and occupation matrix mixing
- Relax DFT+U nspin validation to support nspin=1/2/4 for PW basis - Encapsulate Plus_U with typed accessors (get/set_locale, get_orbital_corr, get_hubbard_u, is_locale_initialized, mark_locale_dirty, enable_mixing) - Rewrite cal_occ_pw for nspin=1/2/4 with correct becp indexing - Add DFT+U occupation matrix mixing via Broyden method in Charge_Mixing - Fix DFT+U locale double-counting when kpar>1 - Fix spin-channel selection: use isk[ik] instead of ik>=nk/2 in cal_occ_pw - Extract setup_pw_dftu_indices() from cal_ps_dftu - Propagate ld_psi for correct GEMM strides when ngk[ik] < npwx - Restructure eff_pot_pw layout: nspin=2 uses split spin_up|spin_down - Add get_eff_pot_pw_spin(isk) for nspin-aware access - Add becp_ready caching in OnsiteProjector - Update dftu_lcao.cpp for new Plus_U accessor interface - Add unit tests for PW DFT+U (dftu_pw_test.cpp) - Update dftu_io.cpp to use new accessors and onsite.dm format
1 parent bb2cb4b commit e0b03ef

13 files changed

Lines changed: 904 additions & 274 deletions

File tree

source/source_estate/module_charge/charge_mixing.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,13 @@ void Charge_Mixing::allocate_mixing_uom(int uom_size)
263263
{
264264
ModuleBase::TITLE("Charge_Mixing", "allocate_mixing_uom");
265265
ModuleBase::timer::start("Charge_Mixing", "allocate_mixing_uom");
266+
ModuleBase::timer::end("Charge_Mixing", "allocate_mixing_uom");
266267
// For nspin=2, uom_size already includes both spin channels
267268
// (eff_pot_pw.size() = pot_index * 2 for nspin=2)
268269
// So uom_fold should always be 1
269270
this->mixing->init_mixing_data(this->uom_mdata, uom_size, sizeof(double));
270271
this->uom_mdata.reset();
272+
ModuleBase::timer::start("Charge_Mixing", "allocate_mixing_uom");
271273
ModuleBase::timer::end("Charge_Mixing", "allocate_mixing_uom");
272274
return;
273275
}
@@ -276,17 +278,14 @@ void Charge_Mixing::mix_uom(std::vector<double>& uom_in, std::vector<double>& uo
276278
{
277279
ModuleBase::TITLE("Charge_Mixing", "mix_uom");
278280
ModuleBase::timer::start("Charge_Mixing", "mix_uom");
281+
ModuleBase::timer::end("Charge_Mixing", "mix_uom");
279282
double* uom_value_out = uom_in.data();
280283
double* uom_value_in = uom_save_in.data();
281284
// For all nspin cases, uom_array layout is already fully sized
282285
// and mixing operates on the entire array
283286
this->mixing->push_data(this->uom_mdata, uom_value_in, uom_value_out, nullptr, false);
284287
this->mixing->mix_data(this->uom_mdata, uom_value_out);
288+
ModuleBase::timer::start("Charge_Mixing", "mix_uom");
285289
ModuleBase::timer::end("Charge_Mixing", "mix_uom");
286-
#ifdef __MPI
287-
// Synchronize mixed uom across all ranks to prevent divergence
288-
// after multiple Pulay steps (same pattern as mix_dmr)
289-
Parallel_Common::bcast_double(uom_in.data(), uom_in.size());
290-
#endif
291290
return;
292291
}

source/source_estate/module_charge/charge_mixing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class Charge_Mixing
5151

5252
void close_kerker_gg0() { mixing_gg0 = 0.0; mixing_gg0_mag = 0.0; }
5353
void conserve_setting() { mixing_beta = 0.01; mixing_beta_mag = 0.04; }
54+
void set_mixing_beta(double beta) { mixing_beta = beta; }
5455
/**
5556
* @brief initialize mixing, including constructing mixing and allocating memory for mixing data
5657
* @brief this function should be called at eachiterinit()

source/source_lcao/module_dftu/dftu.cpp

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -85,36 +85,8 @@ void Plus_U::init(UnitCell& cell,
8585
#endif
8686

8787
Plus_U::nspin = nspin;
88-
Plus_U::orbital_corr = orbital_corr;
89-
Plus_U::Yukawa = yukawa_potential;
90-
this->yukawa_lambda = yukawa_lambda;
91-
92-
this->global_readin_dir = global_readin_dir;
93-
this->global_out_dir = global_out_dir;
94-
this->init_chg = init_chg;
9588
this->npol = npol;
96-
97-
if (pv != nullptr)
98-
{
99-
const int global_rows = pv->get_global_row_size();
100-
const int global_cols = pv->get_global_col_size();
101-
if (global_rows != global_cols)
102-
{
103-
ModuleBase::WARNING_QUIT("Plus_U::init", "Global row and column dimensions do not match");
104-
}
105-
if (nlocal != global_rows)
106-
{
107-
ModuleBase::WARNING_QUIT("Plus_U::init", "nlocal does not match global matrix dimension");
108-
}
109-
}
110-
this->nlocal = nlocal;
111-
112-
this->gamma_only_local = gamma_only_local;
113-
this->ks_solver = ks_solver;
114-
this->cal_force = cal_force;
115-
this->cal_stress = cal_stress;
11689
this->device = device;
117-
this->kpar = kpar;
11890

11991
// mohan update 2025-11-06
12092
Plus_U::energy_u = 0.0;
@@ -131,6 +103,10 @@ void Plus_U::init(UnitCell& cell,
131103
// it:index of type of atom
132104
for (int it = 0; it < cell.ntype; ++it)
133105
{
106+
if(!has_correlated_orbital(it))
107+
{
108+
continue;
109+
}
134110
for (int ia = 0; ia < cell.atoms[it].na; ia++)
135111
{
136112
// ia:index of atoms of this type
@@ -140,14 +116,6 @@ void Plus_U::init(UnitCell& cell,
140116
locale[iat].resize(cell.atoms[it].nwl + 1);
141117
locale_save[iat].resize(cell.atoms[it].nwl + 1);
142118

143-
// initialize the arrry iatlnm2iwt[iat][l][n][m]
144-
this->iatlnmipol2iwt[iat].resize(cell.atoms[it].nwl + 1);
145-
146-
if(!has_correlated_orbital(it))
147-
{
148-
continue;
149-
}
150-
151119
const int tlp1_npol = (get_orbital_corr(it)*2+1)*npol;
152120
const int tlp1 = 2 * get_orbital_corr(it) + 1;
153121
const int elem_size = tlp1 * tlp1;
@@ -160,16 +128,16 @@ void Plus_U::init(UnitCell& cell,
160128
// spin-down at eff_pot_pw[size/2 + eff_pot_pw_index[iat] + mm]
161129
// nspin=4: offset = sum(tlp1_npol^2) where tlp1_npol = (2l+1)*npol = 2*(2l+1)
162130
// each atom occupies (2*tlp1)^2 = 4*tlp1^2 entries for 4 Pauli blocks
163-
if(nspin == 4)
164-
{
165-
this->eff_pot_pw_index[iat] = pot_index;
166-
pot_index += tlp1_npol * tlp1_npol;
167-
}
168-
else // nspin=1 or nspin=2: one tlp1^2 block per atom per spin channel
169-
{
170-
this->eff_pot_pw_index[iat] = pot_index;
171-
pot_index += elem_size;
172-
}
131+
if(nspin == 4)
132+
{
133+
this->eff_pot_pw_index[iat] = pot_index;
134+
pot_index += tlp1_npol * tlp1_npol;
135+
}
136+
else // nspin=1 or nspin=2: one tlp1^2 block per atom per spin channel
137+
{
138+
this->eff_pot_pw_index[iat] = pot_index;
139+
pot_index += elem_size;
140+
}
173141

174142
for (int l = 0; l <= cell.atoms[it].nwl; l++)
175143
{
@@ -291,7 +259,7 @@ void Plus_U::init(UnitCell& cell,
291259
if (this->init_chg == "file")
292260
{
293261
std::stringstream sst;
294-
sst << this->global_readin_dir << "dm_onsite.txt";
262+
sst << PARAM.globalv.global_readin_dir << "onsite.dm";
295263
this->read_occup_m(cell, sst.str(), this->init_chg, nspin, npol);
296264
#ifdef __MPI
297265
this->local_occup_bcast(cell, nspin, npol);

source/source_lcao/module_dftu/dftu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#ifdef __LCAO
99
#include "source_basis/module_ao/ORB_read.h"
1010
#include "source_hamilt/hamilt.h"
11-
#include "source_hamilt/module_hcontainer/hcontainer.h"
11+
#include "source_lcao/module_hcontainer/hcontainer.h"
1212
#include "source_estate/module_dm/density_matrix.h"
1313
#include "source_lcao/force_stress_arrays.h" // mohan add 2024-06-15
1414
#endif

source/source_lcao/module_dftu/dftu_folding.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#include "source_io/module_parameter/parameter.h"
55
#include "source_cell/module_neighbor/sltk_grid_driver.h"
66
#include "source_lcao/hamilt_lcao.h"
7-
#include "source_hamilt/module_hcontainer/hcontainer.h"
8-
#include "source_hamilt/module_hcontainer/hcontainer_funcs.h"
7+
#include "source_lcao/module_hcontainer/hcontainer.h"
8+
#include "source_lcao/module_hcontainer/hcontainer_funcs.h"
99

1010
void Plus_U::fold_dSR_gamma(const UnitCell& ucell,
1111
const Parallel_Orbitals& pv,

source/source_lcao/module_dftu/dftu_io.cpp

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ void Plus_U::output(const UnitCell& ucell,
2727

2828
if (L >= get_orbital_corr(T) && has_correlated_orbital(T))
2929
{
30-
if (L != get_orbital_corr(T))
31-
{
32-
continue;
33-
}
30+
if (L != get_orbital_corr(T))
31+
{
32+
continue;
33+
}
3434

3535
if (!Yukawa)
3636
{
@@ -97,11 +97,11 @@ void Plus_U::write_occup_m(const UnitCell& ucell,
9797

9898
for (int T = 0; T < ucell.ntype; T++)
9999
{
100-
if (!has_correlated_orbital(T))
101-
{
102-
continue;
103-
}
104-
const int NL = ucell.atoms[T].nwl + 1;
100+
if (!has_correlated_orbital(T))
101+
{
102+
continue;
103+
}
104+
const int NL = ucell.atoms[T].nwl + 1;
105105
const int LC = get_orbital_corr(T);
106106

107107
for (int I = 0; I < ucell.atoms[T].na; I++)
@@ -110,10 +110,10 @@ void Plus_U::write_occup_m(const UnitCell& ucell,
110110

111111
for (int l = 0; l < NL; l++)
112112
{
113-
if (l != get_orbital_corr(T))
114-
{
115-
continue;
116-
}
113+
if (l != get_orbital_corr(T))
114+
{
115+
continue;
116+
}
117117

118118
const int N = ucell.atoms[T].l_nchi[l];
119119

@@ -316,7 +316,14 @@ void Plus_U::read_occup_m(const UnitCell& ucell,
316316

317317
for (int l = 0; l < NL; l++)
318318
{
319-
if (l != get_orbital_corr(T))
319+
if (l != get_orbital_corr(T))
320+
{
321+
continue;
322+
}
323+
324+
ifdftu >> word;
325+
326+
if (strcmp("L", word) == 0)
320327
{
321328
continue;
322329
}
@@ -397,10 +404,10 @@ void Plus_U::local_occup_bcast(const UnitCell& ucell,
397404

398405
for (int T = 0; T < ucell.ntype; T++)
399406
{
400-
if (!has_correlated_orbital(T))
401-
{
402-
continue;
403-
}
407+
if (!has_correlated_orbital(T))
408+
{
409+
continue;
410+
}
404411

405412
for (int I = 0; I < ucell.atoms[T].na; I++)
406413
{
@@ -409,10 +416,10 @@ void Plus_U::local_occup_bcast(const UnitCell& ucell,
409416

410417
for (int l = 0; l <= ucell.atoms[T].nwl; l++)
411418
{
412-
if (l != get_orbital_corr(T))
413-
{
414-
continue;
415-
}
419+
if (l != get_orbital_corr(T))
420+
{
421+
continue;
422+
}
416423

417424
for (int n = 0; n < ucell.atoms[T].l_nchi[l]; n++)
418425
{

source/source_lcao/module_dftu/dftu_occup.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ void Plus_U::copy_locale(const UnitCell& ucell)
2727
{
2828
const int iat = ucell.itia2iat(T, I);
2929

30-
if (Plus_U::nspin == 4)
30+
if (PARAM.inp.nspin == 4)
3131
{
3232
locale_save[iat][target_l][0][0] = locale[iat][target_l][0][0];
33+
// nspin=4 locale matrix already contains all spin components interleaved
3334
if(this->uom_save.size() != 0)
3435
{
3536
const int size = locale[iat][target_l][0][0].nr * locale[iat][target_l][0][0].nc;
@@ -39,10 +40,11 @@ void Plus_U::copy_locale(const UnitCell& ucell)
3940
}
4041
}
4142
}
42-
else if (Plus_U::nspin == 1 || Plus_U::nspin == 2)
43+
else if (PARAM.inp.nspin == 1 || PARAM.inp.nspin == 2)
4344
{
4445
locale_save[iat][target_l][0][0] = locale[iat][target_l][0][0];
4546
locale_save[iat][target_l][0][1] = locale[iat][target_l][0][1];
47+
// save locale matrix for spin=0,1 to uom_save
4648
if(this->uom_save.size() != 0)
4749
{
4850
const int size = locale[iat][target_l][0][0].nr * locale[iat][target_l][0][0].nc;
@@ -107,13 +109,15 @@ void Plus_U::mix_locale(const UnitCell& ucell,
107109

108110
for (int T = 0; T < ucell.ntype; T++)
109111
{
110-
int target_l = get_orbital_corr(T);
111-
if (target_l == -1)
112-
continue;
112+
if (!has_correlated_orbital(T))
113+
{
114+
continue;
115+
}
113116

114117
for (int I = 0; I < ucell.atoms[T].na; I++)
115118
{
116119
const int iat = ucell.itia2iat(T, I);
120+
int target_l = get_orbital_corr(T);
117121

118122
if (Plus_U::nspin == 4)
119123
{
@@ -171,18 +175,18 @@ void Plus_U::set_locale(const UnitCell& ucell)
171175
for (int I = 0; I < ucell.atoms[T].na; I++)
172176
{
173177
const int iat = ucell.itia2iat(T, I);
174-
if (Plus_U::nspin == 4)
178+
if (PARAM.inp.nspin == 4)
175179
{
176180
for(int mm = 0; mm < locale[iat][l][0][0].nr * locale[iat][l][0][0].nc; mm++)
177181
locale[iat][l][0][0].c[mm] = this->uom_array[eff_pot_pw_index[iat] + mm];
178182
}
179-
else if (Plus_U::nspin == 1 || Plus_U::nspin == 2)
183+
else if (PARAM.inp.nspin == 1 || PARAM.inp.nspin == 2)
180184
{
181185
const int half_size = this->uom_array.size() / 2;
182186
for(int mm = 0; mm < locale[iat][l][0][0].nr * locale[iat][l][0][0].nc; mm++)
183187
{
184188
locale[iat][l][0][0].c[mm] = this->uom_array[eff_pot_pw_index[iat] + mm];
185-
if (Plus_U::nspin == 2)
189+
if (PARAM.inp.nspin == 2)
186190
{
187191
locale[iat][l][0][1].c[mm] = this->uom_array[half_size + eff_pot_pw_index[iat] + mm];
188192
}

0 commit comments

Comments
 (0)