Skip to content

Commit 12ecc79

Browse files
mohanchenabacus_fixer
andauthored
Refactor DFT+U codes (deepmodeling#7852)
* refactor(dftu): phase 1 - scaffold dftu_base.h/.cpp skeleton - Add empty Plus_U_Base class in source_pw/module_pwdft/ - Wire into CMakeLists.txt and Makefile.Objects - No functional change; dftu.h untouched * refactor(dftu): phase 2 - duplicate base members and implementations to dftu_base Copy all base-class members (static members, Yukawa members, locale/eff_pot_pw data structures) and non-inline method implementations from dftu.cpp, dftu_io.cpp, dftu_occup.cpp, dftu_pw.cpp into dftu_base.h/.cpp under source_pw/module_pwdft/. The Plus_U_Base class is a standalone duplicate of Plus_U's base portion. Plus_U is not yet modified; both classes coexist independently. init_base has an empty stub body (full implementation deferred to Phase 4). cal_slater_UJ and other Yukawa calculation methods remain in dftu_yukawa.cpp as Plus_U methods for now. Build verified: make -j 30 in build_max_para_test passes with no errors. * refactor(dftu): phase 3 - Plus_U inherits Plus_U_Base, remove duplicate members - dftu.h: Plus_U now inherits from Plus_U_Base; LCAO-specific members kept - dftu.cpp: remove duplicate static member definitions and method implementations (uramping_update, u_converged) already in dftu_base - dftu_io.cpp: remove duplicate implementations (output, write_occup_m, read_occup_m, local_occup_bcast); keep inline JacobiRotate/ CalculateEigenvalues helpers - dftu_occup.cpp: remove duplicate locale methods (copy_locale, zero_locale, mix_locale, set_locale, get_locale_flat, set_locale_flat); keep LCAO-specific cal_occup_m_k/gamma - dftu_pw.cpp: cal_occ_pw reimplemented as Plus_U_Base::cal_occ_pw (keeps PW-side OnsiteProjector/Charge_Mixing deps out of dftu_base.cpp) - dftu_base.h: change private to protected for accessors used by derived Plus_U; energy_u moved to protected - test_dftu.cpp: remove duplicate static member definitions; rely on dftu_base.cpp for Plus_U_Base symbols - test CMakeLists.txt: add dftu_base.cpp to SOURCES for MODULE_LCAO_operator_dftu_test Verified: make -j 30 in build_max_para_test succeeds; all dftu unit tests pass (dftu_core_test: 10, dftu_pw_test: 11, dftu_operator_test: 15, MODULE_LCAO_operator_dftu_test: 2). * refactor(dftu): phase 4 - split init() into init_base + LCAO-specific setup - dftu_base.cpp: implement Plus_U_Base::init_base() containing all base-only initialization (static members, locale/eff_pot_pw/uom_array allocation, Yukawa Fk/U_Yukawa/J_Yukawa setup, dm_onsite file reading) - dftu.cpp: Plus_U::init() now calls init_base() and only retains LCAO-specific setup (paraV, ptr_orb_, orb_cutoff_, ucell pointer, parallel orbital dimension checks) Verified: make -j 30 in build_max_para_test succeeds; all dftu unit tests pass (dftu_core_test: 10, dftu_pw_test: 11, dftu_operator_test: 15, MODULE_LCAO_operator_dftu_test: 2). * refactor(dftu): phase 5 - move dftu_pw.cpp to source_pw/module_pwdft - git mv source_lcao/module_dftu/dftu_pw.cpp -> source_pw/module_pwdft/dftu_pw.cpp - dftu_pw.cpp: include dftu_base.h instead of dftu.h (cal_occ_pw is now a Plus_U_Base method, no LCAO types needed) - source_lcao/module_dftu/CMakeLists.txt: remove dftu_pw.cpp from dftu OBJECT library - source_pw/module_pwdft/CMakeLists.txt: add dftu_pw.cpp to module_pwdft OBJECT library - Makefile.Objects: add dftu_pw.o to OBJS_SRCPW (was missing entirely from OBJS_DFTU before) Verified: make -j 30 in build_max_para_test succeeds; all dftu unit tests pass (dftu_core_test: 10, dftu_pw_test: 11, dftu_operator_test: 15, MODULE_LCAO_operator_dftu_test: 2). * refactor(dftu): phase 6 - remove redundant dftu_io.cpp dftu_io.cpp only contained inline JacobiRotate/CalculateEigenvalues helpers, which are already duplicated as inline functions in dftu_base.cpp (where write_occup_m uses them). The file had no non-inline symbols, so deleting it is safe. - git rm source_lcao/module_dftu/dftu_io.cpp - source_lcao/module_dftu/CMakeLists.txt: remove dftu_io.cpp from dftu OBJECT library - Makefile.Objects: remove dftu_io.o from OBJS_DFTU Verified: make -j 30 in build_max_para_test succeeds; all dftu unit tests pass (dftu_core_test: 10, dftu_pw_test: 11, dftu_operator_test: 15, MODULE_LCAO_operator_dftu_test: 2). * Phase 7: switch setup_pot/setup_dftu_pw to Plus_U_Base interface - setup_pot.h/cpp: include dftu_base.h instead of dftu.h - setup_pot.cpp: parameter type Plus_U& -> Plus_U_Base& - setup_pot.cpp: call dftu.init_base() instead of dftu.init() with nullptr pv - setup_dftu_pw.h/cpp: forward declare Plus_U_Base, parameter type updated - Callers (esolver_ks_pw.cpp) pass this->dftu (Plus_U), bound to Plus_U_Base& After this phase, the PW path no longer needs LCAO-specific Plus_U headers. * Phase A: extract output/write_occup_m as free functions in dftu_io namespace - New files: source_pw/module_pwdft/dftu_output.h, dftu_output.cpp - declare and implement dftu_io::output and dftu_io::write_occup_m - first parameter is const Plus_U_Base&, accesses state via public getters - JacobiRotate and CalculateEigenvalues inline helpers migrated here - dftu_base.h: added public getters get_U_Yukawa / get_J_Yukawa; removed output/write_occup_m member declarations - dftu_base.cpp: removed output/write_occup_m implementations and the two Jacobi inline helpers (no longer referenced here) - Callers updated: - setup_dftu_pw.cpp: dftu.output(...) -> dftu_io::output(dftu, ...) - setup_dftu_lcao.cpp: dftu_ptr->output(...) -> dftu_io::output(*dftu_ptr, ...) - CMakeLists.txt and Makefile.Objects: added dftu_output.cpp/dftu_output.o All 4 dftu unit tests pass. --------- Co-authored-by: abacus_fixer <mohanchen@pku.eud.cn>
1 parent f7209c8 commit 12ecc79

19 files changed

Lines changed: 1461 additions & 1352 deletions

source/Makefile.Objects

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,9 @@ OBJS_SRCPW=h_ewald_pw.o\
741741
setup_pwrho.o\
742742
setup_pwwfc.o\
743743
update_cell_pw.o\
744+
dftu_base.o\
745+
dftu_output.o\
746+
dftu_pw.o\
744747
setup_dftu_pw.o\
745748
deltaspin_pw.o\
746749
force_pw.o\
@@ -809,7 +812,6 @@ OBJS_DFTU=dftu.o\
809812
dftu_force.o\
810813
dftu_yukawa.o\
811814
dftu_folding.o\
812-
dftu_io.o\
813815
dftu_tools.o\
814816
dftu_occup.o\
815817
dftu_hamilt.o\

source/source_lcao/module_dftu/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ list(APPEND objects
33
dftu_force.cpp
44
dftu_yukawa.cpp
55
dftu_folding.cpp
6-
dftu_io.cpp
76
dftu_tools.cpp
87
dftu_occup.cpp
98
dftu_hamilt.cpp
10-
dftu_pw.cpp
119
)
1210

1311
add_library(

source/source_lcao/module_dftu/dftu.cpp

Lines changed: 21 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,8 @@
2121
#include <vector>
2222

2323
// mohan add 2025-11-06
24-
double Plus_U::energy_u = 0.0;
25-
26-
std::vector<double> Plus_U::U = {}; // U (Hubbard parameter U)
27-
28-
std::vector<double> Plus_U::U0 = {}; // U0 (target Hubbard parameter U0)
29-
30-
std::vector<int> Plus_U::orbital_corr = {}; //
31-
32-
double Plus_U::uramping = 0.0; // increase U by uramping, default is -1.0
33-
34-
int Plus_U::omc=0; // occupation matrix control
35-
36-
int Plus_U::mixing_dftu=0; //whether to mix locale
37-
int Plus_U::nspin=0;
38-
39-
bool Plus_U::Yukawa=false; // whether to use Yukawa potential
24+
// Static member definitions moved to dftu_base.cpp (Plus_U_Base::)
25+
// Plus_U inherits these from Plus_U_Base.
4026

4127
Plus_U::Plus_U()
4228
{}
@@ -68,14 +54,9 @@ void Plus_U::init(UnitCell& cell,
6854
{
6955
ModuleBase::TITLE("Plus_U", "init");
7056

71-
#ifndef __MPI
72-
std::cout << "DFT+U module is only accessible in mpi versioin" << std::endl;
73-
exit(0);
74-
#endif
75-
7657
this->paraV = pv;
7758

78-
#ifdef __LCAO
59+
#ifdef __LCAO
7960
ptr_orb_ = orb;
8061
if(ptr_orb_ != nullptr)
8162
{
@@ -84,16 +65,6 @@ void Plus_U::init(UnitCell& cell,
8465
ucell = &cell;
8566
#endif
8667

87-
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;
95-
this->npol = npol;
96-
9768
if (pv != nullptr)
9869
{
9970
const int global_rows = pv->get_global_row_size();
@@ -107,204 +78,23 @@ void Plus_U::init(UnitCell& cell,
10778
ModuleBase::WARNING_QUIT("Plus_U::init", "nlocal does not match global matrix dimension");
10879
}
10980
}
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;
116-
this->device = device;
117-
this->kpar = kpar;
118-
119-
// mohan update 2025-11-06
120-
Plus_U::energy_u = 0.0;
121-
122-
this->locale.resize(cell.nat);
123-
this->locale_save.resize(cell.nat);
124-
// only for PW base
125-
this->eff_pot_pw_index.resize(cell.nat);
126-
int pot_index = 0;
127-
128-
this->iatlnmipol2iwt.resize(cell.nat);
129-
130-
int num_locale = 0;
131-
// it:index of type of atom
132-
for (int it = 0; it < cell.ntype; ++it)
133-
{
134-
for (int ia = 0; ia < cell.atoms[it].na; ia++)
135-
{
136-
// ia:index of atoms of this type
137-
// determine the size of locale
138-
const int iat = cell.itia2iat(it, ia);
139-
140-
locale[iat].resize(cell.atoms[it].nwl + 1);
141-
locale_save[iat].resize(cell.atoms[it].nwl + 1);
142-
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-
151-
const int tlp1_npol = (get_orbital_corr(it)*2+1)*npol;
152-
const int tlp1 = 2 * get_orbital_corr(it) + 1;
153-
const int elem_size = tlp1 * tlp1;
154-
// eff_pot_pw_index: per-atom offset into eff_pot_pw (and uom_array)
155-
//
156-
// nspin=1: offset = sum(tlp1^2 for preceding atoms), total = sum(all tlp1^2)
157-
// nspin=2: same per-spin-channel offset; after the loop, pot_index *= 2
158-
// to create split layout: [all_spin_up | all_spin_down]
159-
// spin-up at eff_pot_pw[eff_pot_pw_index[iat] + mm]
160-
// spin-down at eff_pot_pw[size/2 + eff_pot_pw_index[iat] + mm]
161-
// nspin=4: offset = sum(tlp1_npol^2) where tlp1_npol = (2l+1)*npol = 2*(2l+1)
162-
// 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-
}
173-
174-
for (int l = 0; l <= cell.atoms[it].nwl; l++)
175-
{
176-
const int N = cell.atoms[it].l_nchi[l];
177-
178-
locale[iat][l].resize(N);
179-
locale_save[iat][l].resize(N);
180-
181-
for (int n = 0; n < N; n++)
182-
{
183-
if (nspin == 1 || nspin == 2)
184-
{
185-
locale[iat][l][n].resize(2);
186-
locale_save[iat][l][n].resize(2);
187-
188-
locale[iat][l][n][0].create(2 * l + 1, 2 * l + 1);
189-
locale[iat][l][n][1].create(2 * l + 1, 2 * l + 1);
190-
191-
locale_save[iat][l][n][0].create(2 * l + 1, 2 * l + 1);
192-
locale_save[iat][l][n][1].create(2 * l + 1, 2 * l + 1);
193-
num_locale += (2 * l + 1) * (2 * l + 1) * 2;
194-
}
195-
else if (nspin == 4) // SOC
196-
{
197-
locale[iat][l][n].resize(1);
198-
locale_save[iat][l][n].resize(1);
19981

200-
locale[iat][l][n][0].create((2 * l + 1) * npol, (2 * l + 1) * npol);
201-
locale_save[iat][l][n][0].create((2 * l + 1) * npol, (2 * l + 1) * npol);
202-
num_locale += (2 * l + 1) * (2 * l + 1) * npol * npol;
203-
}
204-
}
205-
}
206-
207-
// initialize the arrry iatlnm2iwt[iat][l][n][m]
208-
this->iatlnmipol2iwt[iat].resize(cell.atoms[it].nwl + 1);
209-
for (int L = 0; L <= cell.atoms[it].nwl; L++)
210-
{
211-
this->iatlnmipol2iwt[iat][L].resize(cell.atoms[it].l_nchi[L]);
212-
213-
for (int n = 0; n < cell.atoms[it].l_nchi[L]; n++)
214-
{
215-
this->iatlnmipol2iwt[iat][L][n].resize(2 * L + 1);
216-
217-
for (int m = 0; m < 2 * L + 1; m++)
218-
{
219-
this->iatlnmipol2iwt[iat][L][n][m].resize(npol);
220-
}
221-
}
222-
}
223-
224-
for (int iw = 0; iw < cell.atoms[it].nw * npol; iw++)
225-
{
226-
int iw0 = iw / npol;
227-
int ipol = iw % npol;
228-
int iwt = cell.itiaiw2iwt(it, ia, iw);
229-
int l = cell.atoms[it].iw2l[iw0];
230-
int n = cell.atoms[it].iw2n[iw0];
231-
int m = cell.atoms[it].iw2m[iw0];
232-
233-
this->iatlnmipol2iwt[iat][l][n][m][ipol] = iwt;
234-
}
235-
}
236-
}
237-
// allocate memory for eff_pot_pw
238-
// nspin=2: split layout [all_spin_up | all_spin_down], double the size
239-
// nspin=4: each atom already has 4*tlp1^2 (tlp1_npol^2) entries for Pauli blocks
240-
if (nspin == 2) pot_index *= 2;
241-
242-
this->eff_pot_pw.resize(pot_index, 0.0);
243-
this->uom_array.resize(pot_index, 0.0);
244-
this->uom_save.resize(pot_index, 0.0);
245-
246-
if (Yukawa)
247-
{
248-
this->Fk.resize(cell.ntype);
249-
250-
this->U_Yukawa.resize(cell.ntype);
251-
this->J_Yukawa.resize(cell.ntype);
252-
253-
for (int it = 0; it < cell.ntype; it++)
254-
{
255-
const int NL = cell.atoms[it].nwl + 1;
256-
257-
this->Fk[it].resize(NL);
258-
this->U_Yukawa[it].resize(NL);
259-
this->J_Yukawa[it].resize(NL);
260-
261-
for (int l = 0; l < NL; l++)
262-
{
263-
int N = cell.atoms[it].l_nchi[l];
264-
265-
this->Fk[it][l].resize(N);
266-
for (int n = 0; n < N; n++)
267-
{
268-
this->Fk[it][l][n].resize(l + 1, 0.0);
269-
}
270-
271-
this->U_Yukawa[it][l].resize(N, 0.0);
272-
this->J_Yukawa[it][l].resize(N, 0.0);
273-
}
274-
}
275-
}
276-
277-
if (omc != 0)
278-
{
279-
std::stringstream sst;
280-
sst << this->global_readin_dir << "dm_onsite_ini.txt";
281-
this->read_occup_m(cell, sst.str(), this->init_chg, nspin, npol);
282-
#ifdef __MPI
283-
this->local_occup_bcast(cell, nspin, npol);
284-
#endif
285-
286-
mark_locale_initialized();
287-
this->copy_locale(cell);
288-
}
289-
else
290-
{
291-
if (this->init_chg == "file")
292-
{
293-
std::stringstream sst;
294-
sst << this->global_readin_dir << "dm_onsite.txt";
295-
this->read_occup_m(cell, sst.str(), this->init_chg, nspin, npol);
296-
#ifdef __MPI
297-
this->local_occup_bcast(cell, nspin, npol);
298-
#endif
299-
mark_locale_initialized();
300-
}
301-
else
302-
{
303-
this->zero_locale(cell);
304-
}
305-
}
306-
307-
ModuleBase::Memory::record("Plus_U::locale", sizeof(double) * num_locale);
82+
this->init_base(cell,
83+
npol,
84+
nspin,
85+
orbital_corr,
86+
yukawa_potential,
87+
yukawa_lambda,
88+
global_readin_dir,
89+
global_out_dir,
90+
init_chg,
91+
nlocal,
92+
gamma_only_local,
93+
ks_solver,
94+
cal_force,
95+
cal_stress,
96+
device,
97+
kpar);
30898
return;
30999
}
310100

@@ -465,45 +255,8 @@ void Plus_U::cal_energy_correction(const UnitCell& ucell,
465255

466256
#endif
467257

468-
void Plus_U::uramping_update()
469-
{
470-
// Yukawa calculates U directly every iteration, no need for ramping
471-
if (Yukawa) {
472-
return;
473-
}
474-
// if uramping < 0.1, use the original U
475-
if (this->uramping < 0.01) {
476-
return;
477-
}
478-
// loop to change U
479-
for (int i = 0; i < this->U0.size(); i++)
480-
{
481-
if (this->U[i] + this->uramping < this->U0[i])
482-
{
483-
this->U[i] += this->uramping;
484-
}
485-
else
486-
{
487-
this->U[i] = this->U0[i];
488-
}
489-
}
490-
}
491-
492-
bool Plus_U::u_converged()
493-
{
494-
// Yukawa calculates U directly every iteration, always considered converged
495-
if (Yukawa) {
496-
return true;
497-
}
498-
for (int i = 0; i < this->U0.size(); i++)
499-
{
500-
if (this->U[i] != this->U0[i])
501-
{
502-
return false;
503-
}
504-
}
505-
return true;
506-
}
258+
// uramping_update() and u_converged() are now implemented in
259+
// dftu_base.cpp as Plus_U_Base methods (inherited by Plus_U).
507260

508261
#ifdef __LCAO
509262

0 commit comments

Comments
 (0)