From 9f83dea1fd5bc12954e76ad7459445b5f1bd6c41 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 11:04:08 +0800 Subject: [PATCH 01/33] remove kpar parameter in dft+U --- source/source_lcao/lcao_set.cpp | 1 - source/source_lcao/module_dftu/dftu_nao.cpp | 2 -- source/source_lcao/module_dftu/dftu_nao.h | 1 - source/source_pw/module_pwdft/dftu_base.cpp | 2 -- source/source_pw/module_pwdft/dftu_base.h | 14 +++++++------- source/source_pw/module_pwdft/dftu_base_occ.cpp | 5 +++-- source/source_pw/module_pwdft/setup_dftu_pw.cpp | 2 +- source/source_pw/module_pwdft/setup_pot.cpp | 1 - .../source_pw/module_pwdft/test/dftu_base_test.cpp | 1 - 9 files changed, 11 insertions(+), 18 deletions(-) diff --git a/source/source_lcao/lcao_set.cpp b/source/source_lcao/lcao_set.cpp index 5c6e1bf4a0c..fbab0bcbbd5 100644 --- a/source/source_lcao/lcao_set.cpp +++ b/source/source_lcao/lcao_set.cpp @@ -91,7 +91,6 @@ void LCAO_domain::set_pot( pv.get_global_row_size(), inp.ks_solver, inp.device, - inp.kpar, PARAM.globalv.hubbard_u, PARAM.globalv.uramping, inp.occ_mat_ctrl, diff --git a/source/source_lcao/module_dftu/dftu_nao.cpp b/source/source_lcao/module_dftu/dftu_nao.cpp index f4a3bd6eed7..0309509638e 100644 --- a/source/source_lcao/module_dftu/dftu_nao.cpp +++ b/source/source_lcao/module_dftu/dftu_nao.cpp @@ -31,7 +31,6 @@ void Plus_U::init(UnitCell& cell, const int nlocal, const std::string& ks_solver, const std::string& device, - const int kpar, const std::vector& hubbard_u, const double uramping, const int occ_mat_ctrl, @@ -75,7 +74,6 @@ void Plus_U::init(UnitCell& cell, global_out_dir, init_chg, device, - kpar, hubbard_u, uramping, occ_mat_ctrl, diff --git a/source/source_lcao/module_dftu/dftu_nao.h b/source/source_lcao/module_dftu/dftu_nao.h index fb0bef416c1..46d26ccd3d8 100644 --- a/source/source_lcao/module_dftu/dftu_nao.h +++ b/source/source_lcao/module_dftu/dftu_nao.h @@ -47,7 +47,6 @@ class Plus_U : public Plus_U_Base const int nlocal, const std::string& ks_solver, const std::string& device, - const int kpar, const std::vector& hubbard_u, const double uramping, const int occ_mat_ctrl, diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index 2a078a32ae3..fffe5ab0f17 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -39,7 +39,6 @@ void Plus_U_Base::init_base(UnitCell& cell, const std::string& global_out_dir, const std::string& init_chg, const std::string& device, - const int kpar, const std::vector& hubbard_u, const double uramping, const int occ_mat_ctrl, @@ -64,7 +63,6 @@ void Plus_U_Base::init_base(UnitCell& cell, 0.0); } this->device = device; - this->kpar = kpar; this->energy_u = 0.0; diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index e52b39279ef..68c77b8757d 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -36,7 +36,6 @@ class Plus_U_Base const std::string& global_out_dir, const std::string& init_chg, const std::string& device, - const int kpar, const std::vector& hubbard_u, const double uramping, const int occ_mat_ctrl, @@ -76,7 +75,8 @@ class Plus_U_Base const ModuleBase::matrix& wg_in, const UnitCell& cell, Charge_Mixing* p_chgmix, - const int* isk); + const int* isk, + const int kpar); /// get effective potential pointer for the given spin channel (PW basis) /// @@ -123,6 +123,11 @@ class Plus_U_Base const OccMatMixer& occ_mixer() const { return *occ_mixer_; } bool has_occ_mixer() const { return occ_mixer_ != nullptr; } + private: + // --- State flags --- + // dftu can be calculated only after occ_mat has been initialized + bool occ_mat_initialized = false; + protected: // --- U values and orbital configuration (set in init_base) --- std::vector u_current; @@ -134,10 +139,6 @@ class Plus_U_Base int occ_mat_ctrl = 0; int nspin = 0; - // --- State flags --- - // dftu can be calculated only after occ_mat has been initialized - bool occ_mat_initialized = false; - // --- Occupation matrices --- OccupationMatrix occmat_; @@ -150,7 +151,6 @@ class Plus_U_Base int cal_type = 3; std::string device; - int kpar = 1; std::vector> pot_uterm_pw; std::vector pot_uterm_pw_index; diff --git a/source/source_pw/module_pwdft/dftu_base_occ.cpp b/source/source_pw/module_pwdft/dftu_base_occ.cpp index e844e976931..666c5aaf07a 100644 --- a/source/source_pw/module_pwdft/dftu_base_occ.cpp +++ b/source/source_pw/module_pwdft/dftu_base_occ.cpp @@ -29,7 +29,8 @@ void Plus_U_Base::cal_occ_pw(const void* psi_in, const ModuleBase::matrix& wg_in, const UnitCell& cell, Charge_Mixing* p_chgmix, - const int* isk) + const int* isk, + const int kpar) { ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); this->occmat_.copy_to_save(cell, this->orbital_corr); @@ -53,7 +54,7 @@ void Plus_U_Base::cal_occ_pw(const void* psi_in, #endif // reduce occ_mat across k-pools - DFTU_BASE::reduce_occ_mat(cell, this->nspin, this->kpar, + DFTU_BASE::reduce_occ_mat(cell, this->nspin, kpar, this->orbital_corr, this->occmat_); // mixing: flatten the fresh occ, mix against the saved one, write back diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index f330a6c6982..ef7e56b516e 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -27,7 +27,7 @@ void iter_init_dftu_pw(const int iter, if (dftu.get_occ_mat_ctrl() != 2) { - dftu.cal_occ_pw(psi, wg, ucell, p_chgmix, isk); + dftu.cal_occ_pw(psi, wg, ucell, p_chgmix, isk, PARAM.inp.kpar); } DFTU_BASE::output(dftu, ucell, PARAM.inp.out_chg[0], PARAM.globalv.global_out_dir, PARAM.inp.nspin, PARAM.globalv.npol); } diff --git a/source/source_pw/module_pwdft/setup_pot.cpp b/source/source_pw/module_pwdft/setup_pot.cpp index 98e46340f1d..1f1364d444f 100644 --- a/source/source_pw/module_pwdft/setup_pot.cpp +++ b/source/source_pw/module_pwdft/setup_pot.cpp @@ -129,7 +129,6 @@ void pw::setup_pot(const int istep, PARAM.globalv.global_out_dir, inp.init_chg, inp.device, - inp.kpar, PARAM.globalv.hubbard_u, PARAM.globalv.uramping, inp.occ_mat_ctrl, diff --git a/source/source_pw/module_pwdft/test/dftu_base_test.cpp b/source/source_pw/module_pwdft/test/dftu_base_test.cpp index daf920343c3..87248b9e46e 100644 --- a/source/source_pw/module_pwdft/test/dftu_base_test.cpp +++ b/source/source_pw/module_pwdft/test/dftu_base_test.cpp @@ -88,7 +88,6 @@ class DFTUBaseTest : public testing::Test "", // global_out_dir "none", // init_chg "cpu", // device - 1, // kpar hubbard_u, 0.0, // uramping 0, // occ_mat_ctrl From eabfabcc02658b0bdcfd06c25b069b60273c9893 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 14:46:20 +0800 Subject: [PATCH 02/33] refactor(dftu): rename orbital_corr to l_channel for clarity - Rename member variable `orbital_corr` to `l_channel` in Plus_U_Base - Rename member variable `orbital_corr_` to `l_channel_` in YukawaScreening and OccMatMixer - Rename accessor `get_orbital_corr(int)` to `get_l_channel(int)` - Rename accessor `get_orbital_corr_vec()` to `get_l_channel_vec()` - Rename predicate `has_correlated_orbital(int)` to `has_l_channel(int)` - Rename local variable `orbital_corr_tmp` to `l_channel_tmp` in onsite_proj_tools_force.cpp - Update all call sites across PW, LCAO, IO, and test modules The new name `l_channel` directly indicates the angular momentum quantum number `l` of the channel receiving the +U correction, avoiding confusion with "correlated orbital" (many-body physics concept) and the ambiguous abbreviation `corr`. --- source/source_estate/occ_matrix.cpp | 28 +++++++++---------- source/source_estate/occ_matrix.h | 14 +++++----- source/source_estate/occ_mixer.cpp | 14 +++++----- source/source_estate/occ_mixer.h | 6 ++-- source/source_estate/test/test_occ_mixer.cpp | 22 +++++++-------- .../module_parameter/input_parameter.h | 2 +- .../module_parameter/read_inp_exx_dftu.cpp | 18 ++++++------ source/source_io/test/read_input_ptest.cpp | 2 +- .../test_serial/read_input_item_test.cpp | 12 ++++---- source/source_lcao/lcao_set.cpp | 2 +- source/source_lcao/module_dftu/dftu_nao.cpp | 4 +-- source/source_lcao/module_dftu/dftu_nao.h | 2 +- .../module_dftu/dftu_nao_energy.cpp | 6 ++-- .../source_lcao/module_dftu/dftu_nao_fs_k.cpp | 16 +++++------ .../source_lcao/module_dftu/dftu_nao_fs_k.h | 4 +-- .../source_lcao/module_dftu/dftu_nao_fs_r.cpp | 6 ++-- .../source_lcao/module_dftu/dftu_nao_occ.cpp | 24 ++++++++-------- .../source_lcao/module_dftu/dftu_nao_op.cpp | 12 ++++---- .../source_lcao/module_dftu/dftu_nao_pots.cpp | 8 +++--- .../module_dftu/test/dftu_lcao_test.cpp | 2 +- source/source_lcao/setup_dftu_lcao.cpp | 2 +- source/source_pw/module_pwdft/dftu_base.cpp | 24 ++++++++-------- source/source_pw/module_pwdft/dftu_base.h | 18 ++++++------ .../source_pw/module_pwdft/dftu_base_io.cpp | 22 +++++++-------- source/source_pw/module_pwdft/dftu_base_io.h | 4 +-- .../source_pw/module_pwdft/dftu_base_occ.cpp | 24 ++++++++-------- .../source_pw/module_pwdft/dftu_base_tools.h | 6 ++-- .../module_pwdft/kernels/cuda/force_op.cu | 12 ++++---- .../module_pwdft/kernels/cuda/stress_op.cu | 12 ++++---- .../module_pwdft/kernels/force_op.cpp | 4 +-- .../source_pw/module_pwdft/kernels/force_op.h | 4 +-- .../module_pwdft/kernels/rocm/force_op.hip.cu | 12 ++++---- .../kernels/rocm/stress_op.hip.cu | 12 ++++---- .../module_pwdft/kernels/stress_op.cpp | 4 +-- .../module_pwdft/kernels/stress_op.h | 4 +-- .../module_pwdft/onsite_proj_force_stress.cpp | 4 +-- .../module_pwdft/onsite_proj_tools.h | 4 +-- .../module_pwdft/onsite_proj_tools_force.cpp | 14 +++++----- source/source_pw/module_pwdft/op_pw_proj.cpp | 2 +- source/source_pw/module_pwdft/setup_pot.cpp | 2 +- .../module_pwdft/test/dftu_base_test.cpp | 4 +-- .../module_pwdft/yukawa_screening.cpp | 8 +++--- .../source_pw/module_pwdft/yukawa_screening.h | 6 ++-- 43 files changed, 205 insertions(+), 207 deletions(-) diff --git a/source/source_estate/occ_matrix.cpp b/source/source_estate/occ_matrix.cpp index eb8736a36e4..61094312314 100644 --- a/source/source_estate/occ_matrix.cpp +++ b/source/source_estate/occ_matrix.cpp @@ -4,7 +4,7 @@ #include "source_cell/unitcell.h" void OccupationMatrix::init(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const int nspin, const int npol) { @@ -25,7 +25,7 @@ void OccupationMatrix::init(const UnitCell& cell, occ_save_[iat].resize(cell.atoms[it].nwl + 1); iatlnmipol2iwt_[iat].resize(cell.atoms[it].nwl + 1); - if (orbital_corr[it] == -1) + if (l_channel[it] == -1) { continue; } @@ -123,11 +123,11 @@ void OccupationMatrix::set_flat(const int iat, const int l, const int spin, } } -void OccupationMatrix::zero(const UnitCell& cell, const std::vector& orbital_corr) +void OccupationMatrix::zero(const UnitCell& cell, const std::vector& l_channel) { for (int T = 0; T < cell.ntype; T++) { - if (orbital_corr[T] == -1) + if (l_channel[T] == -1) { continue; } @@ -157,14 +157,14 @@ void OccupationMatrix::zero(const UnitCell& cell, const std::vector& orbita } } -void OccupationMatrix::copy_to_save(const UnitCell& cell, const std::vector& orbital_corr) +void OccupationMatrix::copy_to_save(const UnitCell& cell, const std::vector& l_channel) { ModuleBase::TITLE("OccupationMatrix", "copy_to_save"); ModuleBase::timer::start("OccupationMatrix", "copy_to_save"); for (int T = 0; T < cell.ntype; T++) { - const int target_l = orbital_corr[T]; + const int target_l = l_channel[T]; if (target_l == -1) { continue; @@ -189,7 +189,7 @@ void OccupationMatrix::copy_to_save(const UnitCell& cell, const std::vector } void OccupationMatrix::write_to_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, std::vector& uom) const { @@ -200,7 +200,7 @@ void OccupationMatrix::write_to_flat(const UnitCell& cell, for (int iat = 0; iat < cell.nat; iat++) { const int it = cell.iat2it[iat]; - const int target_l = orbital_corr[it]; + const int target_l = l_channel[it]; if (target_l == -1) { continue; @@ -223,13 +223,13 @@ void OccupationMatrix::write_to_flat(const UnitCell& cell, } void OccupationMatrix::read_from_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, const std::vector& uom) { for (int T = 0; T < cell.ntype; T++) { - const int l = orbital_corr[T]; + const int l = l_channel[T]; if (l == -1) { continue; @@ -261,7 +261,7 @@ void OccupationMatrix::read_from_flat(const UnitCell& cell, } void OccupationMatrix::write_save_to_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, std::vector& uom_save) const { @@ -271,7 +271,7 @@ void OccupationMatrix::write_save_to_flat(const UnitCell& cell, } for (int T = 0; T < cell.ntype; T++) { - const int target_l = orbital_corr[T]; + const int target_l = l_channel[T]; if (target_l == -1) { continue; @@ -318,13 +318,13 @@ namespace elecstate void mix_occ_with_save(std::vector>>>& occ_mat, const std::vector>>>& occ_mat_save, const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const int nspin, const double beta) { for (int T = 0; T < cell.ntype; T++) { - const int target_l = orbital_corr[T]; + const int target_l = l_channel[T]; if (target_l == -1) { continue; diff --git a/source/source_estate/occ_matrix.h b/source/source_estate/occ_matrix.h index 3ac30729fd2..2bffbdea7c6 100644 --- a/source/source_estate/occ_matrix.h +++ b/source/source_estate/occ_matrix.h @@ -22,7 +22,7 @@ class OccupationMatrix public: /// allocate occ/occ_save/iatlnmipol2iwt according to the cell void init(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, int nspin, int npol); @@ -82,23 +82,23 @@ class OccupationMatrix void set_flat(int iat, int l, int spin, const std::vector& occ); // --- whole-array operations --- - void zero(const UnitCell& cell, const std::vector& orbital_corr); - void copy_to_save(const UnitCell& cell, const std::vector& orbital_corr); + void zero(const UnitCell& cell, const std::vector& l_channel); + void copy_to_save(const UnitCell& cell, const std::vector& l_channel); // --- flat mixing buffer (de)serialization over all atoms --- /// write occ into uom at offsets given by index (split spin layout) void write_to_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, std::vector& uom) const; /// read occ from uom at offsets given by index (split spin layout) void read_from_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, const std::vector& uom); /// write occ_save into uom_save (skips when uom_save is empty) void write_save_to_flat(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& index, std::vector& uom_save) const; @@ -121,7 +121,7 @@ namespace elecstate void mix_occ_with_save(std::vector>>>& occ_mat, const std::vector>>>& occ_mat_save, const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, const int nspin, const double beta); } // namespace elecstate diff --git a/source/source_estate/occ_mixer.cpp b/source/source_estate/occ_mixer.cpp index 840ace4308d..c82b7bf3c0a 100644 --- a/source/source_estate/occ_mixer.cpp +++ b/source/source_estate/occ_mixer.cpp @@ -1,13 +1,13 @@ #include "source_estate/occ_mixer.h" void OccMatMixer::init(const UnitCell* cell, - const std::vector* orbital_corr, + const std::vector* l_channel, const std::vector* flat_index, const int nspin, const int total_size) { this->cell_ = cell; - this->orbital_corr_ = orbital_corr; + this->l_channel_ = l_channel; this->index_ = flat_index; this->nspin_ = nspin; this->uom_.resize(total_size, 0.0); @@ -16,7 +16,7 @@ void OccMatMixer::init(const UnitCell* cell, void OccMatMixer::seed_save(const OccupationMatrix& occmat) { - occmat.write_save_to_flat(*this->cell_, *this->orbital_corr_, + occmat.write_save_to_flat(*this->cell_, *this->l_channel_, *this->index_, this->uom_save_); } @@ -25,25 +25,25 @@ void OccMatMixer::begin_iter(OccupationMatrix& occmat) // the caller has already snapshotted occ into occ_save via // OccupationMatrix::copy_to_save; here we only flatten that snapshot // into uom_save_ for the mixing history. - occmat.write_save_to_flat(*this->cell_, *this->orbital_corr_, + occmat.write_save_to_flat(*this->cell_, *this->l_channel_, *this->index_, this->uom_save_); } void OccMatMixer::collect(const OccupationMatrix& occmat) { - occmat.write_to_flat(*this->cell_, *this->orbital_corr_, + occmat.write_to_flat(*this->cell_, *this->l_channel_, *this->index_, this->uom_); } void OccMatMixer::write_back(OccupationMatrix& occmat) { - occmat.read_from_flat(*this->cell_, *this->orbital_corr_, + occmat.read_from_flat(*this->cell_, *this->l_channel_, *this->index_, this->uom_); } void OccMatMixer::mix_plain(OccupationMatrix& occmat, const double beta) { elecstate::mix_occ_with_save(occmat.data(), occmat.data_save(), - *this->cell_, *this->orbital_corr_, + *this->cell_, *this->l_channel_, this->nspin_, beta); } diff --git a/source/source_estate/occ_mixer.h b/source/source_estate/occ_mixer.h index 9d7d22602a8..c425c855bcf 100644 --- a/source/source_estate/occ_mixer.h +++ b/source/source_estate/occ_mixer.h @@ -38,13 +38,13 @@ class OccMatMixer /** * @brief Allocate the flat buffers and bind the layout table. * @param cell unit cell (borrowed, must outlive this object) - * @param orbital_corr per-type correlated-l table (borrowed) + * @param l_channel per-type correlated-l table (borrowed) * @param flat_index per-atom offset table, i.e. pot_uterm_pw_index (borrowed) * @param nspin spin channels (1, 2 or 4) * @param total_size total flat-buffer size (== pot_uterm_pw.size()) */ void init(const UnitCell* cell, - const std::vector* orbital_corr, + const std::vector* l_channel, const std::vector* flat_index, int nspin, int total_size); @@ -99,7 +99,7 @@ class OccMatMixer std::vector uom_save_; ///< previous flat occupation matrix const std::vector* index_ = nullptr; ///< borrowed pot_uterm_pw_index const UnitCell* cell_ = nullptr; ///< borrowed unit cell - const std::vector* orbital_corr_ = nullptr; ///< borrowed correlated-l table + const std::vector* l_channel_ = nullptr; ///< borrowed l_channel table int nspin_ = 0; }; diff --git a/source/source_estate/test/test_occ_mixer.cpp b/source/source_estate/test/test_occ_mixer.cpp index 87a74a8416f..0af0904b8bb 100644 --- a/source/source_estate/test/test_occ_mixer.cpp +++ b/source/source_estate/test/test_occ_mixer.cpp @@ -64,7 +64,7 @@ class OccMatMixerTest : public ::testing::Test cell.itia2iat(0, iat) = iat; } - orbital_corr = {l_corr}; + l_channel = {l_corr}; // per-atom offset table matching Plus_U_Base::init_base layout flat_index.resize(cell.nat); @@ -81,7 +81,7 @@ class OccMatMixerTest : public ::testing::Test UnitCell cell; std::vector atoms_storage; ///< backing store for cell.atoms - std::vector orbital_corr; + std::vector l_channel; std::vector flat_index; }; @@ -97,10 +97,10 @@ TEST_F(OccMatMixerTest, MixPlainNspin1) const int nspin = 1; const int npol = 1; OccupationMatrix occmat; - occmat.init(cell, orbital_corr, nspin, npol); + occmat.init(cell, l_channel, nspin, npol); OccMatMixer mixer; - mixer.init(&cell, &orbital_corr, &flat_index, nspin, total_size(nspin)); + mixer.init(&cell, &l_channel, &flat_index, nspin, total_size(nspin)); // fill occ and occ_save with known distinct values for (int iat = 0; iat < cell.nat; iat++) @@ -130,10 +130,10 @@ TEST_F(OccMatMixerTest, MixPlainNspin2BothChannels) const int nspin = 2; const int npol = 1; OccupationMatrix occmat; - occmat.init(cell, orbital_corr, nspin, npol); + occmat.init(cell, l_channel, nspin, npol); OccMatMixer mixer; - mixer.init(&cell, &orbital_corr, &flat_index, nspin, total_size(nspin)); + mixer.init(&cell, &l_channel, &flat_index, nspin, total_size(nspin)); for (int iat = 0; iat < cell.nat; iat++) { @@ -171,10 +171,10 @@ TEST_F(OccMatMixerTest, FlatRoundtripNspin2) const int nspin = 2; const int npol = 1; OccupationMatrix occmat; - occmat.init(cell, orbital_corr, nspin, npol); + occmat.init(cell, l_channel, nspin, npol); OccMatMixer mixer; - mixer.init(&cell, &orbital_corr, &flat_index, nspin, total_size(nspin)); + mixer.init(&cell, &l_channel, &flat_index, nspin, total_size(nspin)); EXPECT_EQ(mixer.flat_size(), total_size(nspin)); // distinct value per (iat, spin, m) to detect layout mistakes @@ -192,7 +192,7 @@ TEST_F(OccMatMixerTest, FlatRoundtripNspin2) mixer.collect(occmat); // occ -> uom_ // scramble the nested matrix, then restore it from the flat buffer - occmat.zero(cell, orbital_corr); + occmat.zero(cell, l_channel); mixer.write_back(occmat); // uom_ -> occ for (int iat = 0; iat < cell.nat; iat++) @@ -216,10 +216,10 @@ TEST_F(OccMatMixerTest, BeginIterFlattensSave) const int nspin = 1; const int npol = 1; OccupationMatrix occmat; - occmat.init(cell, orbital_corr, nspin, npol); + occmat.init(cell, l_channel, nspin, npol); OccMatMixer mixer; - mixer.init(&cell, &orbital_corr, &flat_index, nspin, total_size(nspin)); + mixer.init(&cell, &l_channel, &flat_index, nspin, total_size(nspin)); for (int m = 0; m < block; m++) { diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index 01f28ff0040..12a7141bd85 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -639,7 +639,7 @@ struct Input_para int occ_mat_ctrl = 0; ///< the mode of occupation matrix control double onsite_radius = 0.0; ///< radius of the sphere for onsite projection (Bohr) std::vector hubbard_u_eV = {}; ///< Hubbard Coulomb interaction parameter U(ev) - std::vector orbital_corr = {}; ///< which correlated orbitals need corrected ; d:2 ,f:3, do not + std::vector l_channel = {}; ///< which correlated orbitals need corrected ; d:2 ,f:3, do not ///< need correction:-1 // ============== #Parameters (17.non-collinear spin-constrained DFT) ========= diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 13515d403ee..29e67de771d 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -603,7 +603,7 @@ void ReadInput::item_dftu() read_sync_int(input.dft_plus_u); item.reset_value = [](const Input_Item& item, Parameter& para) { bool all_minus1 = true; - for (auto& val: para.input.orbital_corr) + for (auto& val: para.input.l_channel) { if (val != -1) { @@ -651,7 +651,7 @@ void ReadInput::item_dftu() this->add_item(item); } { - Input_Item item("orbital_corr"); + Input_Item item("l_channel"); item.annotation = "which correlated orbitals need corrected ; d:2 " ",f:3, do not need correction:-1"; item.category = "DFT+U correction"; @@ -667,7 +667,7 @@ void ReadInput::item_dftu() size_t count = item.get_size(); for (int i = 0; i < count; i++) { - para.input.orbital_corr.push_back(std::stoi(item.str_values[i])); + para.input.l_channel.push_back(std::stoi(item.str_values[i])); } }; @@ -676,21 +676,21 @@ void ReadInput::item_dftu() { return; } - if (para.input.orbital_corr.size() != para.input.ntype) + if (para.input.l_channel.size() != para.input.ntype) { ModuleBase::WARNING_QUIT("ReadInput", - "orbital_corr should have the same " + "l_channel should have the same " "number of elements as ntype"); } - for (auto& val: para.input.orbital_corr) + for (auto& val: para.input.l_channel) { if (val < -1 || val > 3) { - ModuleBase::WARNING_QUIT("ReadInput", "WRONG ARGUMENTS OF orbital_corr"); + ModuleBase::WARNING_QUIT("ReadInput", "WRONG ARGUMENTS OF l_channel"); } } }; - sync_intvec(input.orbital_corr, para.input.ntype, -1); + sync_intvec(input.l_channel, para.input.ntype, -1); this->add_item(item); } { @@ -784,7 +784,7 @@ void ReadInput::item_dftu() }; item.reset_value = [](const Input_Item& item, Parameter& para) { bool all_minus1 = true; - for (auto& val: para.input.orbital_corr) + for (auto& val: para.input.l_channel) { if (val != -1) { diff --git a/source/source_io/test/read_input_ptest.cpp b/source/source_io/test/read_input_ptest.cpp index e15a71f3e5e..948c5618678 100644 --- a/source/source_io/test/read_input_ptest.cpp +++ b/source/source_io/test/read_input_ptest.cpp @@ -389,7 +389,7 @@ TEST_F(InputParaTest, ParaRead) EXPECT_EQ(param.inp.device, "cpu"); EXPECT_NEAR(param.inp.force_thr_ev, 0.025711245953622324, 1e-8); EXPECT_DOUBLE_EQ(param.globalv.hubbard_u[0], 0); - EXPECT_EQ(param.inp.orbital_corr[0], -1); + EXPECT_EQ(param.inp.l_channel[0], -1); EXPECT_EQ(param.inp.mdp.lj_rule, 2); EXPECT_FALSE(param.inp.mdp.lj_eshift); EXPECT_NEAR(param.inp.mdp.lj_epsilon[0], 0.01032, 1e-7); diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 0b393ae487a..48ff0b6330f 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -1782,14 +1782,14 @@ TEST_F(InputTest, Item_test2) { // dft_plus_u auto it = find_label("dft_plus_u", readinput.input_lists); param.input.dft_plus_u = 1; - param.input.orbital_corr = {-1, -1}; + param.input.l_channel = {-1, -1}; it->second.reset_value(it->second, param); EXPECT_EQ(param.input.dft_plus_u, 0); } { // uramping auto it = find_label("uramping", readinput.input_lists); param.sys.uramping = 1; - param.input.orbital_corr = {-1, -1}; + param.input.l_channel = {-1, -1}; it->second.reset_value(it->second, param); EXPECT_EQ(param.sys.uramping, 0); } @@ -1819,11 +1819,11 @@ TEST_F(InputTest, Item_test2) output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("NOTICE")); } - { // orbital_corr - auto it = find_label("orbital_corr", readinput.input_lists); + { // l_channel + auto it = find_label("l_channel", readinput.input_lists); param.input.ntype = 2; it->second.str_values = {"1", "2"}; - param.input.orbital_corr = {1, 2}; + param.input.l_channel = {1, 2}; it->second.check_value(it->second, param); param.input.ntype = 3; testing::internal::CaptureStdout(); @@ -1832,7 +1832,7 @@ TEST_F(InputTest, Item_test2) EXPECT_THAT(output, testing::HasSubstr("NOTICE")); param.input.ntype = 2; - param.input.orbital_corr = {1, 4}; + param.input.l_channel = {1, 4}; testing::internal::CaptureStdout(); EXPECT_EXIT(it->second.check_value(it->second, param), ::testing::ExitedWithCode(1), ""); output = testing::internal::GetCapturedStdout(); diff --git a/source/source_lcao/lcao_set.cpp b/source/source_lcao/lcao_set.cpp index fbab0bcbbd5..92d674bb501 100644 --- a/source/source_lcao/lcao_set.cpp +++ b/source/source_lcao/lcao_set.cpp @@ -84,7 +84,7 @@ void LCAO_domain::set_pot( { dftu.init(ucell, &pv, PARAM.globalv.npol, - inp.nspin, inp.orbital_corr, inp.yukawa_potential, inp.yukawa_lambda, + inp.nspin, inp.l_channel, inp.yukawa_potential, inp.yukawa_lambda, PARAM.globalv.global_readin_dir, PARAM.globalv.global_out_dir, inp.init_chg, diff --git a/source/source_lcao/module_dftu/dftu_nao.cpp b/source/source_lcao/module_dftu/dftu_nao.cpp index 0309509638e..07c21f4843b 100644 --- a/source/source_lcao/module_dftu/dftu_nao.cpp +++ b/source/source_lcao/module_dftu/dftu_nao.cpp @@ -22,7 +22,7 @@ void Plus_U::init(UnitCell& cell, const Parallel_Orbitals* pv, const int npol, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, const bool yukawa_potential, const double yukawa_lambda, const std::string& global_readin_dir, @@ -67,7 +67,7 @@ void Plus_U::init(UnitCell& cell, this->init_base(cell, npol, nspin, - orbital_corr, + l_channel, yukawa_potential, yukawa_lambda, global_readin_dir, diff --git a/source/source_lcao/module_dftu/dftu_nao.h b/source/source_lcao/module_dftu/dftu_nao.h index 46d26ccd3d8..31c552b127b 100644 --- a/source/source_lcao/module_dftu/dftu_nao.h +++ b/source/source_lcao/module_dftu/dftu_nao.h @@ -38,7 +38,7 @@ class Plus_U : public Plus_U_Base const Parallel_Orbitals* pv, const int npol, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, const bool yukawa_potential, const double yukawa_lambda, const std::string& global_readin_dir, diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.cpp b/source/source_lcao/module_dftu/dftu_nao_energy.cpp index dcb1f5949d6..5e128372ad0 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_energy.cpp @@ -30,7 +30,7 @@ void DFTU_LCAO::cal_energy_correction(Plus_U& dftu, const UnitCell& ucell) for (int T = 0; T < ucell.ntype; T++) { const int NL = ucell.atoms[T].nwl + 1; - const int LC = dftu.get_orbital_corr(T); + const int LC = dftu.get_l_channel(T); for (int I = 0; I < ucell.atoms[T].na; I++) { if (LC == -1) @@ -39,11 +39,11 @@ void DFTU_LCAO::cal_energy_correction(Plus_U& dftu, const UnitCell& ucell) } const int iat = ucell.itia2iat(T, I); - const int L = dftu.get_orbital_corr(T); + const int L = dftu.get_l_channel(T); for (int l = 0; l < NL; l++) { - if (l != dftu.get_orbital_corr(T)) + if (l != dftu.get_l_channel(T)) { continue; } diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp index 6fe8c0a68af..7361784bc42 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp @@ -135,7 +135,7 @@ void force_stress(Plus_U& dftu, if (cal_force) { cal_force_gamma(nlocal, npol, - dftu.get_orbital_corr_vec(), dftu.occmat().iatlnmipol2iwt(), + dftu.get_l_channel_vec(), dftu.occmat().iatlnmipol2iwt(), ucell, &rho_pot_onsite[0], pv, fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z, force_dftu); } @@ -182,7 +182,7 @@ void force_stress(Plus_U& dftu, { cal_force_k(nlocal, npol, PARAM.inp.ks_solver, dftu.get_orb_cutoff(), - dftu.get_orbital_corr_vec(), dftu.occmat().iatlnmipol2iwt(), + dftu.get_l_channel_vec(), dftu.occmat().iatlnmipol2iwt(), ucell, gd, fsr, pv, ik, &rho_pot_onsite[0], force_dftu, kv.kvec_d[ik]); } if (cal_stress) @@ -229,7 +229,7 @@ void cal_force_k(const int nlocal, const int npol, const std::string& ks_solver, const std::vector& orb_cutoff, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector>>>>& iatlnmipol2iwt, const UnitCell& ucell, const Grid_Driver& gd, @@ -322,7 +322,7 @@ void cal_force_k(const int nlocal, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = orbital_corr[it]; + const int LC = l_channel[it]; if (LC == -1) continue; @@ -332,7 +332,7 @@ void cal_force_k(const int nlocal, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[it]) + if (l != l_channel[it]) continue; const int N = ucell.atoms[it].l_nchi[l]; @@ -440,7 +440,7 @@ void cal_stress_k(const int nlocal, void cal_force_gamma(const int nlocal, const int npol, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector>>>>& iatlnmipol2iwt, const UnitCell& ucell, const double* rho_pot_onsite, @@ -541,7 +541,7 @@ void cal_force_gamma(const int nlocal, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = orbital_corr[it]; + const int LC = l_channel[it]; if (LC == -1) continue; @@ -551,7 +551,7 @@ void cal_force_gamma(const int nlocal, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[it]) + if (l != l_channel[it]) continue; const int N = ucell.atoms[it].l_nchi[l]; diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.h b/source/source_lcao/module_dftu/dftu_nao_fs_k.h index 87da49d16d8..e3ac9eeb41d 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.h +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.h @@ -49,7 +49,7 @@ void cal_force_k(int nlocal, int npol, const std::string& ks_solver, const std::vector& orb_cutoff, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector>>>>& iatlnmipol2iwt, const UnitCell& ucell, const Grid_Driver& gd, @@ -77,7 +77,7 @@ void cal_stress_k(int nlocal, /// @brief Force contribution at gamma point. void cal_force_gamma(int nlocal, int npol, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector>>>>& iatlnmipol2iwt, const UnitCell& ucell, const double* rho_VU, diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp b/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp index d06da3479fd..6e170cd7527 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp @@ -57,7 +57,7 @@ void cal_fs_nao_r(DFTU>* dftu_op, int T0 = 0; int I0 = 0; dftu_op->get_ucell()->iat2iait(iat0, &I0, &T0); - if (!dftu_op->get_dftu()->has_correlated_orbital(T0)) + if (!dftu_op->get_dftu()->has_l_channel(T0)) { continue; } @@ -79,11 +79,11 @@ void cal_fs_nao_r(DFTU>* dftu_op, int T0 = 0; int I0 = 0; dftu_op->get_ucell()->iat2iait(iat0, &I0, &T0); - if (!dftu_op->get_dftu()->has_correlated_orbital(T0)) + if (!dftu_op->get_dftu()->has_l_channel(T0)) { continue; } - const int target_L = dftu_op->get_dftu()->get_orbital_corr(T0); + const int target_L = dftu_op->get_dftu()->get_l_channel(T0); const int tlp1 = 2 * target_L + 1; AdjacentAtomInfo& adjs = dftu_op->get_adjs_all()[atom_index_all[iat0]]; diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.cpp b/source/source_lcao/module_dftu/dftu_nao_occ.cpp index fe9cef82477..cc84924757d 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_occ.cpp @@ -33,11 +33,11 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, const int nlocal = pv->get_global_row_size(); const std::string& ks_solver = PARAM.inp.ks_solver; const auto& iatlnmipol2iwt = dftu.occmat().iatlnmipol2iwt(); - const std::vector& orbital_corr = dftu.get_orbital_corr_vec(); + const std::vector& l_channel = dftu.get_l_channel_vec(); // copy occ_mat to occ_mat_save, then zero occ_mat - dftu.occmat().copy_to_save(ucell, orbital_corr); - dftu.occmat().zero(ucell, orbital_corr); + dftu.occmat().copy_to_save(ucell, l_channel); + dftu.occmat().zero(ucell, l_channel); //=================Part 1====================== // call SCALAPACK routine to calculate the product of the S and density matrix @@ -90,7 +90,7 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = orbital_corr[it]; + const int LC = l_channel[it]; if (LC == -1) { @@ -103,7 +103,7 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[it]) + if (l != l_channel[it]) { continue; } @@ -165,7 +165,7 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = orbital_corr[it]; + const int LC = l_channel[it]; if (LC == -1) { @@ -178,7 +178,7 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[it]) + if (l != l_channel[it]) { continue; } @@ -288,11 +288,11 @@ void DFTU_LCAO::cal_occ_mat_gamma(const Parallel_Orbitals* pv, const int npol = dftu.occmat().npol(); const int nlocal = pv->get_global_row_size(); const auto& iatlnmipol2iwt = dftu.occmat().iatlnmipol2iwt(); - const std::vector& orbital_corr = dftu.get_orbital_corr_vec(); + const std::vector& l_channel = dftu.get_l_channel_vec(); // copy occ_mat to occ_mat_save, then zero occ_mat - dftu.occmat().copy_to_save(ucell, orbital_corr); - dftu.occmat().zero(ucell, orbital_corr); + dftu.occmat().copy_to_save(ucell, l_channel); + dftu.occmat().zero(ucell, l_channel); //=================Part 1====================== // call PBLAS routine to calculate the product of the S and density matrix @@ -331,7 +331,7 @@ void DFTU_LCAO::cal_occ_mat_gamma(const Parallel_Orbitals* pv, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = orbital_corr[it]; + const int LC = l_channel[it]; if (LC == -1) { @@ -343,7 +343,7 @@ void DFTU_LCAO::cal_occ_mat_gamma(const Parallel_Orbitals* pv, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[it]) + if (l != l_channel[it]) { continue; } diff --git a/source/source_lcao/module_dftu/dftu_nao_op.cpp b/source/source_lcao/module_dftu/dftu_nao_op.cpp index c23ed2be5e0..77a2200b464 100644 --- a/source/source_lcao/module_dftu/dftu_nao_op.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_op.cpp @@ -54,11 +54,11 @@ void hamilt::DFTU>::initialize_HR(const Grid_Driver int T0=0; int I0=0; ucell->iat2iait(iat0, &I0, &T0); - if (!this->dftu->has_correlated_orbital(T0)) + if (!this->dftu->has_l_channel(T0)) { continue; } - const int target_L = this->dftu->get_orbital_corr(T0); + const int target_L = this->dftu->get_l_channel(T0); AdjacentAtomInfo adjs; GridD->Find_atom(*ucell, tau0, T0, I0, &adjs); @@ -106,11 +106,11 @@ void hamilt::DFTU>::cal_nlm_all(const Parallel_Orbi int T0=0; int I0=0; ucell->iat2iait(iat0, &I0, &T0); - if (!this->dftu->has_correlated_orbital(T0)) + if (!this->dftu->has_l_channel(T0)) { continue; } - const int target_L = this->dftu->get_orbital_corr(T0); + const int target_L = this->dftu->get_l_channel(T0); const int tlp1 = 2 * target_L + 1; AdjacentAtomInfo& adjs = this->adjs_all[atom_index++]; @@ -261,11 +261,11 @@ void hamilt::DFTU>::contributeHR() auto tau0 = ucell->get_tau(iat0); int T0, I0; ucell->iat2iait(iat0, &I0, &T0); - if (!this->dftu->has_correlated_orbital(T0)) + if (!this->dftu->has_l_channel(T0)) { continue; } - const int target_L = this->dftu->get_orbital_corr(T0); + const int target_L = this->dftu->get_l_channel(T0); const int tlp1 = 2 * target_L + 1; AdjacentAtomInfo& adjs = this->adjs_all[atom_index++]; diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.cpp b/source/source_lcao/module_dftu/dftu_nao_pots.cpp index 1f7486593e7..640c2f32442 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_pots.cpp @@ -22,7 +22,7 @@ void DFTU_LCAO::pot_onsite_complex(const Plus_U& dftu, for (int it = 0; it < ucell.ntype; ++it) { - if (dftu.get_orbital_corr(it) == -1) + if (dftu.get_l_channel(it) == -1) { continue; } @@ -31,7 +31,7 @@ void DFTU_LCAO::pot_onsite_complex(const Plus_U& dftu, const int iat = ucell.itia2iat(it, ia); for (int L = 0; L <= ucell.atoms[it].nwl; L++) { - if (L != dftu.get_orbital_corr(it)) + if (L != dftu.get_l_channel(it)) { continue; } @@ -95,7 +95,7 @@ void DFTU_LCAO::pot_onsite_real(const Plus_U& dftu, for (int it = 0; it < ucell.ntype; ++it) { - if (dftu.get_orbital_corr(it) == -1) + if (dftu.get_l_channel(it) == -1) { continue; } @@ -104,7 +104,7 @@ void DFTU_LCAO::pot_onsite_real(const Plus_U& dftu, const int iat = ucell.itia2iat(it, ia); for (int L = 0; L <= ucell.atoms[it].nwl; L++) { - if (L != dftu.get_orbital_corr(it)) + if (L != dftu.get_l_channel(it)) { continue; } diff --git a/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp b/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp index 6c6db0902ce..1cc566c69b0 100644 --- a/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp @@ -98,7 +98,7 @@ class DFTUTest : public ::testing::Test } } dftu.u_current = {U_test}; - dftu.orbital_corr = {orbital_c_test}; + dftu.l_channel = {orbital_c_test}; PARAM.input.onsite_radius = 1.0; } diff --git a/source/source_lcao/setup_dftu_lcao.cpp b/source/source_lcao/setup_dftu_lcao.cpp index 4d9d62195e7..7c0a9e064e8 100644 --- a/source/source_lcao/setup_dftu_lcao.cpp +++ b/source/source_lcao/setup_dftu_lcao.cpp @@ -40,7 +40,7 @@ void init_dftu_lcao(const int istep, // update current U with calculated U-J from Slater integrals for (int T = 0; T < ucell.ntype; T++) { - if (dftu_ptr->has_correlated_orbital(T)) + if (dftu_ptr->has_l_channel(T)) { dftu_ptr->set_u_current(T, dftu_ptr->yukawa().get_Ueff(T)); } diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index fffe5ab0f17..20b9464e7b6 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -32,7 +32,7 @@ Plus_U_Base::~Plus_U_Base() void Plus_U_Base::init_base(UnitCell& cell, const int npol, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, const bool yukawa_potential, const double yukawa_lambda, const std::string& global_readin_dir, @@ -51,7 +51,7 @@ void Plus_U_Base::init_base(UnitCell& cell, #endif this->nspin = nspin; - this->orbital_corr = orbital_corr; + this->l_channel = l_channel; this->uramping = uramping; this->occ_mat_ctrl = occ_mat_ctrl; this->u_target = hubbard_u; @@ -66,7 +66,7 @@ void Plus_U_Base::init_base(UnitCell& cell, this->energy_u = 0.0; - this->occmat_.init(cell, orbital_corr, nspin, npol); + this->occmat_.init(cell, l_channel, nspin, npol); this->pot_uterm_pw_index.resize(cell.nat); int pot_index = 0; @@ -78,7 +78,7 @@ void Plus_U_Base::init_base(UnitCell& cell, { const int iat = cell.itia2iat(it, ia); - const int target_l = this->orbital_corr[it]; + const int target_l = this->l_channel[it]; if (target_l == -1) { continue; @@ -125,14 +125,14 @@ void Plus_U_Base::init_base(UnitCell& cell, if (mixing_dftu != 0) { this->occ_mixer_.reset(new OccMatMixer()); - this->occ_mixer_->init(&cell, &this->orbital_corr, + this->occ_mixer_->init(&cell, &this->l_channel, &this->pot_uterm_pw_index, nspin, pot_index); } if (yukawa_potential) { this->yukawa_.reset(new YukawaScreening()); - this->yukawa_->init(cell, orbital_corr, yukawa_lambda); + this->yukawa_->init(cell, l_channel, yukawa_lambda); } else { @@ -145,14 +145,14 @@ void Plus_U_Base::init_base(UnitCell& cell, { std::stringstream sst; sst << global_readin_dir << "dm_onsite_ini.txt"; - DFTU_BASE::read_occup_m(cell, this->occmat_, this->orbital_corr, this->occ_mat_ctrl, + DFTU_BASE::read_occup_m(cell, this->occmat_, this->l_channel, this->occ_mat_ctrl, sst.str(), init_chg, nspin, npol); #ifdef __MPI - DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->orbital_corr, nspin, npol); + DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->l_channel, nspin, npol); #endif this->occ_mat_initialized = true; - this->occmat_.copy_to_save(cell, this->orbital_corr); + this->occmat_.copy_to_save(cell, this->l_channel); if (this->has_occ_mixer()) { // seed the mixing history with the file-loaded occupation matrix @@ -165,16 +165,16 @@ void Plus_U_Base::init_base(UnitCell& cell, { std::stringstream sst; sst << global_readin_dir << "dm_onsite.txt"; - DFTU_BASE::read_occup_m(cell, this->occmat_, this->orbital_corr, this->occ_mat_ctrl, + DFTU_BASE::read_occup_m(cell, this->occmat_, this->l_channel, this->occ_mat_ctrl, sst.str(), init_chg, nspin, npol); #ifdef __MPI - DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->orbital_corr, nspin, npol); + DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->l_channel, nspin, npol); #endif this->occ_mat_initialized = true; } else { - this->occmat_.zero(cell, this->orbital_corr); + this->occmat_.zero(cell, this->l_channel); } } diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index 68c77b8757d..48bd5936ea1 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -29,7 +29,7 @@ class Plus_U_Base void init_base(UnitCell& cell, const int npol, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, const bool yukawa_potential, const double yukawa_lambda, const std::string& global_readin_dir, @@ -44,16 +44,16 @@ class Plus_U_Base void uramping_update(); bool u_converged(); - // --- Accessors for U values and orbital configuration --- + // u_current double get_u_current(int it) const { return u_current[it]; } + void set_u_current(int it, double val) { u_current[it] = val; } int get_num_u_types() const { return static_cast(u_current.size()); } - int get_orbital_corr(int it) const { return orbital_corr[it]; } - bool has_correlated_orbital(int it) const { return orbital_corr[it] != -1; } - /// read-only access to the orbital_corr vector (length ntype) - const std::vector& get_orbital_corr_vec() const { return orbital_corr; } + // l_channel + int get_l_channel(int it) const { return l_channel[it]; } + bool has_l_channel(int it) const { return l_channel[it] != -1; } + const std::vector& get_l_channel_vec() const { return l_channel; } - // --- Accessors for DFT+U configuration --- double get_uramping() const { return uramping; } int get_occ_mat_ctrl() const { return occ_mat_ctrl; } int get_cal_type() const { return cal_type; } @@ -63,7 +63,6 @@ class Plus_U_Base YukawaScreening& yukawa() { return *yukawa_; } const YukawaScreening& yukawa() const { return *yukawa_; } - void set_u_current(int it, double val) { u_current[it] = val; } double get_energy() const { return energy_u; } void set_energy(const double &e) { energy_u = e; } @@ -132,9 +131,8 @@ class Plus_U_Base // --- U values and orbital configuration (set in init_base) --- std::vector u_current; std::vector u_target; - std::vector orbital_corr; + std::vector l_channel; - // --- DFT+U configuration flags --- double uramping = 0.0; int occ_mat_ctrl = 0; int nspin = 0; diff --git a/source/source_pw/module_pwdft/dftu_base_io.cpp b/source/source_pw/module_pwdft/dftu_base_io.cpp index 04ca5278877..c74614d349d 100644 --- a/source/source_pw/module_pwdft/dftu_base_io.cpp +++ b/source/source_pw/module_pwdft/dftu_base_io.cpp @@ -94,7 +94,7 @@ namespace DFTU_BASE void read_occup_m(const UnitCell& ucell, OccupationMatrix& occ, - const std::vector& orbital_corr, + const std::vector& l_channel, const int occ_mat_ctrl, const std::string& fn, const std::string& init_chg, @@ -172,7 +172,7 @@ void read_occup_m(const UnitCell& ucell, for (int l = 0; l < NL; l++) { - if (l != orbital_corr[T]) + if (l != l_channel[T]) { continue; } @@ -253,7 +253,7 @@ void read_occup_m(const UnitCell& ucell, /// element. void local_occup_bcast(const UnitCell& ucell, OccupationMatrix& occ, - const std::vector& orbital_corr, + const std::vector& l_channel, int nspin, int npol) { @@ -261,7 +261,7 @@ void local_occup_bcast(const UnitCell& ucell, for (int T = 0; T < ucell.ntype; T++) { - if (orbital_corr[T] == -1) + if (l_channel[T] == -1) { continue; } @@ -269,11 +269,11 @@ void local_occup_bcast(const UnitCell& ucell, for (int I = 0; I < ucell.atoms[T].na; I++) { const int iat = ucell.itia2iat(T, I); - const int L = orbital_corr[T]; + const int L = l_channel[T]; for (int l = 0; l <= ucell.atoms[T].nwl; l++) { - if (l != orbital_corr[T]) + if (l != l_channel[T]) { continue; } @@ -328,9 +328,9 @@ void output(const Plus_U_Base& dftu, { const int N = ucell.atoms[T].l_nchi[L]; - if (L >= dftu.get_orbital_corr(T) && dftu.has_correlated_orbital(T)) + if (L >= dftu.get_l_channel(T) && dftu.has_l_channel(T)) { - if (L != dftu.get_orbital_corr(T)) + if (L != dftu.get_l_channel(T)) { continue; } @@ -399,12 +399,12 @@ void write_occup_m(const Plus_U_Base& dftu, for (int T = 0; T < ucell.ntype; T++) { - if (!dftu.has_correlated_orbital(T)) + if (!dftu.has_l_channel(T)) { continue; } const int NL = ucell.atoms[T].nwl + 1; - const int LC = dftu.get_orbital_corr(T); + const int LC = dftu.get_l_channel(T); for (int I = 0; I < ucell.atoms[T].na; I++) { @@ -412,7 +412,7 @@ void write_occup_m(const Plus_U_Base& dftu, for (int l = 0; l < NL; l++) { - if (l != dftu.get_orbital_corr(T)) + if (l != dftu.get_l_channel(T)) { continue; } diff --git a/source/source_pw/module_pwdft/dftu_base_io.h b/source/source_pw/module_pwdft/dftu_base_io.h index ed48701f2e5..291602f3a22 100644 --- a/source/source_pw/module_pwdft/dftu_base_io.h +++ b/source/source_pw/module_pwdft/dftu_base_io.h @@ -24,7 +24,7 @@ using OccMatData = std::vector& orbital_corr, + const std::vector& l_channel, const int occ_mat_ctrl, const std::string& fn, const std::string& init_chg, @@ -36,7 +36,7 @@ void read_occup_m(const UnitCell& ucell, /// Implemented in dftu_base_io.cpp (only available in MPI builds). void local_occup_bcast(const UnitCell& ucell, OccupationMatrix& occ, - const std::vector& orbital_corr, + const std::vector& l_channel, int nspin, int npol); diff --git a/source/source_pw/module_pwdft/dftu_base_occ.cpp b/source/source_pw/module_pwdft/dftu_base_occ.cpp index 666c5aaf07a..f1bfc9fbb2f 100644 --- a/source/source_pw/module_pwdft/dftu_base_occ.cpp +++ b/source/source_pw/module_pwdft/dftu_base_occ.cpp @@ -33,29 +33,29 @@ void Plus_U_Base::cal_occ_pw(const void* psi_in, const int kpar) { ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); - this->occmat_.copy_to_save(cell, this->orbital_corr); + this->occmat_.copy_to_save(cell, this->l_channel); if(this->has_occ_mixer()) { this->occ_mixer().begin_iter(this->occmat_); } - this->occmat_.zero(cell, this->orbital_corr); + this->occmat_.zero(cell, this->l_channel); if(this->device == "cpu") { DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, this->nspin, this->orbital_corr, this->occmat_); + psi_in, wg_in, cell, isk, this->nspin, this->l_channel, this->occmat_); } #if defined(__CUDA) || defined(__ROCM) else { DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, this->nspin, this->orbital_corr, this->occmat_); + psi_in, wg_in, cell, isk, this->nspin, this->l_channel, this->occmat_); } #endif // reduce occ_mat across k-pools DFTU_BASE::reduce_occ_mat(cell, this->nspin, kpar, - this->orbital_corr, this->occmat_); + this->l_channel, this->occmat_); // mixing: flatten the fresh occ, mix against the saved one, write back if(this->has_occ_mixer() && p_chgmix != nullptr) @@ -66,7 +66,7 @@ void Plus_U_Base::cal_occ_pw(const void* psi_in, } DFTU_BASE::compute_pot_uterm_and_energy(cell, this->nspin, - this->u_current, this->orbital_corr, this->pot_uterm_pw_index, + this->u_current, this->l_channel, this->pot_uterm_pw_index, this->occmat_, this->pot_uterm_pw, this->energy_u); ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); @@ -77,13 +77,13 @@ namespace DFTU_BASE { void reduce_occ_mat(const UnitCell& cell, const int nspin, const int kpar, - const std::vector& orbital_corr, + const std::vector& l_channel, OccupationMatrix& occmat) { for(int iat = 0; iat < cell.nat; iat++) { const int it = cell.iat2it[iat]; - const int target_l = orbital_corr[it]; + const int target_l = l_channel[it]; if(target_l == -1) { continue; @@ -117,7 +117,7 @@ void reduce_occ_mat(const UnitCell& cell, void compute_pot_uterm_and_energy(const UnitCell& cell, const int nspin, const std::vector& u_current, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& pot_uterm_pw_index, const OccupationMatrix& occmat, std::vector>& pot_uterm_pw, @@ -130,7 +130,7 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, for(int iat = 0; iat < cell.nat; iat++) { const int it = cell.iat2it[iat]; - const int target_l = orbital_corr[it]; + const int target_l = l_channel[it]; if(target_l == -1) { continue; @@ -185,7 +185,7 @@ void accumulate_occ_one_k(const void* psi_in, const UnitCell& cell, const int* isk, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, OccupationMatrix& occmat) { auto* onsite_p = projectors::OnsiteProjector::get_instance(); @@ -208,7 +208,7 @@ void accumulate_occ_one_k(const void* psi_in, { const int it = cell.iat2it[iat]; const int nh = onsite_p->get_nh(iat); - const int target_l = orbital_corr[it]; + const int target_l = l_channel[it]; if(target_l == -1) { begin_ih += nh; diff --git a/source/source_pw/module_pwdft/dftu_base_tools.h b/source/source_pw/module_pwdft/dftu_base_tools.h index 57aca9226c4..7f1099512ee 100644 --- a/source/source_pw/module_pwdft/dftu_base_tools.h +++ b/source/source_pw/module_pwdft/dftu_base_tools.h @@ -110,7 +110,7 @@ void accumulate_occ_scalar( void reduce_occ_mat(const UnitCell& cell, const int nspin, const int kpar, - const std::vector& orbital_corr, + const std::vector& l_channel, OccupationMatrix& occmat); /// compute effective potential pot_onsite and DFT+U energy from occ_mat. @@ -128,7 +128,7 @@ void reduce_occ_mat(const UnitCell& cell, void compute_pot_uterm_and_energy(const UnitCell& cell, const int nspin, const std::vector& u_current, - const std::vector& orbital_corr, + const std::vector& l_channel, const std::vector& pot_uterm_pw_index, const OccupationMatrix& occmat, std::vector>& pot_uterm_pw, @@ -144,7 +144,7 @@ void accumulate_occ_one_k(const void* psi_in, const UnitCell& cell, const int* isk, const int nspin, - const std::vector& orbital_corr, + const std::vector& l_channel, OccupationMatrix& occmat); } // namespace DFTU_BASE diff --git a/source/source_pw/module_pwdft/kernels/cuda/force_op.cu b/source/source_pw/module_pwdft/kernels/cuda/force_op.cu index deb42bfa405..c99ebe0228c 100644 --- a/source/source_pw/module_pwdft/kernels/cuda/force_op.cu +++ b/source/source_pw/module_pwdft/kernels/cuda/force_op.cu @@ -329,16 +329,16 @@ __global__ void cal_force_onsite(int wg_nc, FPTYPE tpiba, const FPTYPE* d_wg, const thrust::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const thrust::complex* becp, const thrust::complex* dbecp, FPTYPE* force) { const int ib = blockIdx.x / ntype; const int it = blockIdx.x % ntype; - if (orbital_corr[it] == -1) + if (l_channel[it] == -1) return; - const int orbital_l = orbital_corr[it]; + const int orbital_l = l_channel[it]; const int ip_begin = orbital_l * orbital_l; const int tlp1 = 2 * orbital_l + 1; const int tlp1_2 = tlp1 * tlp1; @@ -483,7 +483,7 @@ void cal_force_nl_op::operator()(const base_dev const FPTYPE& tpiba, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* force) @@ -502,7 +502,7 @@ void cal_force_nl_op::operator()(const base_dev tpiba, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), force); @@ -521,7 +521,7 @@ void cal_force_nl_op::operator()(const base_dev tpiba, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), force); diff --git a/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu b/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu index ea73f8eb28e..9e29a364b6e 100644 --- a/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu +++ b/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu @@ -937,15 +937,15 @@ __global__ void cal_stress_onsite( const int *atom_na, const FPTYPE *d_wg, const thrust::complex *pot_onsite, - const int* orbital_corr, + const int* l_channel, const thrust::complex *becp, const thrust::complex *dbecp, FPTYPE *stress) { const int ib = blockIdx.x / ntype; const int it = blockIdx.x % ntype; - if(orbital_corr[it] == -1) return; - const int orbital_l = orbital_corr[it]; + if(l_channel[it] == -1) return; + const int orbital_l = l_channel[it]; const int ip_begin = orbital_l * orbital_l; const int tlp1 = 2 * orbital_l + 1; const int tlp1_2 = tlp1 * tlp1; @@ -1074,7 +1074,7 @@ void cal_stress_nl_op::operator()(const base_de const int* atom_na, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* stress) @@ -1090,7 +1090,7 @@ void cal_stress_nl_op::operator()(const base_de atom_na, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), stress); @@ -1106,7 +1106,7 @@ void cal_stress_nl_op::operator()(const base_de atom_na, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), stress); diff --git a/source/source_pw/module_pwdft/kernels/force_op.cpp b/source/source_pw/module_pwdft/kernels/force_op.cpp index 5c80e6663b2..7d0f4da615f 100644 --- a/source/source_pw/module_pwdft/kernels/force_op.cpp +++ b/source/source_pw/module_pwdft/kernels/force_op.cpp @@ -298,7 +298,7 @@ struct cal_force_nl_op const FPTYPE& tpiba, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* force) @@ -307,7 +307,7 @@ struct cal_force_nl_op int sum0 = 0; for (int it = 0; it < ntype; it++) { - const int orbital_l = orbital_corr[it]; + const int orbital_l = l_channel[it]; const int nproj = atom_nh[it]; if(orbital_l == -1) { diff --git a/source/source_pw/module_pwdft/kernels/force_op.h b/source/source_pw/module_pwdft/kernels/force_op.h index 5ce771fedc1..0067e510744 100644 --- a/source/source_pw/module_pwdft/kernels/force_op.h +++ b/source/source_pw/module_pwdft/kernels/force_op.h @@ -126,7 +126,7 @@ struct cal_force_nl_op const FPTYPE& tpiba, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* force); @@ -258,7 +258,7 @@ struct cal_force_nl_op const FPTYPE& tpiba, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* force); diff --git a/source/source_pw/module_pwdft/kernels/rocm/force_op.hip.cu b/source/source_pw/module_pwdft/kernels/rocm/force_op.hip.cu index 68b7f4cf453..b7dcc54fe12 100644 --- a/source/source_pw/module_pwdft/kernels/rocm/force_op.hip.cu +++ b/source/source_pw/module_pwdft/kernels/rocm/force_op.hip.cu @@ -315,16 +315,16 @@ __global__ void cal_force_onsite(int wg_nc, FPTYPE tpiba, const FPTYPE* d_wg, const thrust::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const thrust::complex* becp, const thrust::complex* dbecp, FPTYPE* force) { const int ib = blockIdx.x / ntype; const int it = blockIdx.x % ntype; - if (orbital_corr[it] == -1) + if (l_channel[it] == -1) return; - const int orbital_l = orbital_corr[it]; + const int orbital_l = l_channel[it]; const int ip_begin = orbital_l * orbital_l; const int tlp1 = 2 * orbital_l + 1; const int tlp1_2 = tlp1 * tlp1; @@ -469,7 +469,7 @@ void cal_force_nl_op::operator()(const base_dev const FPTYPE& tpiba, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* force) @@ -492,7 +492,7 @@ void cal_force_nl_op::operator()(const base_dev tpiba, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), force); @@ -515,7 +515,7 @@ void cal_force_nl_op::operator()(const base_dev tpiba, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), force); diff --git a/source/source_pw/module_pwdft/kernels/rocm/stress_op.hip.cu b/source/source_pw/module_pwdft/kernels/rocm/stress_op.hip.cu index d5c093cb519..90bbee5871d 100644 --- a/source/source_pw/module_pwdft/kernels/rocm/stress_op.hip.cu +++ b/source/source_pw/module_pwdft/kernels/rocm/stress_op.hip.cu @@ -926,15 +926,15 @@ __global__ void cal_stress_onsite( const int *atom_na, const FPTYPE *d_wg, const thrust::complex *pot_onsite, - const int* orbital_corr, + const int* l_channel, const thrust::complex *becp, const thrust::complex *dbecp, FPTYPE *stress) { const int ib = blockIdx.x / ntype; const int it = blockIdx.x % ntype; - if(orbital_corr[it] == -1) return; - const int orbital_l = orbital_corr[it]; + if(l_channel[it] == -1) return; + const int orbital_l = l_channel[it]; const int ip_begin = orbital_l * orbital_l; const int tlp1 = 2 * orbital_l + 1; const int tlp1_2 = tlp1 * tlp1; @@ -1063,7 +1063,7 @@ void cal_stress_nl_op::operator()(const base_de const int* atom_na, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* stress) @@ -1079,7 +1079,7 @@ void cal_stress_nl_op::operator()(const base_de atom_na, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), stress); @@ -1095,7 +1095,7 @@ void cal_stress_nl_op::operator()(const base_de atom_na, d_wg, reinterpret_cast*>(pot_onsite), - orbital_corr, + l_channel, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), stress); diff --git a/source/source_pw/module_pwdft/kernels/stress_op.cpp b/source/source_pw/module_pwdft/kernels/stress_op.cpp index a6d0612b651..aff61a53d69 100644 --- a/source/source_pw/module_pwdft/kernels/stress_op.cpp +++ b/source/source_pw/module_pwdft/kernels/stress_op.cpp @@ -256,7 +256,7 @@ struct cal_stress_nl_op const int* atom_na, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* stress) @@ -266,7 +266,7 @@ struct cal_stress_nl_op int sum = 0; for (int it = 0; it < ntype; it++) { - const int orbital_l = orbital_corr[it]; + const int orbital_l = l_channel[it]; const int nproj = atom_nh[it]; if(orbital_l == -1) { diff --git a/source/source_pw/module_pwdft/kernels/stress_op.h b/source/source_pw/module_pwdft/kernels/stress_op.h index 260053dba68..fd61c483550 100644 --- a/source/source_pw/module_pwdft/kernels/stress_op.h +++ b/source/source_pw/module_pwdft/kernels/stress_op.h @@ -133,7 +133,7 @@ struct cal_stress_nl_op const int* atom_na, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* stress); @@ -341,7 +341,7 @@ struct cal_stress_nl_op const int* atom_na, const FPTYPE* d_wg, const std::complex* pot_onsite, - const int* orbital_corr, + const int* l_channel, const std::complex* becp, const std::complex* dbecp, FPTYPE* stress); diff --git a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp index e794839ffe8..4fa3cab3bff 100644 --- a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp +++ b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp @@ -12,7 +12,7 @@ void projectors::OnsiteProjector::cal_force_onsite_dftu(int ik, int n const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(isk_val); const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(); this->fs_tools->cal_force_dftu(ik, npm, force, - dftu.get_orbital_corr_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); + dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } template @@ -24,7 +24,7 @@ double projectors::OnsiteProjector::cal_stress_onsite_dftu(int ik, in const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(isk_val); const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(); return this->fs_tools->cal_stress_dftu(ik, npm, - dftu.get_orbital_corr_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); + dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } template diff --git a/source/source_pw/module_pwdft/onsite_proj_tools.h b/source/source_pw/module_pwdft/onsite_proj_tools.h index 6c3ecc0a377..7e8bfd2facf 100644 --- a/source/source_pw/module_pwdft/onsite_proj_tools.h +++ b/source/source_pw/module_pwdft/onsite_proj_tools.h @@ -77,7 +77,7 @@ class Onsite_Proj_tools int ik, int npm, FPTYPE* force, - const int* orbital_corr, + const int* l_channel, const std::complex* pot_onsite, const int size_pot_onsite, const FPTYPE* h_wg @@ -95,7 +95,7 @@ class Onsite_Proj_tools double cal_stress_dftu( int ik, int npm, - const int* orbital_corr, + const int* l_channel, const std::complex* pot_onsite, const int size_pot_onsite, const FPTYPE* h_wg diff --git a/source/source_pw/module_pwdft/onsite_proj_tools_force.cpp b/source/source_pw/module_pwdft/onsite_proj_tools_force.cpp index 2b49560b5dc..7c326c0ab8f 100644 --- a/source/source_pw/module_pwdft/onsite_proj_tools_force.cpp +++ b/source/source_pw/module_pwdft/onsite_proj_tools_force.cpp @@ -18,18 +18,18 @@ template void Onsite_Proj_tools::cal_force_dftu(int ik, int npm, FPTYPE* force, - const int* orbital_corr, + const int* l_channel, const std::complex* pot_onsite, const int size_pot_onsite, const FPTYPE* h_wg) { - int* orbital_corr_tmp = nullptr; + int* l_channel_tmp = nullptr; std::complex* pot_onsite_tmp = nullptr; #if defined(__CUDA) || defined(__ROCM) if (this->device == base_device::GpuDevice) { - resmem_int_op()(orbital_corr_tmp, this->ucell_->ntype); - syncmem_int_h2d_op()(orbital_corr_tmp, orbital_corr, this->ucell_->ntype); + resmem_int_op()(l_channel_tmp, this->ucell_->ntype); + syncmem_int_h2d_op()(l_channel_tmp, l_channel, this->ucell_->ntype); resmem_complex_op()(pot_onsite_tmp, size_pot_onsite); syncmem_complex_h2d_op()(pot_onsite_tmp, pot_onsite, size_pot_onsite); syncmem_var_h2d_op()(d_wg, h_wg, this->nbands * (ik+1)); @@ -37,7 +37,7 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, else #endif { - orbital_corr_tmp = const_cast(orbital_corr); + l_channel_tmp = const_cast(l_channel); pot_onsite_tmp = const_cast*>(pot_onsite); d_wg = const_cast(h_wg); } @@ -57,7 +57,7 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, this->ucell_->tpiba, d_wg, pot_onsite_tmp, - orbital_corr_tmp, + l_channel_tmp, becp, dbecp, force); @@ -65,7 +65,7 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, if (this->device == base_device::GpuDevice) { delmem_complex_op()(pot_onsite_tmp); - delmem_int_op()(orbital_corr_tmp); + delmem_int_op()(l_channel_tmp); } #endif } diff --git a/source/source_pw/module_pwdft/op_pw_proj.cpp b/source/source_pw/module_pwdft/op_pw_proj.cpp index 9321138cc90..4dfe83d0384 100644 --- a/source/source_pw/module_pwdft/op_pw_proj.cpp +++ b/source/source_pw/module_pwdft/op_pw_proj.cpp @@ -221,7 +221,7 @@ void OnsiteProj>::setup_pw_dftu_indices() const for(int iat=0;iatucell->nat;iat++) { const int it = this->ucell->iat2it[iat]; - const int target_l = this->dftu->get_orbital_corr(it); + const int target_l = this->dftu->get_l_channel(it); orb_l_iat0[iat] = target_l; const int nproj = onsite_p->get_nh(iat); if(target_l == -1) diff --git a/source/source_pw/module_pwdft/setup_pot.cpp b/source/source_pw/module_pwdft/setup_pot.cpp index 1f1364d444f..4541f891a9d 100644 --- a/source/source_pw/module_pwdft/setup_pot.cpp +++ b/source/source_pw/module_pwdft/setup_pot.cpp @@ -123,7 +123,7 @@ void pw::setup_pot(const int istep, { dftu.init_base(ucell, PARAM.globalv.npol, - inp.nspin, inp.orbital_corr, inp.yukawa_potential, + inp.nspin, inp.l_channel, inp.yukawa_potential, inp.yukawa_lambda, PARAM.globalv.global_readin_dir, PARAM.globalv.global_out_dir, diff --git a/source/source_pw/module_pwdft/test/dftu_base_test.cpp b/source/source_pw/module_pwdft/test/dftu_base_test.cpp index 87248b9e46e..b33d6f628a3 100644 --- a/source/source_pw/module_pwdft/test/dftu_base_test.cpp +++ b/source/source_pw/module_pwdft/test/dftu_base_test.cpp @@ -76,12 +76,12 @@ class DFTUBaseTest : public testing::Test /// Call init_base with the given Yukawa switch on a fresh d orbital void init_dftu(Plus_U_Base& dftu, const bool yukawa_potential) { - const std::vector orbital_corr = {2}; + const std::vector l_channel = {2}; const std::vector hubbard_u = {0.0}; dftu.init_base(ucell, 1, // npol 2, // nspin - orbital_corr, + l_channel, yukawa_potential, 0.5, // yukawa_lambda "", // global_readin_dir diff --git a/source/source_pw/module_pwdft/yukawa_screening.cpp b/source/source_pw/module_pwdft/yukawa_screening.cpp index 9f5892d28fc..61498299b3f 100644 --- a/source/source_pw/module_pwdft/yukawa_screening.cpp +++ b/source/source_pw/module_pwdft/yukawa_screening.cpp @@ -15,12 +15,12 @@ #include void YukawaScreening::init(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, double yukawa_lambda_cfg) { this->yukawa_lambda_cfg_ = yukawa_lambda_cfg; this->lambda_ = 0.0; - this->orbital_corr_ = orbital_corr; + this->l_channel_ = l_channel; this->Fk_.resize(cell.ntype); this->U_Yukawa_.resize(cell.ntype); @@ -214,9 +214,9 @@ void YukawaScreening::cal_slater_UJ(const UnitCell& ucell, for (int L = 0; L < NL; L++) { - if (L >= this->orbital_corr_[T] && this->orbital_corr_[T] != -1) + if (L >= this->l_channel_[T] && this->l_channel_[T] != -1) { - if (L != this->orbital_corr_[T]) + if (L != this->l_channel_[T]) { continue; } diff --git a/source/source_pw/module_pwdft/yukawa_screening.h b/source/source_pw/module_pwdft/yukawa_screening.h index 1cf8e32cfdc..b81c9a2266a 100644 --- a/source/source_pw/module_pwdft/yukawa_screening.h +++ b/source/source_pw/module_pwdft/yukawa_screening.h @@ -26,7 +26,7 @@ class YukawaScreening /// allocate Fk / U_Yukawa / J_Yukawa according to the cell and record the /// user-provided screening length (yukawa_lambda_cfg > 0 means fixed). void init(const UnitCell& cell, - const std::vector& orbital_corr, + const std::vector& l_channel, double yukawa_lambda_cfg); /// determine lambda: use the fixed config value when positive, otherwise @@ -51,7 +51,7 @@ class YukawaScreening /// effective U-J of the correlated orbital (n = 0) for atom type it double get_Ueff(int it) const { - const int l = orbital_corr_[it]; + const int l = l_channel_[it]; return U_Yukawa_[it][l][0] - J_Yukawa_[it][l][0]; } @@ -63,7 +63,7 @@ class YukawaScreening double lambda_ = 0.0; double yukawa_lambda_cfg_ = 0.0; - std::vector orbital_corr_; + std::vector l_channel_; std::vector>>> Fk_; std::vector>> U_Yukawa_; std::vector>> J_Yukawa_; From a5bc9dac6fbcc35814ac19fb0ce2bb1712c4bfbe Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 14:58:53 +0800 Subject: [PATCH 03/33] refactor(dftu): extract cal_occ_pw from Plus_U_Base to free function Move Plus_U_Base::cal_occ_pw to DFTU_BASE::cal_occ_pw in dftu_base_occ.cpp, with all dependencies passed explicitly as parameters. This decouples the PW occupation-matrix calculation from the Plus_U_Base class, making it directly unit-testable. Changes: - dftu_base_tools.h: declare DFTU_BASE::cal_occ_pw with 15 params - dftu_base_occ.cpp: implement as free function, remove member version - dftu_base.h: remove cal_occ_pw declaration, add public accessors (get_nspin, get_device, get_u_current_vec, get_pot_uterm_pw_index, get_pot_uterm_pw, energy_ref) needed by callers - setup_dftu_pw.cpp: call DFTU_BASE::cal_occ_pw via accessors - dftu_base.cpp: update comment to reflect free-function status --- source/source_pw/module_pwdft/dftu_base.cpp | 5 +- source/source_pw/module_pwdft/dftu_base.h | 16 ++++-- .../source_pw/module_pwdft/dftu_base_occ.cpp | 56 +++++++++++-------- .../source_pw/module_pwdft/dftu_base_tools.h | 29 ++++++++++ .../source_pw/module_pwdft/setup_dftu_pw.cpp | 9 ++- 5 files changed, 84 insertions(+), 31 deletions(-) diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index 20b9464e7b6..dfbb3ef86ba 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -227,6 +227,7 @@ bool Plus_U_Base::u_converged() } -// cal_occ_pw() is implemented in source_pw/module_pwdft/dftu_base_occ.cpp -// as a Plus_U_Base method. Pure per-atom kernels live in dftu_base_tools.{h,cpp} +// cal_occ_pw() is implemented as free function DFTU_BASE::cal_occ_pw +// in source_pw/module_pwdft/dftu_base_occ.cpp. +// Pure per-atom kernels live in dftu_base_tools.{h,cpp} // as free functions in namespace DFTU_BASE. diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index 48bd5936ea1..96cb0b7c596 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -70,12 +70,7 @@ class Plus_U_Base /// interface for PW basis /// calculate the local occupation number matrix for PW based wave functions - void cal_occ_pw(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - Charge_Mixing* p_chgmix, - const int* isk, - const int kpar); + /// (implemented as free function DFTU_BASE::cal_occ_pw in dftu_base_occ.cpp) /// get effective potential pointer for the given spin channel (PW basis) /// @@ -122,6 +117,15 @@ class Plus_U_Base const OccMatMixer& occ_mixer() const { return *occ_mixer_; } bool has_occ_mixer() const { return occ_mixer_ != nullptr; } + // --- Accessors for free-function interfaces (e.g. DFTU_BASE::cal_occ_pw) --- + int get_nspin() const { return nspin; } + const std::string& get_device() const { return device; } + const std::vector& get_u_current_vec() const { return u_current; } + const std::vector& get_pot_uterm_pw_index() const { return pot_uterm_pw_index; } + std::vector>& get_pot_uterm_pw() { return pot_uterm_pw; } + const std::vector>& get_pot_uterm_pw() const { return pot_uterm_pw; } + double& energy_ref() { return energy_u; } + private: // --- State flags --- // dftu can be calculated only after occ_mat has been initialized diff --git a/source/source_pw/module_pwdft/dftu_base_occ.cpp b/source/source_pw/module_pwdft/dftu_base_occ.cpp index f1bfc9fbb2f..03aa02e977a 100644 --- a/source/source_pw/module_pwdft/dftu_base_occ.cpp +++ b/source/source_pw/module_pwdft/dftu_base_occ.cpp @@ -12,6 +12,8 @@ +namespace DFTU_BASE { + /// calculate occupation matrix for DFT+U (PW basis) /// /// nspin=1 (npol=1): single spin channel; occ_mat[iat][l][n][0] only; @@ -25,53 +27,63 @@ /// nspin=4 (npol=2): spinor calculation; /// occ_mat has a single matrix of size (2*tlp1) x (2*tlp1) per atom /// storing all 4 Pauli blocks contiguously. -void Plus_U_Base::cal_occ_pw(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - Charge_Mixing* p_chgmix, - const int* isk, - const int kpar) +void cal_occ_pw(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + Charge_Mixing* p_chgmix, + const int* isk, + const int kpar, + const int nspin, + const std::string& device, + const std::vector& l_channel, + const std::vector& u_current, + const std::vector& pot_uterm_pw_index, + OccupationMatrix& occmat, + OccMatMixer* occ_mixer, + std::vector>& pot_uterm_pw, + double& energy_u) { ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); - this->occmat_.copy_to_save(cell, this->l_channel); - if(this->has_occ_mixer()) + occmat.copy_to_save(cell, l_channel); + if (occ_mixer != nullptr) { - this->occ_mixer().begin_iter(this->occmat_); + occ_mixer->begin_iter(occmat); } - this->occmat_.zero(cell, this->l_channel); + occmat.zero(cell, l_channel); - if(this->device == "cpu") + if (device == "cpu") { DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, this->nspin, this->l_channel, this->occmat_); + psi_in, wg_in, cell, isk, nspin, l_channel, occmat); } #if defined(__CUDA) || defined(__ROCM) else { DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, this->nspin, this->l_channel, this->occmat_); + psi_in, wg_in, cell, isk, nspin, l_channel, occmat); } #endif // reduce occ_mat across k-pools - DFTU_BASE::reduce_occ_mat(cell, this->nspin, kpar, - this->l_channel, this->occmat_); + DFTU_BASE::reduce_occ_mat(cell, nspin, kpar, l_channel, occmat); // mixing: flatten the fresh occ, mix against the saved one, write back - if(this->has_occ_mixer() && p_chgmix != nullptr) + if (occ_mixer != nullptr && p_chgmix != nullptr) { - this->occ_mixer().collect(this->occmat_); - p_chgmix->mix_uom(this->occ_mixer().uom(), this->occ_mixer().uom_save()); - this->occ_mixer().write_back(this->occmat_); + occ_mixer->collect(occmat); + p_chgmix->mix_uom(occ_mixer->uom(), occ_mixer->uom_save()); + occ_mixer->write_back(occmat); } - DFTU_BASE::compute_pot_uterm_and_energy(cell, this->nspin, - this->u_current, this->l_channel, this->pot_uterm_pw_index, - this->occmat_, this->pot_uterm_pw, this->energy_u); + DFTU_BASE::compute_pot_uterm_and_energy(cell, nspin, + u_current, l_channel, pot_uterm_pw_index, + occmat, pot_uterm_pw, energy_u); ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); } +} // namespace DFTU_BASE + namespace DFTU_BASE { void reduce_occ_mat(const UnitCell& cell, diff --git a/source/source_pw/module_pwdft/dftu_base_tools.h b/source/source_pw/module_pwdft/dftu_base_tools.h index 7f1099512ee..e95b901012e 100644 --- a/source/source_pw/module_pwdft/dftu_base_tools.h +++ b/source/source_pw/module_pwdft/dftu_base_tools.h @@ -7,6 +7,8 @@ class UnitCell; class OccupationMatrix; +class OccMatMixer; +class Charge_Mixing; /// Free functions for DFT+U PW basis calculations. /// @@ -147,6 +149,33 @@ void accumulate_occ_one_k(const void* psi_in, const std::vector& l_channel, OccupationMatrix& occmat); +/// calculate the local occupation number matrix for PW based wave functions. +/// +/// This is the PW-basis entry point that: +/// 1. saves and zeroes the occupation matrix +/// 2. accumulates it from psi via accumulate_occ_one_k +/// 3. reduces across k-pools via reduce_occ_mat +/// 4. applies occupation-matrix mixing when enabled +/// 5. computes the effective potential and DFT+U energy +/// +/// All state is passed explicitly so this function can be unit-tested +/// without constructing a Plus_U_Base object. +void cal_occ_pw(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + Charge_Mixing* p_chgmix, + const int* isk, + const int kpar, + const int nspin, + const std::string& device, + const std::vector& l_channel, + const std::vector& u_current, + const std::vector& pot_uterm_pw_index, + OccupationMatrix& occmat, + OccMatMixer* occ_mixer, + std::vector>& pot_uterm_pw, + double& energy_u); + } // namespace DFTU_BASE #endif diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index ef7e56b516e..605767ecca5 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -1,6 +1,7 @@ #include "source_pw/module_pwdft/setup_dftu_pw.h" #include "source_pw/module_pwdft/dftu_base.h" // mohan add 2025-11-06 #include "source_pw/module_pwdft/dftu_base_io.h" // mohan add 2025-11-08 +#include "source_pw/module_pwdft/dftu_base_tools.h" #include "source_io/module_parameter/parameter.h" namespace DFTU_BASE @@ -27,7 +28,13 @@ void iter_init_dftu_pw(const int iter, if (dftu.get_occ_mat_ctrl() != 2) { - dftu.cal_occ_pw(psi, wg, ucell, p_chgmix, isk, PARAM.inp.kpar); + DFTU_BASE::cal_occ_pw(psi, wg, ucell, p_chgmix, isk, PARAM.inp.kpar, + dftu.get_nspin(), dftu.get_device(), + dftu.get_l_channel_vec(), dftu.get_u_current_vec(), + dftu.get_pot_uterm_pw_index(), + dftu.occmat(), + dftu.has_occ_mixer() ? &dftu.occ_mixer() : nullptr, + dftu.get_pot_uterm_pw(), dftu.energy_ref()); } DFTU_BASE::output(dftu, ucell, PARAM.inp.out_chg[0], PARAM.globalv.global_out_dir, PARAM.inp.nspin, PARAM.globalv.npol); } From 190fab34bd5ae6f965c180a16cb9fb11004f3bb1 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 15:12:06 +0800 Subject: [PATCH 04/33] refactor(dftu): remove Plus_U_Base::nspin member variable Remove the mutable nspin member from Plus_U_Base to avoid hidden workflow state. The value is now passed explicitly: - init_base keeps its nspin parameter (needed for layout setup) - get_pot_uterm_pw_spin / get_size_pot_uterm_pw_spin take nspin as a function argument - Call sites pass PARAM.inp.nspin at the PW operator boundaries where signatures are fixed by the framework Also add missing parameter.h include to onsite_proj_force_stress.cpp. --- source/source_pw/module_pwdft/dftu_base.cpp | 1 - source/source_pw/module_pwdft/dftu_base.h | 16 ++++++---------- .../module_pwdft/onsite_proj_force_stress.cpp | 9 +++++---- source/source_pw/module_pwdft/op_pw_proj.cpp | 4 ++-- source/source_pw/module_pwdft/setup_dftu_pw.cpp | 2 +- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index dfbb3ef86ba..e829dc63e3c 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -50,7 +50,6 @@ void Plus_U_Base::init_base(UnitCell& cell, ModuleBase::WARNING_QUIT("Plus_U_Base::init_base", "DFT+U module is only accessible in MPI version"); #endif - this->nspin = nspin; this->l_channel = l_channel; this->uramping = uramping; this->occ_mat_ctrl = occ_mat_ctrl; diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index 96cb0b7c596..a3e6784104a 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -57,20 +57,18 @@ class Plus_U_Base double get_uramping() const { return uramping; } int get_occ_mat_ctrl() const { return occ_mat_ctrl; } int get_cal_type() const { return cal_type; } - bool use_yukawa() const { return yukawa_ != nullptr; } - /// access the Yukawa screening object (non-null only when use_yukawa()) + + /// Yukawa screening object (non-null only when use_yukawa()) + bool use_yukawa() const { return yukawa_ != nullptr; } YukawaScreening& yukawa() { return *yukawa_; } const YukawaScreening& yukawa() const { return *yukawa_; } - + // +U energy term double get_energy() const { return energy_u; } void set_energy(const double &e) { energy_u = e; } void set_double_energy() { energy_u *= 2.0; } - /// interface for PW basis - /// calculate the local occupation number matrix for PW based wave functions - /// (implemented as free function DFTU_BASE::cal_occ_pw in dftu_base_occ.cpp) /// get effective potential pointer for the given spin channel (PW basis) /// @@ -78,7 +76,7 @@ class Plus_U_Base /// nspin=2: isk selects spin-up (0) or spin-down (1) half of the /// split layout [all_up | all_dn] /// nspin=4: isk is ignored, returns &pot_uterm_pw[0] (all Pauli blocks) - const std::complex* get_pot_uterm_pw_spin(const int isk) const + const std::complex* get_pot_uterm_pw_spin(const int nspin, const int isk) const { if (nspin == 2 && isk == 1) { @@ -92,7 +90,7 @@ class Plus_U_Base /// nspin=1: full array size /// nspin=2: half of the total (one spin channel in split layout) /// nspin=4: full array size (all Pauli blocks are packed together) - int get_size_pot_uterm_pw_spin() const + int get_size_pot_uterm_pw_spin(const int nspin) const { return (nspin == 2) ? static_cast(pot_uterm_pw.size() / 2) : static_cast(pot_uterm_pw.size()); @@ -118,7 +116,6 @@ class Plus_U_Base bool has_occ_mixer() const { return occ_mixer_ != nullptr; } // --- Accessors for free-function interfaces (e.g. DFTU_BASE::cal_occ_pw) --- - int get_nspin() const { return nspin; } const std::string& get_device() const { return device; } const std::vector& get_u_current_vec() const { return u_current; } const std::vector& get_pot_uterm_pw_index() const { return pot_uterm_pw_index; } @@ -139,7 +136,6 @@ class Plus_U_Base double uramping = 0.0; int occ_mat_ctrl = 0; - int nspin = 0; // --- Occupation matrices --- OccupationMatrix occmat_; diff --git a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp index 4fa3cab3bff..ab9275d0aba 100644 --- a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp +++ b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp @@ -1,5 +1,6 @@ #include +#include "source_io/module_parameter/parameter.h" #include "source_pw/module_pwdft/onsite_proj.h" #include "source_pw/module_pwdft/dftu_base.h" @@ -9,8 +10,8 @@ void projectors::OnsiteProjector::cal_force_onsite_dftu(int ik, int n const double* wg_ik) const { const int isk_val = this->isk_ ? this->isk_[ik] : 0; - const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(isk_val); - const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(); + const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(PARAM.inp.nspin); this->fs_tools->cal_force_dftu(ik, npm, force, dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } @@ -21,8 +22,8 @@ double projectors::OnsiteProjector::cal_stress_onsite_dftu(int ik, in const double* wg_ik) const { const int isk_val = this->isk_ ? this->isk_[ik] : 0; - const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(isk_val); - const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(); + const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(PARAM.inp.nspin); return this->fs_tools->cal_stress_dftu(ik, npm, dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } diff --git a/source/source_pw/module_pwdft/op_pw_proj.cpp b/source/source_pw/module_pwdft/op_pw_proj.cpp index 4dfe83d0384..70ee657a30a 100644 --- a/source/source_pw/module_pwdft/op_pw_proj.cpp +++ b/source/source_pw/module_pwdft/op_pw_proj.cpp @@ -291,8 +291,8 @@ void OnsiteProj>::cal_ps_dftu( } const int isk_val = (PARAM.inp.nspin == 2) ? this->isk[this->ik] : 0; - const std::complex* pot_onsite_host = dftu->get_pot_uterm_pw_spin(isk_val); - const int pot_onsite_size = dftu->get_size_pot_uterm_pw_spin(); + const std::complex* pot_onsite_host = dftu->get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu->get_size_pot_uterm_pw_spin(PARAM.inp.nspin); syncmem_complex_h2d_op()(this->pot_onsite_device, pot_onsite_host, pot_onsite_size); hamilt::onsite_ps_op()( this->ctx, diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index 605767ecca5..ed8275db67a 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -29,7 +29,7 @@ void iter_init_dftu_pw(const int iter, if (dftu.get_occ_mat_ctrl() != 2) { DFTU_BASE::cal_occ_pw(psi, wg, ucell, p_chgmix, isk, PARAM.inp.kpar, - dftu.get_nspin(), dftu.get_device(), + PARAM.inp.nspin, dftu.get_device(), dftu.get_l_channel_vec(), dftu.get_u_current_vec(), dftu.get_pot_uterm_pw_index(), dftu.occmat(), From 6394257da131ba773bbf8d985774cc59dd7f28d9 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 15:58:21 +0800 Subject: [PATCH 05/33] refactor(dftu): rename cal_type to UForm enum with explicit formalism semantics Replace the opaque int cal_type (always 3, never written) in Plus_U_Base with a type-safe enum class UForm that explicitly names the DFT+U formalism and double-counting scheme: - lich_fll = 1: Lichtenstein rotationally invariant + FLL DC - lich_amf = 2: Lichtenstein rotationally invariant + AMF DC - dud_fll = 3: Dudarev simplified + FLL DC (default, implemented) Changes: - dftu_base.h: add UForm enum, replace member and getter - dftu_nao_pots.cpp: switch dispatch to enum cases - dftu_nao_pots.h: update doc comment - dftu_core_test.cpp: update comments The enum preserves the existing placeholder values for future implementation of the Lichtenstein formalism paths. Also rename the per-atom DFT+U effective-potential buffer from pot_uterm_pw/pot_uterm_pw_index to uterm_mat/uterm_mat_index and the related accessors (get_uterm_mat*, get_size_uterm_mat*). The old name suggested a basis-expanded potential; it is actually the small (2l+1)^2 projector coefficient matrix, analogous to the nonlocal-pseudopotential D_ij coefficients, and is basis-independent despite living in the PW/LCAO-shared base class. --- .../module_charge/charge_mixing.cpp | 2 +- source/source_estate/occ_mixer.h | 8 +-- .../source_lcao/module_dftu/dftu_nao_pots.cpp | 11 ++- .../source_lcao/module_dftu/dftu_nao_pots.h | 4 +- .../module_dftu/test/dftu_core_test.cpp | 68 +++++++++---------- .../module_dftu/test/dftu_pw_test.cpp | 18 ++--- source/source_pw/module_pwdft/dftu_base.cpp | 10 +-- source/source_pw/module_pwdft/dftu_base.h | 48 +++++++------ .../source_pw/module_pwdft/dftu_base_occ.cpp | 18 ++--- .../source_pw/module_pwdft/dftu_base_tools.h | 14 ++-- .../module_pwdft/onsite_proj_force_stress.cpp | 8 +-- source/source_pw/module_pwdft/op_pw_proj.cpp | 10 +-- .../source_pw/module_pwdft/setup_dftu_pw.cpp | 4 +- 13 files changed, 115 insertions(+), 108 deletions(-) diff --git a/source/source_estate/module_charge/charge_mixing.cpp b/source/source_estate/module_charge/charge_mixing.cpp index 32c7b4f87e0..640fa480c0a 100644 --- a/source/source_estate/module_charge/charge_mixing.cpp +++ b/source/source_estate/module_charge/charge_mixing.cpp @@ -264,7 +264,7 @@ void Charge_Mixing::allocate_mixing_uom(int uom_size) ModuleBase::TITLE("Charge_Mixing", "allocate_mixing_uom"); ModuleBase::timer::start("Charge_Mixing", "allocate_mixing_uom"); // For nspin=2, uom_size already includes both spin channels - // (pot_uterm_pw.size() = pot_index * 2 for nspin=2) + // (uterm_mat.size() = pot_index * 2 for nspin=2) // So uom_fold should always be 1 this->mixing->init_mixing_data(this->uom_mdata, uom_size, sizeof(double)); this->uom_mdata.reset(); diff --git a/source/source_estate/occ_mixer.h b/source/source_estate/occ_mixer.h index c425c855bcf..a1d5f94eec1 100644 --- a/source/source_estate/occ_mixer.h +++ b/source/source_estate/occ_mixer.h @@ -13,7 +13,7 @@ class UnitCell; * Owns the flattened occupation-matrix buffers used by the charge-mixing * machinery (PW path) and the plain linear mixing kernel (LCAO path). * - * The flat layout reuses the pot_uterm_pw_index offset table: for nspin=2 + * The flat layout reuses the uterm_mat_index offset table: for nspin=2 * the buffer is split into [all_up | all_dn] halves; for nspin=1/4 a single * block per atom is used. Serialization to/from the nested OccupationMatrix * is delegated to OccupationMatrix::{write_to_flat, read_from_flat, @@ -39,9 +39,9 @@ class OccMatMixer * @brief Allocate the flat buffers and bind the layout table. * @param cell unit cell (borrowed, must outlive this object) * @param l_channel per-type correlated-l table (borrowed) - * @param flat_index per-atom offset table, i.e. pot_uterm_pw_index (borrowed) + * @param flat_index per-atom offset table, i.e. uterm_mat_index (borrowed) * @param nspin spin channels (1, 2 or 4) - * @param total_size total flat-buffer size (== pot_uterm_pw.size()) + * @param total_size total flat-buffer size (== uterm_mat.size()) */ void init(const UnitCell* cell, const std::vector* l_channel, @@ -97,7 +97,7 @@ class OccMatMixer private: std::vector uom_; ///< new / mixed flat occupation matrix std::vector uom_save_; ///< previous flat occupation matrix - const std::vector* index_ = nullptr; ///< borrowed pot_uterm_pw_index + const std::vector* index_ = nullptr; ///< borrowed uterm_mat_index const UnitCell* cell_ = nullptr; ///< borrowed unit cell const std::vector* l_channel_ = nullptr; ///< borrowed l_channel table int nspin_ = 0; diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.cpp b/source/source_lcao/module_dftu/dftu_nao_pots.cpp index 640c2f32442..94cf1a70f52 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_pots.cpp @@ -168,15 +168,15 @@ double DFTU_LCAO::get_onsite_pot(const Plus_U& dftu, double pot_onsite = 0.0; - switch (dftu.get_cal_type()) + switch (dftu.get_form()) { - case 1: // rotationally invarient formalism and FLL double counting + case Plus_U_Base::UForm::lich_fll: // Lichtenstein (rotationally invariant) + FLL DC break; - case 2: // rotationally invarient formalism and AMF double counting + case Plus_U_Base::UForm::lich_amf: // Lichtenstein (rotationally invariant) + AMF DC break; - case 3: // simplified formalism and FLL double counting + case Plus_U_Base::UForm::dud_fll: // Dudarev (simplified) + FLL DC if (new_occ_mat) { if (dftu.use_yukawa()) @@ -237,9 +237,6 @@ double DFTU_LCAO::get_onsite_pot(const Plus_U& dftu, } break; - - case 4: // simplified formalism and AMF double counting - break; } return pot_onsite; diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.h b/source/source_lcao/module_dftu/dftu_nao_pots.h index 58fe41838ac..cd489c7e0d3 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.h +++ b/source/source_lcao/module_dftu/dftu_nao_pots.h @@ -13,8 +13,8 @@ namespace DFTU_LCAO { /** * @brief one-body effective onsite potential element for a given (m0,m1) pair. * - * Dispatches on cal_type; only case 3 (simplified formalism with FLL double - * counting) is currently implemented, the other cases return 0. + * Dispatches on UForm; only dud_fll (Dudarev simplified formalism with FLL + * double counting) is currently implemented, the other forms return 0. * * @param dftu Plus_U state providing U/J values and occupation matrices * @param T atom type diff --git a/source/source_lcao/module_dftu/test/dftu_core_test.cpp b/source/source_lcao/module_dftu/test/dftu_core_test.cpp index 60500ac5f0f..1d61578d642 100644 --- a/source/source_lcao/module_dftu/test/dftu_core_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_core_test.cpp @@ -9,14 +9,14 @@ * Unit tests for DFT+U core algorithms. * * These tests target the most complex and bug-prone logic: - * 1. pot_uterm_pw_index calculation for mixed atom types and nspin modes + * 1. uterm_mat_index calculation for mixed atom types and nspin modes * 2. copy_occ_mat <-> set_occ_mat roundtrip (3 data layouts) - * 3. pot_onsite effective potential formula (cal_type=3, FLL) + * 3. pot_onsite effective potential formula (UForm::dud_fll, FLL) * 4. Energy correction and double-counting terms ***********************************************************************/ // ===================================================================== -// 1. pot_uterm_pw_index calculation +// 1. uterm_mat_index calculation // // nspin=1: offset = sum(tlp1^2), total = sum(all tlp1^2) // nspin=2: same per-spin-channel, then pot_index *= 2 (split layout) @@ -27,13 +27,13 @@ class EffPotIndexTest : public ::testing::Test { protected: struct AtomSpec { int l; int na; }; // correlated orbital l, number of atoms - std::vector pot_uterm_pw_index; + std::vector uterm_mat_index; int pot_index; void compute_indices(const std::vector& atoms, int nspin) { pot_index = 0; - pot_uterm_pw_index.resize(atoms.size()); + uterm_mat_index.resize(atoms.size()); for (size_t i = 0; i < atoms.size(); i++) { @@ -42,12 +42,12 @@ class EffPotIndexTest : public ::testing::Test if (nspin == 4) { - pot_uterm_pw_index[i] = pot_index; + uterm_mat_index[i] = pot_index; pot_index += tlp1_npol * tlp1_npol; } else { - pot_uterm_pw_index[i] = pot_index; + uterm_mat_index[i] = pot_index; pot_index += tlp1 * tlp1; } } @@ -64,9 +64,9 @@ TEST_F(EffPotIndexTest, Nspin1_MixedOrbitals) compute_indices(atoms, 1); // p: 9, d: 25, p: 9 - EXPECT_EQ(pot_uterm_pw_index[0], 0); - EXPECT_EQ(pot_uterm_pw_index[1], 9); - EXPECT_EQ(pot_uterm_pw_index[2], 34); + EXPECT_EQ(uterm_mat_index[0], 0); + EXPECT_EQ(uterm_mat_index[1], 9); + EXPECT_EQ(uterm_mat_index[2], 34); EXPECT_EQ(pot_index, 43); // 9 + 25 + 9 } @@ -75,15 +75,15 @@ TEST_F(EffPotIndexTest, Nspin2and4_SplitAndPauli) // nspin=2: 2 d-atoms, split layout [up | dn] std::vector atoms2 = {{2, 1}, {2, 1}}; compute_indices(atoms2, 2); - EXPECT_EQ(pot_uterm_pw_index[0], 0); - EXPECT_EQ(pot_uterm_pw_index[1], 25); + EXPECT_EQ(uterm_mat_index[0], 0); + EXPECT_EQ(uterm_mat_index[1], 25); EXPECT_EQ(pot_index, 100); // (25 + 25) * 2 // nspin=4: d + p atoms, Pauli blocks std::vector atoms4 = {{2, 1}, {1, 1}}; compute_indices(atoms4, 4); - EXPECT_EQ(pot_uterm_pw_index[0], 0); // d: (5*2)^2 = 100 - EXPECT_EQ(pot_uterm_pw_index[1], 100); // p: (3*2)^2 = 36 + EXPECT_EQ(uterm_mat_index[0], 0); // d: (5*2)^2 = 100 + EXPECT_EQ(uterm_mat_index[1], 100); // p: (3*2)^2 = 36 EXPECT_EQ(pot_index, 136); } @@ -107,7 +107,7 @@ static void copy_occ_mat_to_flat( const std::vector& occ_mat_up, const std::vector& occ_mat_dn, std::vector& uom_save, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, int nspin) { if (nspin == 4) @@ -116,7 +116,7 @@ static void copy_occ_mat_to_flat( { int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat_up[iat].data[mm]; + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; } } else if (nspin == 2) // split layout: [up | dn] @@ -127,8 +127,8 @@ static void copy_occ_mat_to_flat( int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) { - uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat_up[iat].data[mm]; - uom_save[half_size + pot_uterm_pw_index[iat] + mm] = occ_mat_dn[iat].data[mm]; + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; + uom_save[half_size + uterm_mat_index[iat] + mm] = occ_mat_dn[iat].data[mm]; } } } @@ -138,7 +138,7 @@ static void copy_occ_mat_to_flat( { int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat_up[iat].data[mm]; + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; } } } @@ -147,7 +147,7 @@ static void set_occ_mat_from_flat( const std::vector& uom_array, std::vector& occ_mat_up, std::vector& occ_mat_dn, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, int nspin) { if (nspin == 4) @@ -156,7 +156,7 @@ static void set_occ_mat_from_flat( { int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - occ_mat_up[iat].data[mm] = uom_array[pot_uterm_pw_index[iat] + mm]; + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; } } else if (nspin == 2) @@ -167,8 +167,8 @@ static void set_occ_mat_from_flat( int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) { - occ_mat_up[iat].data[mm] = uom_array[pot_uterm_pw_index[iat] + mm]; - occ_mat_dn[iat].data[mm] = uom_array[half_size + pot_uterm_pw_index[iat] + mm]; + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; + occ_mat_dn[iat].data[mm] = uom_array[half_size + uterm_mat_index[iat] + mm]; } } } @@ -178,7 +178,7 @@ static void set_occ_mat_from_flat( { int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - occ_mat_up[iat].data[mm] = uom_array[pot_uterm_pw_index[iat] + mm]; + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; } } } @@ -200,10 +200,10 @@ TEST_F(OccMatRoundtripTest, Nspin1and2_SingleAndSplitLayout) for (int i = 0; i < size; i++) occ_mat_up[0].data[i] = static_cast(i + 1); - std::vector pot_uterm_pw_index = {0}; + std::vector uterm_mat_index = {0}; std::vector uom_save(size, 0.0); - copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, pot_uterm_pw_index, 1); - set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, pot_uterm_pw_index, 1); + copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 1); + set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 1); for (int i = 0; i < size; i++) EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); @@ -215,14 +215,14 @@ TEST_F(OccMatRoundtripTest, Nspin1and2_SingleAndSplitLayout) occ_mat_dn[0].data[i] = static_cast(i + 100); } uom_save.assign(total, 0.0); - copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, pot_uterm_pw_index, 2); + copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 2); // Verify split layout for (int i = 0; i < size; i++) { EXPECT_DOUBLE_EQ(uom_save[i], static_cast(i + 1)); EXPECT_DOUBLE_EQ(uom_save[size + i], static_cast(i + 100)); } - set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, pot_uterm_pw_index, 2); + set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 2); for (int i = 0; i < size; i++) { EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); @@ -245,11 +245,11 @@ TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) } int total = std::accumulate(sizes.begin(), sizes.end(), 0); - std::vector pot_uterm_pw_index(specs.size()); + std::vector uterm_mat_index(specs.size()); int offset = 0; for (size_t i = 0; i < specs.size(); i++) { - pot_uterm_pw_index[i] = offset; + uterm_mat_index[i] = offset; offset += sizes[i]; } @@ -265,8 +265,8 @@ TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) std::vector uom_array(total, 0.0); std::vector occ_mat_dn(specs.size()); // unused for nspin=4 - copy_occ_mat_to_flat(occ_mat, occ_mat_dn, uom_array, pot_uterm_pw_index, 4); - set_occ_mat_from_flat(uom_array, occ_mat, occ_mat_dn, pot_uterm_pw_index, 4); + copy_occ_mat_to_flat(occ_mat, occ_mat_dn, uom_array, uterm_mat_index, 4); + set_occ_mat_from_flat(uom_array, occ_mat, occ_mat_dn, uterm_mat_index, 4); for (size_t i = 0; i < specs.size(); i++) for (int j = 0; j < sizes[i]; j++) @@ -274,7 +274,7 @@ TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) } // ===================================================================== -// 3. pot_onsite effective potential formula (cal_type=3, FLL) +// 3. pot_onsite effective potential formula (UForm::dud_fll, FLL) // // pot_onsite[m0,m1] = U * (0.5*delta(m0,m1) - occ_mat[m0,m1]) (diagonal) // pot_onsite[m0,m1] = -U * occ_mat[m0,m1] (off-diagonal) diff --git a/source/source_lcao/module_dftu/test/dftu_pw_test.cpp b/source/source_lcao/module_dftu/test/dftu_pw_test.cpp index fcca0a5a75c..c7c2ba5c0e9 100644 --- a/source/source_lcao/module_dftu/test/dftu_pw_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_pw_test.cpp @@ -285,8 +285,8 @@ TEST_F(DftuPwTest, MultiAtomSplitLayout_Nspin2) const int nat = 2, m_size = 5, size = m_size * m_size; const int P = nat * size, total = P * 2, half_size = P; - // pot_uterm_pw_index: split layout, each atom gets `size` entries - std::vector pot_uterm_pw_index = {0, size}; + // uterm_mat_index: split layout, each atom gets `size` entries + std::vector uterm_mat_index = {0, size}; // Simulate occ_mat values for both atoms std::vector loc_up[2], loc_dn[2]; @@ -302,8 +302,8 @@ TEST_F(DftuPwTest, MultiAtomSplitLayout_Nspin2) std::vector uom_array(total, 0.0); for (int iat = 0; iat < nat; iat++) for (int mm = 0; mm < size; mm++) { - uom_array[pot_uterm_pw_index[iat] + mm] = loc_up[iat][mm]; - uom_array[half_size + pot_uterm_pw_index[iat] + mm] = loc_dn[iat][mm]; + uom_array[uterm_mat_index[iat] + mm] = loc_up[iat][mm]; + uom_array[half_size + uterm_mat_index[iat] + mm] = loc_dn[iat][mm]; } // Verify split layout: first half = all spin-up, second half = all spin-down @@ -314,25 +314,25 @@ TEST_F(DftuPwTest, MultiAtomSplitLayout_Nspin2) // --- Read back and verify round-trip --- for (int iat = 0; iat < nat; iat++) - EXPECT_DOUBLE_EQ(uom_array[pot_uterm_pw_index[iat]], loc_up[iat][0]); + EXPECT_DOUBLE_EQ(uom_array[uterm_mat_index[iat]], loc_up[iat][0]); // --- pot_onsite values in split layout --- const double U_val = 5.0; const double diag_coeff = 0.5; - std::vector> pot_uterm_pw(total, {0.0, 0.0}); + std::vector> uterm_mat(total, {0.0, 0.0}); // atom 0 spin-up pot_onsite - std::complex* pot_onsite_up_0 = &pot_uterm_pw[0]; + std::complex* pot_onsite_up_0 = &uterm_mat[0]; pot_onsite_up_0[0] = U_val * (diag_coeff - loc_up[0][0]); // atom 0 spin-down pot_onsite (split layout: offset by half_size) - std::complex* pot_onsite_dn_0 = &pot_uterm_pw[half_size]; + std::complex* pot_onsite_dn_0 = &uterm_mat[half_size]; pot_onsite_dn_0[0] = U_val * (diag_coeff - loc_dn[0][0]); EXPECT_DOUBLE_EQ(pot_onsite_up_0[0].real(), -1.5); // 5*(0.5-0.8) EXPECT_DOUBLE_EQ(pot_onsite_dn_0[0].real(), 1.5); // 5*(0.5-0.2) // Verify no overlap between atoms in pot_onsite arrays - std::complex* pot_onsite_up_1 = &pot_uterm_pw[size]; + std::complex* pot_onsite_up_1 = &uterm_mat[size]; pot_onsite_up_1[0] = U_val * (diag_coeff - loc_up[1][0]); EXPECT_NE(pot_onsite_up_0[0], pot_onsite_up_1[0]); } diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index e829dc63e3c..81c07fbc081 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -67,7 +67,7 @@ void Plus_U_Base::init_base(UnitCell& cell, this->occmat_.init(cell, l_channel, nspin, npol); - this->pot_uterm_pw_index.resize(cell.nat); + this->uterm_mat_index.resize(cell.nat); int pot_index = 0; int num_locale = 0; @@ -88,12 +88,12 @@ void Plus_U_Base::init_base(UnitCell& cell, const int elem_size = tlp1 * tlp1; if(nspin == 4) { - this->pot_uterm_pw_index[iat] = pot_index; + this->uterm_mat_index[iat] = pot_index; pot_index += tlp1_npol * tlp1_npol; } else { - this->pot_uterm_pw_index[iat] = pot_index; + this->uterm_mat_index[iat] = pot_index; pot_index += elem_size; } @@ -118,14 +118,14 @@ void Plus_U_Base::init_base(UnitCell& cell, if (nspin == 2) pot_index *= 2; - this->pot_uterm_pw.resize(pot_index, 0.0); + this->uterm_mat.resize(pot_index, 0.0); // construct the occupation-matrix mixer only when mixing is enabled if (mixing_dftu != 0) { this->occ_mixer_.reset(new OccMatMixer()); this->occ_mixer_->init(&cell, &this->l_channel, - &this->pot_uterm_pw_index, nspin, pot_index); + &this->uterm_mat_index, nspin, pot_index); } if (yukawa_potential) diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index a3e6784104a..cbebb8a58d6 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -22,6 +22,15 @@ class Plus_U_Base friend class DFTUTest; public: + // DFT+U formalism & double-counting (DC) scheme. + // Only dud_fll is implemented; the others are placeholders (return 0). + enum class UForm + { + lich_fll = 1, // Lichtenstein (rotationally invariant) + FLL DC + lich_amf = 2, // Lichtenstein (rotationally invariant) + AMF DC + dud_fll = 3, // Dudarev (simplified) + FLL DC -- default, implemented + }; + Plus_U_Base(); ~Plus_U_Base(); @@ -56,7 +65,7 @@ class Plus_U_Base double get_uramping() const { return uramping; } int get_occ_mat_ctrl() const { return occ_mat_ctrl; } - int get_cal_type() const { return cal_type; } + UForm get_form() const { return form; } /// Yukawa screening object (non-null only when use_yukawa()) @@ -70,35 +79,36 @@ class Plus_U_Base void set_double_energy() { energy_u *= 2.0; } - /// get effective potential pointer for the given spin channel (PW basis) + /// get the U-term coefficient matrix pointer for the given spin channel + /// (small (2l+1)^2 per-atom matrix, projector coefficient) /// - /// nspin=1: isk is ignored, returns &pot_uterm_pw[0] + /// nspin=1: isk is ignored, returns &uterm_mat[0] /// nspin=2: isk selects spin-up (0) or spin-down (1) half of the /// split layout [all_up | all_dn] - /// nspin=4: isk is ignored, returns &pot_uterm_pw[0] (all Pauli blocks) - const std::complex* get_pot_uterm_pw_spin(const int nspin, const int isk) const + /// nspin=4: isk is ignored, returns &uterm_mat[0] (all Pauli blocks) + const std::complex* get_uterm_mat_spin(const int nspin, const int isk) const { if (nspin == 2 && isk == 1) { - return pot_uterm_pw.data() + pot_uterm_pw.size() / 2; + return uterm_mat.data() + uterm_mat.size() / 2; } - return pot_uterm_pw.data(); + return uterm_mat.data(); } - /// get size of effective potential for a single spin channel (PW basis) + /// get size of the U-term coefficient matrix for a single spin channel /// /// nspin=1: full array size /// nspin=2: half of the total (one spin channel in split layout) /// nspin=4: full array size (all Pauli blocks are packed together) - int get_size_pot_uterm_pw_spin(const int nspin) const + int get_size_uterm_mat_spin(const int nspin) const { - return (nspin == 2) ? static_cast(pot_uterm_pw.size() / 2) - : static_cast(pot_uterm_pw.size()); + return (nspin == 2) ? static_cast(uterm_mat.size() / 2) + : static_cast(uterm_mat.size()); } - int get_size_pot_uterm_pw() const + int get_size_uterm_mat() const { - return pot_uterm_pw.size(); + return uterm_mat.size(); } // dftu can be calculated only after occ_mat has been initialized @@ -118,9 +128,9 @@ class Plus_U_Base // --- Accessors for free-function interfaces (e.g. DFTU_BASE::cal_occ_pw) --- const std::string& get_device() const { return device; } const std::vector& get_u_current_vec() const { return u_current; } - const std::vector& get_pot_uterm_pw_index() const { return pot_uterm_pw_index; } - std::vector>& get_pot_uterm_pw() { return pot_uterm_pw; } - const std::vector>& get_pot_uterm_pw() const { return pot_uterm_pw; } + const std::vector& get_uterm_mat_index() const { return uterm_mat_index; } + std::vector>& get_uterm_mat() { return uterm_mat; } + const std::vector>& get_uterm_mat() const { return uterm_mat; } double& energy_ref() { return energy_u; } private: @@ -147,11 +157,11 @@ class Plus_U_Base // --- Internal state --- double energy_u = 0.0; - int cal_type = 3; + UForm form = UForm::dud_fll; std::string device; - std::vector> pot_uterm_pw; - std::vector pot_uterm_pw_index; + std::vector> uterm_mat; + std::vector uterm_mat_index; // Yukawa screening object; constructed only when use_yukawa() is true. // Owns the screening length, Slater integrals and derived U/J. diff --git a/source/source_pw/module_pwdft/dftu_base_occ.cpp b/source/source_pw/module_pwdft/dftu_base_occ.cpp index 03aa02e977a..24ad924eb01 100644 --- a/source/source_pw/module_pwdft/dftu_base_occ.cpp +++ b/source/source_pw/module_pwdft/dftu_base_occ.cpp @@ -17,7 +17,7 @@ namespace DFTU_BASE { /// calculate occupation matrix for DFT+U (PW basis) /// /// nspin=1 (npol=1): single spin channel; occ_mat[iat][l][n][0] only; -/// pot_uterm_pw has one block of tlp1^2 per atom. +/// uterm_mat has one block of tlp1^2 per atom. /// /// nspin=2 (npol=1): two spin channels stored separately: /// occ_mat[iat][l][n][0] = spin-up, occ_mat[iat][l][n][1] = spin-down; @@ -37,10 +37,10 @@ void cal_occ_pw(const void* psi_in, const std::string& device, const std::vector& l_channel, const std::vector& u_current, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, OccupationMatrix& occmat, OccMatMixer* occ_mixer, - std::vector>& pot_uterm_pw, + std::vector>& uterm_mat, double& energy_u) { ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); @@ -76,8 +76,8 @@ void cal_occ_pw(const void* psi_in, } DFTU_BASE::compute_pot_uterm_and_energy(cell, nspin, - u_current, l_channel, pot_uterm_pw_index, - occmat, pot_uterm_pw, energy_u); + u_current, l_channel, uterm_mat_index, + occmat, uterm_mat, energy_u); ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); } @@ -130,9 +130,9 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, const int nspin, const std::vector& u_current, const std::vector& l_channel, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, const OccupationMatrix& occmat, - std::vector>& pot_uterm_pw, + std::vector>& uterm_mat, double& energy_u) { energy_u = 0.0; @@ -151,7 +151,7 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, //update effective potential const double u_value = u_current[it]; - std::complex* pot_onsite_iat = &(pot_uterm_pw[pot_uterm_pw_index[iat]]); + std::complex* pot_onsite_iat = &(uterm_mat[uterm_mat_index[iat]]); const int m_size = 2 * target_l + 1; if(nspin == 4) @@ -177,7 +177,7 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, // spin-down channel for nspin=2 if(nspin == 2) { - std::complex* pot_onsite_iat1 = &(pot_uterm_pw[pot_uterm_pw.size()/2 + pot_uterm_pw_index[iat]]); + std::complex* pot_onsite_iat1 = &(uterm_mat[uterm_mat.size()/2 + uterm_mat_index[iat]]); energy_u += compute_pot_onsite_scalar( pot_onsite_iat1, occmat.mat(iat, target_l, 0, 1).c, diff --git a/source/source_pw/module_pwdft/dftu_base_tools.h b/source/source_pw/module_pwdft/dftu_base_tools.h index e95b901012e..c180703ab83 100644 --- a/source/source_pw/module_pwdft/dftu_base_tools.h +++ b/source/source_pw/module_pwdft/dftu_base_tools.h @@ -15,7 +15,7 @@ class Charge_Mixing; /// These functions are pure (no access to Plus_U_Base members) so they can be /// unit-tested directly by including this header. The member functions in /// dftu_base_occ.cpp call them after computing per-atom offsets and fetching -/// the relevant member state (occ_mat, pot_uterm_pw, u_current, etc.). +/// the relevant member state (occ_mat, uterm_mat, u_current, etc.). namespace DFTU_BASE { /// transform pot_onsite from Pauli basis to spin basis (in-place, nspin==4 only). @@ -36,7 +36,7 @@ void pauli_to_spin_basis(std::complex* pot_onsite, int m_size); /// returns the energy_u increment. Internally calls pauli_to_spin_basis /// to convert pot_onsite to spin basis in-place. /// -/// pot_onsite: pointer to pot_uterm_pw[pot_uterm_pw_index[iat]] +/// pot_onsite: pointer to uterm_mat[uterm_mat_index[iat]] /// occ: pointer to occ_mat[iat][target_l][0][0].c (4 Pauli blocks packed) double compute_pot_onsite_spinor( std::complex* pot_onsite, @@ -121,7 +121,7 @@ void reduce_occ_mat(const UnitCell& cell, /// - occmat has been accumulated from psi and reduced across k-pools. /// /// Outputs: -/// - pot_uterm_pw: pot_onsite = U * (diag*delta - occ) written per atom +/// - uterm_mat: pot_onsite = U * (diag*delta - occ) written per atom /// nspin=4: 4 Pauli blocks per atom, then transformed to spin basis /// nspin=1: single channel /// nspin=2: two channels in split layout [all_up | all_dn] @@ -131,9 +131,9 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, const int nspin, const std::vector& u_current, const std::vector& l_channel, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, const OccupationMatrix& occmat, - std::vector>& pot_uterm_pw, + std::vector>& uterm_mat, double& energy_u); /// accumulate occ_mat from psi for all k-points (per-device template). @@ -170,10 +170,10 @@ void cal_occ_pw(const void* psi_in, const std::string& device, const std::vector& l_channel, const std::vector& u_current, - const std::vector& pot_uterm_pw_index, + const std::vector& uterm_mat_index, OccupationMatrix& occmat, OccMatMixer* occ_mixer, - std::vector>& pot_uterm_pw, + std::vector>& uterm_mat, double& energy_u); } // namespace DFTU_BASE diff --git a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp index ab9275d0aba..024e077edb3 100644 --- a/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp +++ b/source/source_pw/module_pwdft/onsite_proj_force_stress.cpp @@ -10,8 +10,8 @@ void projectors::OnsiteProjector::cal_force_onsite_dftu(int ik, int n const double* wg_ik) const { const int isk_val = this->isk_ ? this->isk_[ik] : 0; - const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); - const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(PARAM.inp.nspin); + const std::complex* pot_onsite_ptr = dftu.get_uterm_mat_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu.get_size_uterm_mat_spin(PARAM.inp.nspin); this->fs_tools->cal_force_dftu(ik, npm, force, dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } @@ -22,8 +22,8 @@ double projectors::OnsiteProjector::cal_stress_onsite_dftu(int ik, in const double* wg_ik) const { const int isk_val = this->isk_ ? this->isk_[ik] : 0; - const std::complex* pot_onsite_ptr = dftu.get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); - const int pot_onsite_size = dftu.get_size_pot_uterm_pw_spin(PARAM.inp.nspin); + const std::complex* pot_onsite_ptr = dftu.get_uterm_mat_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu.get_size_uterm_mat_spin(PARAM.inp.nspin); return this->fs_tools->cal_stress_dftu(ik, npm, dftu.get_l_channel_vec().data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } diff --git a/source/source_pw/module_pwdft/op_pw_proj.cpp b/source/source_pw/module_pwdft/op_pw_proj.cpp index 70ee657a30a..d783e34db69 100644 --- a/source/source_pw/module_pwdft/op_pw_proj.cpp +++ b/source/source_pw/module_pwdft/op_pw_proj.cpp @@ -183,7 +183,7 @@ void OnsiteProj>::cal_ps_delta_spin(const int npol, const // cal_ps_dftu — compute ps = pot_onsite * becp for DFT+U Hamiltonian contribution // -// pot_uterm_pw layout by nspin: +// uterm_mat layout by nspin: // nspin=1: [iat0_tlp1^2 | iat1_tlp1^2 | ...] // single spin channel, full array uploaded // nspin=2: [iat0_up | iat1_up | ... | iat0_dn | iat1_dn | ...] @@ -260,7 +260,7 @@ void OnsiteProj>::setup_pw_dftu_indices() const syncmem_int_h2d_op()(this->ip_m, ip_m0.data(), onsite_p->get_tot_nproj()); syncmem_int_h2d_op()(this->pot_onsite_begin_iat, pot_onsite_begin_iat0.data(), this->ucell->nat); - resmem_complex_op()(this->pot_onsite_device, dftu->get_size_pot_uterm_pw()); + resmem_complex_op()(this->pot_onsite_device, dftu->get_size_uterm_mat()); } template @@ -291,8 +291,8 @@ void OnsiteProj>::cal_ps_dftu( } const int isk_val = (PARAM.inp.nspin == 2) ? this->isk[this->ik] : 0; - const std::complex* pot_onsite_host = dftu->get_pot_uterm_pw_spin(PARAM.inp.nspin, isk_val); - const int pot_onsite_size = dftu->get_size_pot_uterm_pw_spin(PARAM.inp.nspin); + const std::complex* pot_onsite_host = dftu->get_uterm_mat_spin(PARAM.inp.nspin, isk_val); + const int pot_onsite_size = dftu->get_size_uterm_mat_spin(PARAM.inp.nspin); syncmem_complex_h2d_op()(this->pot_onsite_device, pot_onsite_host, pot_onsite_size); hamilt::onsite_ps_op()( this->ctx, @@ -375,7 +375,7 @@ void OnsiteProj, base_device::DEVICE_GPU>>::cal_p // // nspin handling in cal_ps_dftu: // nspin=1 (npol=1): single spin channel, no spin selection needed -// nspin=2 (npol=1): pot_uterm_pw uses split layout [all_up | all_dn]; +// nspin=2 (npol=1): uterm_mat uses split layout [all_up | all_dn]; // spin-up k-points (isk=0) read from the first half; // spin-down k-points (isk=1) read from the second half. // nspin=4 (npol=2): all 4 Pauli blocks stored per-atom; kernel uses diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index ed8275db67a..b22fb9cf991 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -31,10 +31,10 @@ void iter_init_dftu_pw(const int iter, DFTU_BASE::cal_occ_pw(psi, wg, ucell, p_chgmix, isk, PARAM.inp.kpar, PARAM.inp.nspin, dftu.get_device(), dftu.get_l_channel_vec(), dftu.get_u_current_vec(), - dftu.get_pot_uterm_pw_index(), + dftu.get_uterm_mat_index(), dftu.occmat(), dftu.has_occ_mixer() ? &dftu.occ_mixer() : nullptr, - dftu.get_pot_uterm_pw(), dftu.energy_ref()); + dftu.get_uterm_mat(), dftu.energy_ref()); } DFTU_BASE::output(dftu, ucell, PARAM.inp.out_chg[0], PARAM.globalv.global_out_dir, PARAM.inp.nspin, PARAM.globalv.npol); } From 17f439b5ba8c016cf2c0804dc4b53de534eb851f Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 16:02:47 +0800 Subject: [PATCH 06/33] docs: sync parameters.yaml with C++ source for l_channel Update docs/parameters.yaml to use l_channel instead of orbital_corr, matching the parameter name change in the C++ source (commit eabfabcc). --- docs/parameters.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 4c097ada35e..8f3c5e7f2be 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -4677,7 +4677,7 @@ parameters: default_value: "False" unit: "" availability: basis_type==lcao - - name: orbital_corr + - name: l_channel category: DFT+U correction type: Vector of Integer (n values where n is the number of atomic types) description: | From 761f8d5f6f58ff53794e0a16bb9b095304317b58 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 16:34:32 +0800 Subject: [PATCH 07/33] refactor(io): pass Input_para explicitly to ctrl_output_fp Remove PARAM.inp dependency from ModuleIO::ctrl_output_fp by adding a const Input_para& parameter, and update the single call site in ESolver_FP::after_scf to forward *this->inp_. --- source/source_esolver/esolver_fp.cpp | 2 +- .../source_io/module_ctrl/ctrl_output_fp.cpp | 38 ++++++++++--------- source/source_io/module_ctrl/ctrl_output_fp.h | 3 ++ 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/source/source_esolver/esolver_fp.cpp b/source/source_esolver/esolver_fp.cpp index 0d824a84244..35dc1ebb4ab 100644 --- a/source/source_esolver/esolver_fp.cpp +++ b/source/source_esolver/esolver_fp.cpp @@ -153,7 +153,7 @@ void ESolver_FP::after_scf(UnitCell& ucell, const int istep, const bool conv_eso CE.update_delta_rho(ucell, &(this->chr), &(this->sf)); //! print out charge density, potential, elf, etc. - ModuleIO::ctrl_output_fp(ucell, this->pelec, this->pw_big, this->pw_rhod, + ModuleIO::ctrl_output_fp(ucell, *this->inp_, this->pelec, this->pw_big, this->pw_rhod, this->chr, this->solvent, this->Pgrid, istep); } diff --git a/source/source_io/module_ctrl/ctrl_output_fp.cpp b/source/source_io/module_ctrl/ctrl_output_fp.cpp index 318c571e3c4..e00dbe3f03f 100644 --- a/source/source_io/module_ctrl/ctrl_output_fp.cpp +++ b/source/source_io/module_ctrl/ctrl_output_fp.cpp @@ -5,6 +5,7 @@ #include "source_hamilt/module_xc/xc_functional.h" // use XC_Functional #include "source_estate/write_elecstat_pot.h" // use write_elecstat_pot #include "source_io/module_elf/write_elf.h" +#include "source_io/module_parameter/input_parameter.h" // use Input_para #ifdef __LIBXC #include "source_io/module_chgpot/write_libxc_r.h" @@ -14,6 +15,7 @@ namespace ModuleIO { void ctrl_output_fp(UnitCell& ucell, + const Input_para& inp, elecstate::ElecState* pelec, ModulePW::PW_Basis_Big* pw_big, ModulePW::PW_Basis* pw_rhod, @@ -25,30 +27,30 @@ void ctrl_output_fp(UnitCell& ucell, ModuleBase::TITLE("ModuleIO", "ctrl_output_fp"); ModuleBase::timer::start("ModuleIO", "ctrl_output_fp"); - const bool out_app_flag = PARAM.inp.out_app_flag; + const bool out_app_flag = inp.out_app_flag; const bool gamma_only = PARAM.globalv.gamma_only_local; - const int nspin = PARAM.inp.nspin; + const int nspin = inp.nspin; const std::string global_out_dir = PARAM.globalv.global_out_dir; // print out the 'g' index when istep_in != -1 int istep_in = -1; - if (PARAM.inp.esolver_type != "tddft" && PARAM.inp.out_freq_ion > 0) // default value of out_freq_ion is 0 + if (inp.esolver_type != "tddft" && inp.out_freq_ion > 0) // default value of out_freq_ion is 0 { - if (istep % PARAM.inp.out_freq_ion == 0) + if (istep % inp.out_freq_ion == 0) { istep_in = istep; } } - else if (PARAM.inp.esolver_type == "tddft" && PARAM.inp.out_freq_td > 0) // default value of out_freq_td is 0 + else if (inp.esolver_type == "tddft" && inp.out_freq_td > 0) // default value of out_freq_td is 0 { - if (istep % PARAM.inp.out_freq_td == 0) + if (istep % inp.out_freq_td == 0) { istep_in = istep; } } std::string geom_block; - bool should_output = (PARAM.inp.out_freq_ion == 0); + bool should_output = (inp.out_freq_ion == 0); if (istep_in >= 0) { geom_block = "g" + std::to_string(istep + 1); @@ -56,7 +58,7 @@ void ctrl_output_fp(UnitCell& ucell, } // 4) write charge density - if (PARAM.inp.out_chg[0] > 0 && should_output) + if (inp.out_chg[0] > 0 && should_output) { for (int is = 0; is < nspin; ++is) { @@ -82,7 +84,7 @@ void ctrl_output_fp(UnitCell& ucell, fn, pelec->eferm.get_efval(is), &(ucell), - PARAM.inp.out_chg[1], + inp.out_chg[1], 1, PARAM.globalv.two_fermi, false); @@ -110,7 +112,7 @@ void ctrl_output_fp(UnitCell& ucell, } // 5) write potential - if ((PARAM.inp.out_pot[0] == 1 || PARAM.inp.out_pot[0] == 3) && should_output) + if ((inp.out_pot[0] == 1 || inp.out_pot[0] == 3) && should_output) { for (int is = 0; is < nspin; is++) { @@ -136,13 +138,13 @@ void ctrl_output_fp(UnitCell& ucell, fn, 0.0, // efermi &(ucell), - PARAM.inp.out_pot[1], // precision + inp.out_pot[1], // precision 0, // out_fermi PARAM.globalv.two_fermi, false); } } - else if (PARAM.inp.out_pot[0] == 2 && should_output) + else if (inp.out_pot[0] == 2 && should_output) { std::string fn = PARAM.globalv.global_out_dir + "potes"; fn += geom_block + ".cube"; @@ -159,11 +161,11 @@ void ctrl_output_fp(UnitCell& ucell, &(ucell), pelec->pot->get_fixed_v(), solvent, - PARAM.inp.out_pot[1]); + inp.out_pot[1]); } // 6) write ELF - if (PARAM.inp.out_elf[0] > 0 && should_output) + if (inp.out_elf[0] > 0 && should_output) { chr.cal_elf = true; Symmetry_rho srho; @@ -181,16 +183,16 @@ void ctrl_output_fp(UnitCell& ucell, pw_rhod, para_grid, &(ucell), - PARAM.inp.out_elf[1], + inp.out_elf[1], geom_block, PARAM.globalv.two_fermi); } #ifdef __LIBXC // 7) write xc(r) - if (PARAM.inp.out_xc_r[0] >= 0 && should_output) + if (inp.out_xc_r[0] >= 0 && should_output) { - ModuleIO::write_libxc_r(PARAM.inp.out_xc_r[0], + ModuleIO::write_libxc_r(inp.out_xc_r[0], XC_Functional::get_func_id(), pw_rhod->nrxx, // number of real-space grid ucell.omega, // volume of cell @@ -202,7 +204,7 @@ void ctrl_output_fp(UnitCell& ucell, #endif // 8) write dipole moment - if (PARAM.inp.out_dipole == 1 && should_output) + if (inp.out_dipole == 1 && should_output) { for (int is = 0; is < nspin; ++is) { diff --git a/source/source_io/module_ctrl/ctrl_output_fp.h b/source/source_io/module_ctrl/ctrl_output_fp.h index ec9f4e20e78..f8b92a60069 100644 --- a/source/source_io/module_ctrl/ctrl_output_fp.h +++ b/source/source_io/module_ctrl/ctrl_output_fp.h @@ -3,10 +3,13 @@ #include "source_estate/elecstate_lcao.h" +struct Input_para; + namespace ModuleIO { void ctrl_output_fp(UnitCell& ucell, + const Input_para& inp, elecstate::ElecState* pelec, ModulePW::PW_Basis_Big* pw_big, ModulePW::PW_Basis* pw_rhod, From e6aafbe2ece86ac52f08b673167f1f021e5a4cbb Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Sun, 6 Sep 2026 16:37:41 +0800 Subject: [PATCH 08/33] refactor(dftu): rename occ_mat state accessors to ready/stale semantics Rename the DFT+U occupation-matrix state accessors to shorter, clearer names: - is_occ_mat_initialized() -> is_occmat_ready() - mark_occ_mat_initialized() -> set_occmat_ready() - mark_occ_mat_dirty() -> set_occmat_stale() - member occ_mat_initialized -> occmat_ready_ Also unify the base-class internal write paths to use set_occmat_ready() instead of direct member assignment, and update all call sites and comments across PW, LCAO, and DFPT modules. --- .../source_lcao/module_dftu/dftu_hamilt.cpp | 4 +-- .../module_dftu/dftu_nao_energy.cpp | 2 +- .../source_lcao/module_dftu/dftu_nao_occ.cpp | 10 +++---- .../source_lcao/module_dftu/dftu_nao_op.cpp | 28 +++++++++---------- source/source_lcao/setup_dftu_lcao.cpp | 8 +++--- source/source_pw/module_dfpt/dfpt_pw_data.cpp | 2 +- .../module_dfpt/test/dfpt_pw_data_test.cpp | 2 +- source/source_pw/module_pwdft/dftu_base.cpp | 4 +-- source/source_pw/module_pwdft/dftu_base.h | 12 ++++---- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_hamilt.cpp b/source/source_lcao/module_dftu/dftu_hamilt.cpp index 11251f85bf3..9c8b08b64be 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.cpp +++ b/source/source_lcao/module_dftu/dftu_hamilt.cpp @@ -21,7 +21,7 @@ void pot_uterm_complex(Plus_U& dftu, const int npol) { ModuleBase::TITLE("DFTU_LCAO", "pot_uterm_complex"); - if (!dftu.is_occ_mat_initialized()) + if (!dftu.is_occmat_ready()) { return; } @@ -82,7 +82,7 @@ void pot_uterm_real(Plus_U& dftu, const int npol) { ModuleBase::TITLE("DFTU_LCAO", "pot_uterm_real"); - if (!dftu.is_occ_mat_initialized()) + if (!dftu.is_occmat_ready()) { return; } diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.cpp b/source/source_lcao/module_dftu/dftu_nao_energy.cpp index 5e128372ad0..2a6e0fa6f8a 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_energy.cpp @@ -11,7 +11,7 @@ void DFTU_LCAO::cal_energy_correction(Plus_U& dftu, const UnitCell& ucell) { ModuleBase::TITLE("DFTU_LCAO", "cal_energy_correction"); ModuleBase::timer::start("DFTU_LCAO", "cal_energy_correction"); - if (!dftu.is_occ_mat_initialized()) + if (!dftu.is_occmat_ready()) { ModuleBase::timer::end("DFTU_LCAO", "cal_energy_correction"); return; diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.cpp b/source/source_lcao/module_dftu/dftu_nao_occ.cpp index cc84924757d..f7bd77aa4b2 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_occ.cpp @@ -11,7 +11,7 @@ // cal_occ_mat_k / cal_occ_mat_gamma take Plus_U& dftu directly and read all // occupation-matrix state (occ/save arrays, lookup table, nspin/npol, and the -// occ_mat_initialized flag) from dftu.occmat() and the Plus_U_Base accessors. +// occmat_ready flag) from dftu.occmat() and the Plus_U_Base accessors. #ifdef __LCAO @@ -263,12 +263,12 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, } // end ia } // end it - if(dftu.has_occ_mixer() && dftu.is_occ_mat_initialized()) + if(dftu.has_occ_mixer() && dftu.is_occmat_ready()) { dftu.occ_mixer().mix_plain(dftu.occmat(), mixing_beta); } - dftu.mark_occ_mat_initialized(); + dftu.set_occmat_ready(); ModuleBase::timer::end("DFTU_LCAO", "cal_occ_mat_k"); return; } @@ -436,12 +436,12 @@ void DFTU_LCAO::cal_occ_mat_gamma(const Parallel_Orbitals* pv, } // it } // is - if(dftu.has_occ_mixer() && dftu.is_occ_mat_initialized()) + if(dftu.has_occ_mixer() && dftu.is_occmat_ready()) { dftu.occ_mixer().mix_plain(dftu.occmat(), mixing_beta); } - dftu.mark_occ_mat_initialized(); + dftu.set_occmat_ready(); ModuleBase::timer::end("DFTU_LCAO", "cal_occ_mat_gamma"); return; } diff --git a/source/source_lcao/module_dftu/dftu_nao_op.cpp b/source/source_lcao/module_dftu/dftu_nao_op.cpp index 77a2200b464..a1c8bdcddfc 100644 --- a/source/source_lcao/module_dftu/dftu_nao_op.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_op.cpp @@ -24,9 +24,9 @@ hamilt::DFTU>::DFTU(HS_Matrix_K* hsk_in, this->cal_type = calculation_type::lcao_dftu; this->ucell = &ucell_in; this->dftu = p_dftu; -#ifdef __DEBUG + assert(this->ucell != nullptr); -#endif + // initialize HR to allocate sparse Nonlocal matrix memory this->initialize_HR(GridD_in); // set nspin @@ -176,11 +176,11 @@ void hamilt::DFTU>::cal_nlm_all(const Parallel_Orbi * @brief Contribute DFT+U Hamiltonian to real-space HR matrix * * @details This function handles different scenarios based on: - * 1. Whether occ_mat (occupation matrix) is read from file (is_occ_mat_initialized) + * 1. Whether occ_mat (occupation matrix) is read from file (is_occmat_ready) * 2. Spin configuration (nspin=1, 2, or 4) * 3. SCF iteration stage (first vs subsequent iterations) * - * Case 1: Occ_mat NOT initialized (!is_occ_mat_initialized) + * Case 1: Occ_mat NOT ready (!is_occmat_ready) * - First electronic iteration: calculates occupation matrix from density matrix (DMR) * * Uses get_dmr(current_spin) to get real-space density matrix * * Accumulates contributions from all atom pairs via cal_occ() @@ -189,12 +189,12 @@ void hamilt::DFTU>::cal_nlm_all(const Parallel_Orbi * * For nspin=1: occ is scaled by 0.5 (since only one spin channel computed) * - Subsequent iterations: occ_mat is computed fresh each iteration from updated DMR * - * Case 2: Occ_mat IS initialized (is_occ_mat_initialized, i.e., read from dm_onsite.txt file) + * Case 2: Occ_mat IS ready (is_occmat_ready, i.e., read from dm_onsite.txt file) * - First electronic iteration: uses pre-read occ_mat directly without DMR calculation * * Skips DMR-based occ calculation entirely * * Reads occ_mat from stored data via get_occ_mat() * * Different indexing for nspin=4 vs nspin=1/2 (see below) - * - After first iteration: mark_occ_mat_dirty() is called to force recomputation + * - After first iteration: set_occmat_stale() is called to force recomputation * * Spin configurations: * nspin=1 (non-spin-polarized): @@ -205,14 +205,14 @@ void hamilt::DFTU>::cal_nlm_all(const Parallel_Orbi * nspin=2 (collinear spin-polarized): * - Two separate spin channels (spin-up: 0, spin-down: 1) * - current_spin toggles between 0 and 1 across iterations - * - mark_occ_mat_dirty() called when current_spin == 1 (last spin) + * - set_occmat_stale() called when current_spin == 1 (last spin) * - HR accumulated separately for each spin * * nspin=4 (non-collinear/SOC): * - Single 4x4 Pauli matrix representation per atom * - occ has 4*(2l+1)^2 elements (spin_fold=4) * - get_occ_mat uses spin=0, ipol indices for Pauli blocks - * - mark_occ_mat_dirty() always called (current_spin check always true) + * - set_occmat_stale() always called (current_spin check always true) * - No current_spin toggling (all spins handled simultaneously) * * @warning THREAD SAFETY: cal_HR_IJR() updates shared HR matrix entries. @@ -227,10 +227,10 @@ void hamilt::DFTU>::contributeHR() ModuleBase::TITLE("DFTU", "contributeHR"); // Early exit conditions: // - get_dmr(0) == nullptr: DMR not available (typical in first iteration without file input) - // - !is_occ_mat_initialized(): occ_mat not read from file AND not yet computed from DMR + // - !is_occmat_ready(): occ_mat not read from file AND not yet computed from DMR // When both true, skip DFT+U contribution entirely (first iteration, no file input) const bool dmr_null = (this->dftu->get_dmr(0) == nullptr); - const bool occ_mat_not_init = !this->dftu->is_occ_mat_initialized(); + const bool occ_mat_not_init = !this->dftu->is_occmat_ready(); if (dmr_null && occ_mat_not_init) { @@ -279,10 +279,10 @@ void hamilt::DFTU>::contributeHR() // BRANCH 1: Occ_mat NOT initialized (compute from DMR) // ============================================================ // This branch is taken when: - // - is_occ_mat_initialized() == false (no file read or omc != 0) + // - is_occmat_ready() == false (no file read or omc != 0) // - DMR is available (get_dmr() != nullptr) // Typical scenario: normal SCF iterations after first step - if (!this->dftu->is_occ_mat_initialized()) + if (!this->dftu->is_occmat_ready()) { // TODO: UNSAFE - get_dmr(current_spin) assumes DMR has correct spin indexing. // For nspin=2, current_spin must be correctly toggled (0 then 1). @@ -333,7 +333,7 @@ void hamilt::DFTU>::contributeHR() // BRANCH 2: Occ_mat IS initialized (use pre-read data) // ============================================================ // This branch is taken when: - // - is_occ_mat_initialized() == true (occ_mat read from dm_onsite.txt file) + // - is_occmat_ready() == true (occ_mat read from dm_onsite.txt file) // - OR omc != 0 (occupation matrix control with dm_onsite_ini.txt) // Typical scenario: first SCF iteration with file input, or restart calculation else @@ -445,7 +445,7 @@ void hamilt::DFTU>::contributeHR() // TODO: This logic is confusing. Consider explicit variable like `is_last_spin_channel`. if (this->current_spin == this->nspin - 1 || this->nspin == 4) { - this->dftu->mark_occ_mat_dirty(); + this->dftu->set_occmat_stale(); } // 8. Spin channel toggling for nspin=2 diff --git a/source/source_lcao/setup_dftu_lcao.cpp b/source/source_lcao/setup_dftu_lcao.cpp index 7c0a9e064e8..cf208335065 100644 --- a/source/source_lcao/setup_dftu_lcao.cpp +++ b/source/source_lcao/setup_dftu_lcao.cpp @@ -38,11 +38,11 @@ void init_dftu_lcao(const int istep, { dftu_ptr->yukawa().cal_slater_UJ(ucell, rho, nrxx, PARAM.inp.nspin, dftu_ptr->get_ptr_orb()); // update current U with calculated U-J from Slater integrals - for (int T = 0; T < ucell.ntype; T++) + for (int it = 0; it < ucell.ntype; it++) { - if (dftu_ptr->has_l_channel(T)) + if (dftu_ptr->has_l_channel(it)) { - dftu_ptr->set_u_current(T, dftu_ptr->yukawa().get_Ueff(T)); + dftu_ptr->set_u_current(it, dftu_ptr->yukawa().get_Ueff(it)); } } } @@ -89,7 +89,7 @@ void finish_dftu_lcao(const int iter, /// use the converged occupation matrix for next MD/Relax SCF calculation if (conv_esolver) { - dftu_ptr->mark_occ_mat_initialized(); + dftu_ptr->set_occmat_ready(); } } diff --git a/source/source_pw/module_dfpt/dfpt_pw_data.cpp b/source/source_pw/module_dfpt/dfpt_pw_data.cpp index feede10aa11..754f4e063df 100644 --- a/source/source_pw/module_dfpt/dfpt_pw_data.cpp +++ b/source/source_pw/module_dfpt/dfpt_pw_data.cpp @@ -58,7 +58,7 @@ bool DFPT_PW_Data::u_active() const // state does this when DFT+U actually runs); a wired provider without // them (e.g. a default-constructed reservation) stays inactive. ModuleBase::timer::end("DFPT_PW_Data", "u_active"); - return with_u() && dftu_->is_occ_mat_initialized(); + return with_u() && dftu_->is_occmat_ready(); } void DFPT_PW_Data::set_docc(int q_idx, const std::vector>& occ) diff --git a/source/source_pw/module_dfpt/test/dfpt_pw_data_test.cpp b/source/source_pw/module_dfpt/test/dfpt_pw_data_test.cpp index 843036257de..dcfc50dfbd7 100644 --- a/source/source_pw/module_dfpt/test/dfpt_pw_data_test.cpp +++ b/source/source_pw/module_dfpt/test/dfpt_pw_data_test.cpp @@ -200,7 +200,7 @@ TEST_F(DFPT_PW_DataTest, DftuReservationProviderUsability) EXPECT_FALSE(data.u_active()); ASSERT_NE(data.get_dftu(), nullptr); - dftu.mark_occ_mat_initialized(); + dftu.set_occmat_ready(); EXPECT_TRUE(data.u_active()); data.clean(); diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index 81c07fbc081..ac52cd9d039 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -150,7 +150,7 @@ void Plus_U_Base::init_base(UnitCell& cell, DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->l_channel, nspin, npol); #endif - this->occ_mat_initialized = true; + this->set_occmat_ready(); this->occmat_.copy_to_save(cell, this->l_channel); if (this->has_occ_mixer()) { @@ -169,7 +169,7 @@ void Plus_U_Base::init_base(UnitCell& cell, #ifdef __MPI DFTU_BASE::local_occup_bcast(cell, this->occmat_, this->l_channel, nspin, npol); #endif - this->occ_mat_initialized = true; + this->set_occmat_ready(); } else { diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index cbebb8a58d6..0b6e970bae5 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -111,10 +111,10 @@ class Plus_U_Base return uterm_mat.size(); } - // dftu can be calculated only after occ_mat has been initialized - bool is_occ_mat_initialized() const { return occ_mat_initialized; } - void mark_occ_mat_initialized() { occ_mat_initialized = true; } - void mark_occ_mat_dirty() { occ_mat_initialized = false; } + // dftu can be calculated only after occ_mat is ready + bool is_occmat_ready() const { return occmat_ready_; } + void set_occmat_ready() { occmat_ready_ = true; } + void set_occmat_stale() { occmat_ready_ = false; } /// direct access to the occupation matrix object (new write path) OccupationMatrix& occmat() { return occmat_; } @@ -135,8 +135,8 @@ class Plus_U_Base private: // --- State flags --- - // dftu can be calculated only after occ_mat has been initialized - bool occ_mat_initialized = false; + // dftu can be calculated only after occ_mat is ready + bool occmat_ready_ = false; protected: // --- U values and orbital configuration (set in init_base) --- From 540779697f8d0440d06117a1a97f5db944c648ec Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 08:47:11 +0800 Subject: [PATCH 09/33] refactor: split dftu_pw into dftu_pw_tools (pure functions) + dftu_pw (orchestration) - dftu_pw_tools.h/cpp: 7 pure functions in namespace pw, unit-testable - dftu_pw.h/cpp: cal_occ_pw + accumulate_occ_one_k in namespace DFTU_BASE - test_dftu_pw_tools.cpp: tests for pure functions, links only dftu_pw_tools.cpp - Update CMakeLists.txt accordingly --- .../module_dftu/test/CMakeLists.txt | 7 - .../module_dftu/test/dftu_core_test.cpp | 266 +----------------- .../module_dftu/test/dftu_operator_test.cpp | 74 ----- source/source_pw/module_pwdft/CMakeLists.txt | 4 +- source/source_pw/module_pwdft/dftu_base.cpp | 4 +- .../source_pw/module_pwdft/dftu_base_occ.cpp | 260 ----------------- source/source_pw/module_pwdft/dftu_pw.cpp | 134 +++++++++ source/source_pw/module_pwdft/dftu_pw.h | 62 ++++ ...{dftu_base_tools.cpp => dftu_pw_tools.cpp} | 112 +++++++- .../{dftu_base_tools.h => dftu_pw_tools.h} | 61 +--- .../source_pw/module_pwdft/setup_dftu_pw.cpp | 2 +- .../module_pwdft/test/CMakeLists.txt | 7 + .../module_pwdft/test/dftu_base_test.cpp | 259 +++++++++++++++++ .../module_pwdft/test/test_dftu_pw_tools.cpp} | 96 ++++++- 14 files changed, 673 insertions(+), 675 deletions(-) delete mode 100644 source/source_pw/module_pwdft/dftu_base_occ.cpp create mode 100644 source/source_pw/module_pwdft/dftu_pw.cpp create mode 100644 source/source_pw/module_pwdft/dftu_pw.h rename source/source_pw/module_pwdft/{dftu_base_tools.cpp => dftu_pw_tools.cpp} (53%) rename source/source_pw/module_pwdft/{dftu_base_tools.h => dftu_pw_tools.h} (69%) rename source/{source_lcao/module_dftu/test/dftu_pw_test.cpp => source_pw/module_pwdft/test/test_dftu_pw_tools.cpp} (79%) diff --git a/source/source_lcao/module_dftu/test/CMakeLists.txt b/source/source_lcao/module_dftu/test/CMakeLists.txt index 19b535a59b4..6114af6f9ca 100644 --- a/source/source_lcao/module_dftu/test/CMakeLists.txt +++ b/source/source_lcao/module_dftu/test/CMakeLists.txt @@ -1,12 +1,5 @@ abacus_disable_feature_definitions(__CUDA) -AddTest( - TARGET dftu_pw_test - LIBS base device parameter - SOURCES dftu_pw_test.cpp - ../../../source_pw/module_pwdft/dftu_base_tools.cpp -) - AddTest( TARGET dftu_core_test LIBS base device diff --git a/source/source_lcao/module_dftu/test/dftu_core_test.cpp b/source/source_lcao/module_dftu/test/dftu_core_test.cpp index 1d61578d642..ffe48262461 100644 --- a/source/source_lcao/module_dftu/test/dftu_core_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_core_test.cpp @@ -9,272 +9,12 @@ * Unit tests for DFT+U core algorithms. * * These tests target the most complex and bug-prone logic: - * 1. uterm_mat_index calculation for mixed atom types and nspin modes - * 2. copy_occ_mat <-> set_occ_mat roundtrip (3 data layouts) - * 3. pot_onsite effective potential formula (UForm::dud_fll, FLL) - * 4. Energy correction and double-counting terms + * 1. pot_onsite effective potential formula (UForm::dud_fll, FLL) + * 2. Energy correction and double-counting terms ***********************************************************************/ // ===================================================================== -// 1. uterm_mat_index calculation -// -// nspin=1: offset = sum(tlp1^2), total = sum(all tlp1^2) -// nspin=2: same per-spin-channel, then pot_index *= 2 (split layout) -// nspin=4: offset = sum((tlp1*npol)^2), each atom = 4*tlp1^2 -// ===================================================================== - -class EffPotIndexTest : public ::testing::Test -{ - protected: - struct AtomSpec { int l; int na; }; // correlated orbital l, number of atoms - std::vector uterm_mat_index; - int pot_index; - - void compute_indices(const std::vector& atoms, int nspin) - { - pot_index = 0; - uterm_mat_index.resize(atoms.size()); - - for (size_t i = 0; i < atoms.size(); i++) - { - int tlp1 = 2 * atoms[i].l + 1; - int tlp1_npol = tlp1 * (nspin == 4 ? 2 : 1); - - if (nspin == 4) - { - uterm_mat_index[i] = pot_index; - pot_index += tlp1_npol * tlp1_npol; - } - else - { - uterm_mat_index[i] = pot_index; - pot_index += tlp1 * tlp1; - } - } - - if (nspin == 2) - pot_index *= 2; - } -}; - -TEST_F(EffPotIndexTest, Nspin1_MixedOrbitals) -{ - // 3 atoms: p(l=1), d(l=2), p(l=1) - std::vector atoms = {{1, 1}, {2, 1}, {1, 1}}; - compute_indices(atoms, 1); - - // p: 9, d: 25, p: 9 - EXPECT_EQ(uterm_mat_index[0], 0); - EXPECT_EQ(uterm_mat_index[1], 9); - EXPECT_EQ(uterm_mat_index[2], 34); - EXPECT_EQ(pot_index, 43); // 9 + 25 + 9 -} - -TEST_F(EffPotIndexTest, Nspin2and4_SplitAndPauli) -{ - // nspin=2: 2 d-atoms, split layout [up | dn] - std::vector atoms2 = {{2, 1}, {2, 1}}; - compute_indices(atoms2, 2); - EXPECT_EQ(uterm_mat_index[0], 0); - EXPECT_EQ(uterm_mat_index[1], 25); - EXPECT_EQ(pot_index, 100); // (25 + 25) * 2 - - // nspin=4: d + p atoms, Pauli blocks - std::vector atoms4 = {{2, 1}, {1, 1}}; - compute_indices(atoms4, 4); - EXPECT_EQ(uterm_mat_index[0], 0); // d: (5*2)^2 = 100 - EXPECT_EQ(uterm_mat_index[1], 100); // p: (3*2)^2 = 36 - EXPECT_EQ(pot_index, 136); -} - -// ===================================================================== -// 2. copy_occ_mat <-> set_occ_mat roundtrip -// -// Tests the bidirectional conversion between nested occ_mat matrix -// and flat uom_array/uom_save arrays for all 3 nspin modes. -// ===================================================================== - -struct Matrix2D { - int nr, nc; - std::vector data; - Matrix2D() : nr(0), nc(0), data() {} - Matrix2D(int r, int c) : nr(r), nc(c), data(r * c, 0.0) {} - double& operator()(int i, int j) { return data[i * nc + j]; } - const double& operator()(int i, int j) const { return data[i * nc + j]; } -}; - -static void copy_occ_mat_to_flat( - const std::vector& occ_mat_up, - const std::vector& occ_mat_dn, - std::vector& uom_save, - const std::vector& uterm_mat_index, - int nspin) -{ - if (nspin == 4) - { - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; - } - } - else if (nspin == 2) // split layout: [up | dn] - { - int half_size = uom_save.size() / 2; - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - { - uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; - uom_save[half_size + uterm_mat_index[iat] + mm] = occ_mat_dn[iat].data[mm]; - } - } - } - else // nspin=1: single spin channel - { - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; - } - } -} - -static void set_occ_mat_from_flat( - const std::vector& uom_array, - std::vector& occ_mat_up, - std::vector& occ_mat_dn, - const std::vector& uterm_mat_index, - int nspin) -{ - if (nspin == 4) - { - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; - } - } - else if (nspin == 2) - { - int half_size = uom_array.size() / 2; - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - { - occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; - occ_mat_dn[iat].data[mm] = uom_array[half_size + uterm_mat_index[iat] + mm]; - } - } - } - else // nspin=1 - { - for (size_t iat = 0; iat < occ_mat_up.size(); iat++) - { - int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; - for (int mm = 0; mm < size; mm++) - occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; - } - } -} - -class OccMatRoundtripTest : public ::testing::Test -{ - protected: - void SetUp() override {} -}; - -TEST_F(OccMatRoundtripTest, Nspin1and2_SingleAndSplitLayout) -{ - // nspin=1: single atom d-orbital roundtrip - const int l = 2; - const int size = (2 * l + 1) * (2 * l + 1); // 25 - - std::vector occ_mat_up(1, Matrix2D(2 * l + 1, 2 * l + 1)); - std::vector occ_mat_dn(1, Matrix2D(2 * l + 1, 2 * l + 1)); - for (int i = 0; i < size; i++) - occ_mat_up[0].data[i] = static_cast(i + 1); - - std::vector uterm_mat_index = {0}; - std::vector uom_save(size, 0.0); - copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 1); - set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 1); - for (int i = 0; i < size; i++) - EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); - - // nspin=2: split layout [up | dn] with distinct values - const int total = size * 2; - for (int i = 0; i < size; i++) - { - occ_mat_up[0].data[i] = static_cast(i + 1); - occ_mat_dn[0].data[i] = static_cast(i + 100); - } - uom_save.assign(total, 0.0); - copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 2); - // Verify split layout - for (int i = 0; i < size; i++) - { - EXPECT_DOUBLE_EQ(uom_save[i], static_cast(i + 1)); - EXPECT_DOUBLE_EQ(uom_save[size + i], static_cast(i + 100)); - } - set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 2); - for (int i = 0; i < size; i++) - { - EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); - EXPECT_DOUBLE_EQ(occ_mat_dn[0].data[i], static_cast(i + 100)); - } -} - -TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) -{ - // 2 atoms: d(l=2), p(l=1) - struct AtomSpec { int l; }; - std::vector specs = {{2}, {1}}; - int npol = 2; - - std::vector sizes; - for (auto& s : specs) - { - int tlp1 = 2 * s.l + 1; - sizes.push_back((tlp1 * npol) * (tlp1 * npol)); - } - int total = std::accumulate(sizes.begin(), sizes.end(), 0); - - std::vector uterm_mat_index(specs.size()); - int offset = 0; - for (size_t i = 0; i < specs.size(); i++) - { - uterm_mat_index[i] = offset; - offset += sizes[i]; - } - - std::vector occ_mat(specs.size()); - for (size_t i = 0; i < specs.size(); i++) - { - int dim = (2 * specs[i].l + 1) * npol; - occ_mat[i] = Matrix2D(dim, dim); - for (int j = 0; j < sizes[i]; j++) - occ_mat[i].data[j] = static_cast(i * 1000 + j + 1); - } - - std::vector uom_array(total, 0.0); - std::vector occ_mat_dn(specs.size()); // unused for nspin=4 - - copy_occ_mat_to_flat(occ_mat, occ_mat_dn, uom_array, uterm_mat_index, 4); - set_occ_mat_from_flat(uom_array, occ_mat, occ_mat_dn, uterm_mat_index, 4); - - for (size_t i = 0; i < specs.size(); i++) - for (int j = 0; j < sizes[i]; j++) - EXPECT_DOUBLE_EQ(occ_mat[i].data[j], static_cast(i * 1000 + j + 1)); -} - -// ===================================================================== -// 3. pot_onsite effective potential formula (UForm::dud_fll, FLL) +// 1. pot_onsite effective potential formula (UForm::dud_fll, FLL) // // pot_onsite[m0,m1] = U * (0.5*delta(m0,m1) - occ_mat[m0,m1]) (diagonal) // pot_onsite[m0,m1] = -U * occ_mat[m0,m1] (off-diagonal) diff --git a/source/source_lcao/module_dftu/test/dftu_operator_test.cpp b/source/source_lcao/module_dftu/test/dftu_operator_test.cpp index 89a6b39911f..e65da640977 100644 --- a/source/source_lcao/module_dftu/test/dftu_operator_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_operator_test.cpp @@ -323,77 +323,3 @@ TEST_F(VoigtToMatrixTest, FullMappingAndSymmetry) EXPECT_NEAR(matrix[1], matrix[3], 1e-15); EXPECT_NEAR(matrix[2], matrix[6], 1e-15); EXPECT_NEAR(matrix[5], matrix[7], 1e-15); } - -// ===================================================================== -// 7. PW operator index setup (ip_iat, ip_m, pot_onsite_begin_iat) -// ip_m[ip] = m index if projector is correlated, else -1 -// ip_iat[ip] = atom index, pot_onsite_begin_iat[iat] = pot_onsite array offset -// ===================================================================== - -class PWIndexSetupTest : public ::testing::Test -{ - protected: - struct AtomInfo { int it, nh, target_l; }; // target_l=-1 if not correlated - - void setup_indices(const std::vector& atoms, - std::vector& ip_iat, std::vector& ip_m, - std::vector& pot_onsite_begin_iat, int& pot_onsite_total_size) - { - int ip0 = 0, pot_onsite_begin = 0, npol = 1; - ip_iat.resize(0); ip_m.resize(0); pot_onsite_begin_iat.resize(atoms.size()); - for (const auto& atom : atoms) - { - ip_iat.resize(ip_iat.size() + atom.nh); - ip_m.resize(ip_m.size() + atom.nh); - if (atom.target_l == -1) - { - for (int ip = 0; ip < atom.nh; ip++) - { ip_iat[ip0] = static_cast(&atom - &atoms[0]); ip_m[ip0++] = -1; } - pot_onsite_begin_iat[&atom - &atoms[0]] = 0; - } - else - { - int tlp1 = 2 * atom.target_l + 1; - pot_onsite_begin_iat[&atom - &atoms[0]] = pot_onsite_begin; - pot_onsite_begin += tlp1 * tlp1 * npol * npol; - int m_begin = atom.target_l * atom.target_l; - int m_end = (atom.target_l + 1) * (atom.target_l + 1); - for (int ip = 0; ip < atom.nh; ip++) - { - ip_iat[ip0] = static_cast(&atom - &atoms[0]); - ip_m[ip0++] = (ip >= m_begin && ip < m_end) ? ip - m_begin : -1; - } - } - } - pot_onsite_total_size = pot_onsite_begin; - } -}; - -TEST_F(PWIndexSetupTest, SingleCorrelatedAtom_DOrbital) -{ - std::vector atoms = {{0, 9, 2}}; // s(1)+p(3)+d(5) projectors, l=2 - std::vector ip_iat, ip_m, pot_onsite_begin_iat; int pot_onsite_total_size; - setup_indices(atoms, ip_iat, ip_m, pot_onsite_begin_iat, pot_onsite_total_size); - // Projectors 0-3 (s+p): m=-1; 4-8 (d): m=0..4 - EXPECT_EQ(ip_iat.size(), 9u); - for (int ip = 0; ip < 4; ip++) EXPECT_EQ(ip_m[ip], -1); - for (int ip = 4; ip < 9; ip++) { EXPECT_EQ(ip_iat[ip], 0); EXPECT_EQ(ip_m[ip], ip-4); } - EXPECT_EQ(pot_onsite_begin_iat[0], 0); - EXPECT_EQ(pot_onsite_total_size, 25); // 5*5 -} - -TEST_F(PWIndexSetupTest, MixedCorrelatedUncorrelated) -{ - std::vector atoms = {{0, 4, 1}, {1, 2, -1}}; // atom0: p-correlated, atom1: not - std::vector ip_iat, ip_m, pot_onsite_begin_iat; int pot_onsite_total_size; - setup_indices(atoms, ip_iat, ip_m, pot_onsite_begin_iat, pot_onsite_total_size); - // atom0: s(ip=0)->m=-1, p(ip=1,2,3)->m=0,1,2 - EXPECT_EQ(ip_iat[0], 0); EXPECT_EQ(ip_m[0], -1); - EXPECT_EQ(ip_iat[1], 0); EXPECT_EQ(ip_m[1], 0); - EXPECT_EQ(ip_iat[2], 0); EXPECT_EQ(ip_m[2], 1); - EXPECT_EQ(ip_iat[3], 0); EXPECT_EQ(ip_m[3], 2); - // atom1: all m=-1 - EXPECT_EQ(ip_iat[4], 1); EXPECT_EQ(ip_m[4], -1); - EXPECT_EQ(ip_iat[5], 1); EXPECT_EQ(ip_m[5], -1); - EXPECT_EQ(pot_onsite_total_size, 9); // 3*3 for p-orbital -} diff --git a/source/source_pw/module_pwdft/CMakeLists.txt b/source/source_pw/module_pwdft/CMakeLists.txt index ad769f4ca39..f6b8597c806 100644 --- a/source/source_pw/module_pwdft/CMakeLists.txt +++ b/source/source_pw/module_pwdft/CMakeLists.txt @@ -14,8 +14,8 @@ list(APPEND objects op_pw_exx_pot.cpp dftu_base.cpp dftu_base_io.cpp - dftu_base_occ.cpp - dftu_base_tools.cpp + dftu_pw.cpp + dftu_pw_tools.cpp yukawa_screening.cpp setup_pot.cpp setup_pwrho.cpp diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index ac52cd9d039..25c0be05fb7 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -227,6 +227,6 @@ bool Plus_U_Base::u_converged() // cal_occ_pw() is implemented as free function DFTU_BASE::cal_occ_pw -// in source_pw/module_pwdft/dftu_base_occ.cpp. -// Pure per-atom kernels live in dftu_base_tools.{h,cpp} +// in source_pw/module_pwdft/dftu_pw.cpp. +// All pure per-atom kernels also live in dftu_pw.{h,cpp} // as free functions in namespace DFTU_BASE. diff --git a/source/source_pw/module_pwdft/dftu_base_occ.cpp b/source/source_pw/module_pwdft/dftu_base_occ.cpp deleted file mode 100644 index 24ad924eb01..00000000000 --- a/source/source_pw/module_pwdft/dftu_base_occ.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include "source_pw/module_pwdft/dftu_base.h" -#include "source_pw/module_pwdft/dftu_base_io.h" -#include "source_pw/module_pwdft/dftu_base_tools.h" -#include "source_pw/module_pwdft/onsite_proj.h" -#include "source_cell/unitcell.h" -#include "source_estate/module_charge/charge_mixing.h" -#include "source_base/parallel_reduce.h" -#include "source_base/global_variable.h" -#include "source_base/timer.h" -#include "source_base/parallel_global.h" - - - - -namespace DFTU_BASE { - -/// calculate occupation matrix for DFT+U (PW basis) -/// -/// nspin=1 (npol=1): single spin channel; occ_mat[iat][l][n][0] only; -/// uterm_mat has one block of tlp1^2 per atom. -/// -/// nspin=2 (npol=1): two spin channels stored separately: -/// occ_mat[iat][l][n][0] = spin-up, occ_mat[iat][l][n][1] = spin-down; -/// becp indices: ib*nkb + begin_ih + m (same formula for both spins); -/// spin channel selected by `isk[ik]` (not ik >= nk/2, which fails for kpar>1); -/// -/// nspin=4 (npol=2): spinor calculation; -/// occ_mat has a single matrix of size (2*tlp1) x (2*tlp1) per atom -/// storing all 4 Pauli blocks contiguously. -void cal_occ_pw(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - Charge_Mixing* p_chgmix, - const int* isk, - const int kpar, - const int nspin, - const std::string& device, - const std::vector& l_channel, - const std::vector& u_current, - const std::vector& uterm_mat_index, - OccupationMatrix& occmat, - OccMatMixer* occ_mixer, - std::vector>& uterm_mat, - double& energy_u) -{ - ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); - occmat.copy_to_save(cell, l_channel); - if (occ_mixer != nullptr) - { - occ_mixer->begin_iter(occmat); - } - occmat.zero(cell, l_channel); - - if (device == "cpu") - { - DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, nspin, l_channel, occmat); - } -#if defined(__CUDA) || defined(__ROCM) - else - { - DFTU_BASE::accumulate_occ_one_k( - psi_in, wg_in, cell, isk, nspin, l_channel, occmat); - } -#endif - - // reduce occ_mat across k-pools - DFTU_BASE::reduce_occ_mat(cell, nspin, kpar, l_channel, occmat); - - // mixing: flatten the fresh occ, mix against the saved one, write back - if (occ_mixer != nullptr && p_chgmix != nullptr) - { - occ_mixer->collect(occmat); - p_chgmix->mix_uom(occ_mixer->uom(), occ_mixer->uom_save()); - occ_mixer->write_back(occmat); - } - - DFTU_BASE::compute_pot_uterm_and_energy(cell, nspin, - u_current, l_channel, uterm_mat_index, - occmat, uterm_mat, energy_u); - - ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); -} - -} // namespace DFTU_BASE - -namespace DFTU_BASE { - -void reduce_occ_mat(const UnitCell& cell, - const int nspin, - const int kpar, - const std::vector& l_channel, - OccupationMatrix& occmat) -{ - for(int iat = 0; iat < cell.nat; iat++) - { - const int it = cell.iat2it[iat]; - const int target_l = l_channel[it]; - if(target_l == -1) - { - continue; - } - const int size = (2 * target_l + 1) * (2 * target_l + 1); - - if(nspin != 4) - { - Parallel_Reduce::reduce_double_allpool(kpar, - GlobalV::NPROC_IN_POOL, - occmat.mat(iat, target_l, 0, 0).c, - size); - if(nspin == 2) - { - Parallel_Reduce::reduce_double_allpool(kpar, - GlobalV::NPROC_IN_POOL, - occmat.mat(iat, target_l, 0, 1).c, - size); - } - } - else - { - Parallel_Reduce::reduce_double_allpool(kpar, - GlobalV::NPROC_IN_POOL, - occmat.mat(iat, target_l, 0, 0).c, - size * 4); - } - } -} - -void compute_pot_uterm_and_energy(const UnitCell& cell, - const int nspin, - const std::vector& u_current, - const std::vector& l_channel, - const std::vector& uterm_mat_index, - const OccupationMatrix& occmat, - std::vector>& uterm_mat, - double& energy_u) -{ - energy_u = 0.0; - const double weight_eu = (nspin == 1) ? 1.0 : (nspin == 2) ? 0.5 : 0.25; - const double diag_coeff = (nspin == 4) ? 1.0 : 0.5; - // calculate pot_onsite and energy (occ_mat already reduced above) - for(int iat = 0; iat < cell.nat; iat++) - { - const int it = cell.iat2it[iat]; - const int target_l = l_channel[it]; - if(target_l == -1) - { - continue; - } - const int size = (2 * target_l + 1) * (2 * target_l + 1); - - //update effective potential - const double u_value = u_current[it]; - std::complex* pot_onsite_iat = &(uterm_mat[uterm_mat_index[iat]]); - const int m_size = 2 * target_l + 1; - - if(nspin == 4) - { - // pot_onsite is stored as 4 contiguous Pauli blocks per atom: - // is=0: charge channel (identity), Hubbard U contributes the - // diagonal term diag_coeff*delta(m1,m2) - // is=1,2,3: spin channels (sigma_x/y/z), no U diagonal term - // The occupation matrix occ_mat[...][0][0].c packs all 4 blocks - // contiguously, each of size m_size*m_size. - energy_u += compute_pot_onsite_spinor( - pot_onsite_iat, - occmat.mat(iat, target_l, 0, 0).c, - u_value, diag_coeff, weight_eu, m_size); - } - else // nspin=1 or nspin=2 - { - // spin-up channel - energy_u += compute_pot_onsite_scalar( - pot_onsite_iat, - occmat.mat(iat, target_l, 0, 0).c, - u_value, diag_coeff, weight_eu, m_size); - // spin-down channel for nspin=2 - if(nspin == 2) - { - std::complex* pot_onsite_iat1 = &(uterm_mat[uterm_mat.size()/2 + uterm_mat_index[iat]]); - energy_u += compute_pot_onsite_scalar( - pot_onsite_iat1, - occmat.mat(iat, target_l, 0, 1).c, - u_value, diag_coeff, weight_eu, m_size); - } - } - } -} - -} // namespace DFTU_BASE - -namespace DFTU_BASE { - -template -void accumulate_occ_one_k(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - const int* isk, - const int nspin, - const std::vector& l_channel, - OccupationMatrix& occmat) -{ - auto* onsite_p = projectors::OnsiteProjector::get_instance(); - const psi::Psi, Device>* psi_p = - (const psi::Psi, Device>*)psi_in; - const int nbands = psi_p->get_nbands(); - const int npol = psi_p->get_npol(); - for(int ik = 0; ik < psi_p->get_nk(); ik++) - { - int is = (nspin == 2) ? isk[ik] : 0; - psi_p->fix_k(ik); - onsite_p->tabulate_atomic(ik); - - onsite_p->overlap_proj_psi(nbands*npol, psi_p->get_pointer()); - const std::complex* becp = onsite_p->get_h_becp(); - int nkb = onsite_p->get_size_becp() / nbands / npol; - - int begin_ih = 0; - for(int iat = 0; iat < cell.nat; iat++) - { - const int it = cell.iat2it[iat]; - const int nh = onsite_p->get_nh(iat); - const int target_l = l_channel[it]; - if(target_l == -1) - { - begin_ih += nh; - continue; - } - const int m_begin = target_l * target_l; - const int tlp1 = 2 * target_l + 1; - if(nspin == 4) - { - accumulate_occ_spinor( - occmat.mat(iat, target_l, 0, 0).c, - becp, nbands, npol, nkb, begin_ih, m_begin, tlp1, - wg_in, ik); - } - else // nspin=1 or nspin=2 - { - accumulate_occ_scalar( - occmat.mat(iat, target_l, 0, is).c, - becp, nbands, nkb, begin_ih, m_begin, tlp1, - wg_in, ik); - } - begin_ih += nh; - } - } -} - -} // namespace DFTU_BASE - -// explicit instantiations -template void DFTU_BASE::accumulate_occ_one_k( - const void*, const ModuleBase::matrix&, const UnitCell&, const int*, - const int, const std::vector&, OccupationMatrix&); -#if defined(__CUDA) || defined(__ROCM) -template void DFTU_BASE::accumulate_occ_one_k( - const void*, const ModuleBase::matrix&, const UnitCell&, const int*, - const int, const std::vector&, OccupationMatrix&); -#endif diff --git a/source/source_pw/module_pwdft/dftu_pw.cpp b/source/source_pw/module_pwdft/dftu_pw.cpp new file mode 100644 index 00000000000..53a48b39bc5 --- /dev/null +++ b/source/source_pw/module_pwdft/dftu_pw.cpp @@ -0,0 +1,134 @@ +#include "source_pw/module_pwdft/dftu_pw.h" + +#include "source_pw/module_pwdft/dftu_pw_tools.h" +#include "source_pw/module_pwdft/dftu_base.h" +#include "source_pw/module_pwdft/dftu_base_io.h" +#include "source_pw/module_pwdft/onsite_proj.h" +#include "source_cell/unitcell.h" +#include "source_estate/module_charge/charge_mixing.h" +#include "source_base/timer.h" + +namespace DFTU_BASE { + +template +void accumulate_occ_one_k(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + const int* isk, + const int nspin, + const std::vector& l_channel, + OccupationMatrix& occmat) +{ + auto* onsite_p = projectors::OnsiteProjector::get_instance(); + const psi::Psi, Device>* psi_p = + (const psi::Psi, Device>*)psi_in; + const int nbands = psi_p->get_nbands(); + const int npol = psi_p->get_npol(); + for(int ik = 0; ik < psi_p->get_nk(); ik++) + { + int is = (nspin == 2) ? isk[ik] : 0; + psi_p->fix_k(ik); + onsite_p->tabulate_atomic(ik); + + onsite_p->overlap_proj_psi(nbands*npol, psi_p->get_pointer()); + const std::complex* becp = onsite_p->get_h_becp(); + int nkb = onsite_p->get_size_becp() / nbands / npol; + + int begin_ih = 0; + for(int iat = 0; iat < cell.nat; iat++) + { + const int it = cell.iat2it[iat]; + const int nh = onsite_p->get_nh(iat); + const int target_l = l_channel[it]; + if(target_l == -1) + { + begin_ih += nh; + continue; + } + const int m_begin = target_l * target_l; + const int tlp1 = 2 * target_l + 1; + if(nspin == 4) + { + pw::accumulate_occ_spinor( + occmat.mat(iat, target_l, 0, 0).c, + becp, nbands, npol, nkb, begin_ih, m_begin, tlp1, + wg_in, ik); + } + else // nspin=1 or nspin=2 + { + pw::accumulate_occ_scalar( + occmat.mat(iat, target_l, 0, is).c, + becp, nbands, nkb, begin_ih, m_begin, tlp1, + wg_in, ik); + } + begin_ih += nh; + } + } +} + +void cal_occ_pw(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + Charge_Mixing* p_chgmix, + const int* isk, + const int kpar, + const int nspin, + const std::string& device, + const std::vector& l_channel, + const std::vector& u_current, + const std::vector& uterm_mat_index, + OccupationMatrix& occmat, + OccMatMixer* occ_mixer, + std::vector>& uterm_mat, + double& energy_u) +{ + ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); + occmat.copy_to_save(cell, l_channel); + if (occ_mixer != nullptr) + { + occ_mixer->begin_iter(occmat); + } + occmat.zero(cell, l_channel); + + if (device == "cpu") + { + DFTU_BASE::accumulate_occ_one_k( + psi_in, wg_in, cell, isk, nspin, l_channel, occmat); + } +#if defined(__CUDA) || defined(__ROCM) + else + { + DFTU_BASE::accumulate_occ_one_k( + psi_in, wg_in, cell, isk, nspin, l_channel, occmat); + } +#endif + + // reduce occ_mat across k-pools + pw::reduce_occ_mat(cell, nspin, kpar, l_channel, occmat); + + // mixing: flatten the fresh occ, mix against the saved one, write back + if (occ_mixer != nullptr && p_chgmix != nullptr) + { + occ_mixer->collect(occmat); + p_chgmix->mix_uom(occ_mixer->uom(), occ_mixer->uom_save()); + occ_mixer->write_back(occmat); + } + + pw::compute_pot_uterm_and_energy(cell, nspin, + u_current, l_channel, uterm_mat_index, + occmat, uterm_mat, energy_u); + + ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); +} + +} // namespace DFTU_BASE + +// explicit instantiations +template void DFTU_BASE::accumulate_occ_one_k( + const void*, const ModuleBase::matrix&, const UnitCell&, const int*, + const int, const std::vector&, OccupationMatrix&); +#if defined(__CUDA) || defined(__ROCM) +template void DFTU_BASE::accumulate_occ_one_k( + const void*, const ModuleBase::matrix&, const UnitCell&, const int*, + const int, const std::vector&, OccupationMatrix&); +#endif diff --git a/source/source_pw/module_pwdft/dftu_pw.h b/source/source_pw/module_pwdft/dftu_pw.h new file mode 100644 index 00000000000..e1a125c76d5 --- /dev/null +++ b/source/source_pw/module_pwdft/dftu_pw.h @@ -0,0 +1,62 @@ +#ifndef DFTU_PW_H +#define DFTU_PW_H + +#include +#include +#include "source_base/matrix.h" + +class UnitCell; +class OccupationMatrix; +class OccMatMixer; +class Charge_Mixing; + +/// Orchestration functions for DFT+U PW basis calculations. +/// +/// These functions manage state (psi, OnsiteProjector, Charge_Mixing, etc.) +/// and call the pure functions in dftu_pw_tools.h. They cannot be unit-tested +/// directly because they depend on runtime objects. +namespace DFTU_BASE { + +/// accumulate occ_mat from psi for all k-points (per-device template). +/// +/// Explicitly instantiated for DEVICE_CPU (and DEVICE_GPU when available) +/// in dftu_pw.cpp. +template +void accumulate_occ_one_k(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + const int* isk, + const int nspin, + const std::vector& l_channel, + OccupationMatrix& occmat); + +/// calculate the local occupation number matrix for PW based wave functions. +/// +/// This is the PW-basis entry point that: +/// 1. saves and zeroes the occupation matrix +/// 2. accumulates it from psi via accumulate_occ_one_k +/// 3. reduces across k-pools via reduce_occ_mat +/// 4. applies occupation-matrix mixing when enabled +/// 5. computes the effective potential and DFT+U energy +/// +/// All state is passed explicitly so this function can be unit-tested +/// without constructing a Plus_U_Base object. +void cal_occ_pw(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + Charge_Mixing* p_chgmix, + const int* isk, + const int kpar, + const int nspin, + const std::string& device, + const std::vector& l_channel, + const std::vector& u_current, + const std::vector& uterm_mat_index, + OccupationMatrix& occmat, + OccMatMixer* occ_mixer, + std::vector>& uterm_mat, + double& energy_u); + +} // namespace DFTU_BASE + +#endif // DFTU_PW_H diff --git a/source/source_pw/module_pwdft/dftu_base_tools.cpp b/source/source_pw/module_pwdft/dftu_pw_tools.cpp similarity index 53% rename from source/source_pw/module_pwdft/dftu_base_tools.cpp rename to source/source_pw/module_pwdft/dftu_pw_tools.cpp index d253eeed62e..e3e8c860960 100644 --- a/source/source_pw/module_pwdft/dftu_base_tools.cpp +++ b/source/source_pw/module_pwdft/dftu_pw_tools.cpp @@ -1,6 +1,11 @@ -#include "source_pw/module_pwdft/dftu_base_tools.h" +#include "source_pw/module_pwdft/dftu_pw_tools.h" -namespace DFTU_BASE { +#include "source_pw/module_pwdft/dftu_base.h" +#include "source_cell/unitcell.h" +#include "source_base/parallel_reduce.h" +#include "source_base/global_variable.h" + +namespace pw { void pauli_to_spin_basis(std::complex* pot_onsite, int m_size) { @@ -146,4 +151,105 @@ void accumulate_occ_scalar( } } -} // namespace DFTU_BASE +void reduce_occ_mat(const UnitCell& cell, + const int nspin, + const int kpar, + const std::vector& l_channel, + OccupationMatrix& occmat) +{ + for(int iat = 0; iat < cell.nat; iat++) + { + const int it = cell.iat2it[iat]; + const int target_l = l_channel[it]; + if(target_l == -1) + { + continue; + } + const int size = (2 * target_l + 1) * (2 * target_l + 1); + + if(nspin != 4) + { + Parallel_Reduce::reduce_double_allpool(kpar, + GlobalV::NPROC_IN_POOL, + occmat.mat(iat, target_l, 0, 0).c, + size); + if(nspin == 2) + { + Parallel_Reduce::reduce_double_allpool(kpar, + GlobalV::NPROC_IN_POOL, + occmat.mat(iat, target_l, 0, 1).c, + size); + } + } + else + { + Parallel_Reduce::reduce_double_allpool(kpar, + GlobalV::NPROC_IN_POOL, + occmat.mat(iat, target_l, 0, 0).c, + size * 4); + } + } +} + +void compute_pot_uterm_and_energy(const UnitCell& cell, + const int nspin, + const std::vector& u_current, + const std::vector& l_channel, + const std::vector& uterm_mat_index, + const OccupationMatrix& occmat, + std::vector>& uterm_mat, + double& energy_u) +{ + energy_u = 0.0; + const double weight_eu = (nspin == 1) ? 1.0 : (nspin == 2) ? 0.5 : 0.25; + const double diag_coeff = (nspin == 4) ? 1.0 : 0.5; + // calculate pot_onsite and energy (occ_mat already reduced above) + for(int iat = 0; iat < cell.nat; iat++) + { + const int it = cell.iat2it[iat]; + const int target_l = l_channel[it]; + if(target_l == -1) + { + continue; + } + const int size = (2 * target_l + 1) * (2 * target_l + 1); + + //update effective potential + const double u_value = u_current[it]; + std::complex* pot_onsite_iat = &(uterm_mat[uterm_mat_index[iat]]); + const int m_size = 2 * target_l + 1; + + if(nspin == 4) + { + // pot_onsite is stored as 4 contiguous Pauli blocks per atom: + // is=0: charge channel (identity), Hubbard U contributes the + // diagonal term diag_coeff*delta(m1,m2) + // is=1,2,3: spin channels (sigma_x/y/z), no U diagonal term + // The occupation matrix occ_mat[...][0][0].c packs all 4 blocks + // contiguously, each of size m_size*m_size. + energy_u += compute_pot_onsite_spinor( + pot_onsite_iat, + occmat.mat(iat, target_l, 0, 0).c, + u_value, diag_coeff, weight_eu, m_size); + } + else // nspin=1 or nspin=2 + { + // spin-up channel + energy_u += compute_pot_onsite_scalar( + pot_onsite_iat, + occmat.mat(iat, target_l, 0, 0).c, + u_value, diag_coeff, weight_eu, m_size); + // spin-down channel for nspin=2 + if(nspin == 2) + { + std::complex* pot_onsite_iat1 = &(uterm_mat[uterm_mat.size()/2 + uterm_mat_index[iat]]); + energy_u += compute_pot_onsite_scalar( + pot_onsite_iat1, + occmat.mat(iat, target_l, 0, 1).c, + u_value, diag_coeff, weight_eu, m_size); + } + } + } +} + +} // namespace pw diff --git a/source/source_pw/module_pwdft/dftu_base_tools.h b/source/source_pw/module_pwdft/dftu_pw_tools.h similarity index 69% rename from source/source_pw/module_pwdft/dftu_base_tools.h rename to source/source_pw/module_pwdft/dftu_pw_tools.h index c180703ab83..2b123406ff8 100644 --- a/source/source_pw/module_pwdft/dftu_base_tools.h +++ b/source/source_pw/module_pwdft/dftu_pw_tools.h @@ -1,5 +1,5 @@ -#ifndef DFTU_BASE_TOOLS_H -#define DFTU_BASE_TOOLS_H +#ifndef DFTU_PW_TOOLS_H +#define DFTU_PW_TOOLS_H #include #include @@ -7,16 +7,13 @@ class UnitCell; class OccupationMatrix; -class OccMatMixer; -class Charge_Mixing; -/// Free functions for DFT+U PW basis calculations. +/// Pure (side-effect free) functions for DFT+U PW basis calculations. /// -/// These functions are pure (no access to Plus_U_Base members) so they can be -/// unit-tested directly by including this header. The member functions in -/// dftu_base_occ.cpp call them after computing per-atom offsets and fetching -/// the relevant member state (occ_mat, uterm_mat, u_current, etc.). -namespace DFTU_BASE { +/// These functions are stateless and can be unit-tested directly. +/// The member functions in dftu_pw.cpp call them after computing +/// per-atom offsets and fetching the relevant member state. +namespace pw { /// transform pot_onsite from Pauli basis to spin basis (in-place, nspin==4 only). /// @@ -136,46 +133,6 @@ void compute_pot_uterm_and_energy(const UnitCell& cell, std::vector>& uterm_mat, double& energy_u); -/// accumulate occ_mat from psi for all k-points (per-device template). -/// -/// Explicitly instantiated for DEVICE_CPU (and DEVICE_GPU when available) -/// in dftu_base_occ.cpp. -template -void accumulate_occ_one_k(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - const int* isk, - const int nspin, - const std::vector& l_channel, - OccupationMatrix& occmat); - -/// calculate the local occupation number matrix for PW based wave functions. -/// -/// This is the PW-basis entry point that: -/// 1. saves and zeroes the occupation matrix -/// 2. accumulates it from psi via accumulate_occ_one_k -/// 3. reduces across k-pools via reduce_occ_mat -/// 4. applies occupation-matrix mixing when enabled -/// 5. computes the effective potential and DFT+U energy -/// -/// All state is passed explicitly so this function can be unit-tested -/// without constructing a Plus_U_Base object. -void cal_occ_pw(const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - Charge_Mixing* p_chgmix, - const int* isk, - const int kpar, - const int nspin, - const std::string& device, - const std::vector& l_channel, - const std::vector& u_current, - const std::vector& uterm_mat_index, - OccupationMatrix& occmat, - OccMatMixer* occ_mixer, - std::vector>& uterm_mat, - double& energy_u); - -} // namespace DFTU_BASE +} // namespace pw -#endif +#endif // DFTU_PW_TOOLS_H diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index b22fb9cf991..98cafa75f28 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -1,7 +1,7 @@ #include "source_pw/module_pwdft/setup_dftu_pw.h" #include "source_pw/module_pwdft/dftu_base.h" // mohan add 2025-11-06 #include "source_pw/module_pwdft/dftu_base_io.h" // mohan add 2025-11-08 -#include "source_pw/module_pwdft/dftu_base_tools.h" +#include "source_pw/module_pwdft/dftu_pw.h" #include "source_io/module_parameter/parameter.h" namespace DFTU_BASE diff --git a/source/source_pw/module_pwdft/test/CMakeLists.txt b/source/source_pw/module_pwdft/test/CMakeLists.txt index 044195040bb..5482637ed79 100644 --- a/source/source_pw/module_pwdft/test/CMakeLists.txt +++ b/source/source_pw/module_pwdft/test/CMakeLists.txt @@ -54,6 +54,13 @@ AddTest( ../../../source_cell/bcast_cell.cpp ) +AddTest( + TARGET MODULE_PW_test_dftu_pw_tools + LIBS parameter base device + SOURCES test_dftu_pw_tools.cpp + ../dftu_pw_tools.cpp +) + AddTest( TARGET MODULE_PW_structure_factor_test LIBS parameter base device planewave diff --git a/source/source_pw/module_pwdft/test/dftu_base_test.cpp b/source/source_pw/module_pwdft/test/dftu_base_test.cpp index b33d6f628a3..2281b7f2186 100644 --- a/source/source_pw/module_pwdft/test/dftu_base_test.cpp +++ b/source/source_pw/module_pwdft/test/dftu_base_test.cpp @@ -16,6 +16,7 @@ #include "gtest/gtest.h" #include +#include class DFTUBaseTest : public testing::Test { @@ -119,3 +120,261 @@ TEST_F(DFTUBaseTest, InitBaseYukawaFalseThenTrueCreatesObject) init_dftu(dftu, true); EXPECT_TRUE(dftu.use_yukawa()); } + +// ===================================================================== +// uterm_mat_index calculation +// +// nspin=1: offset = sum(tlp1^2), total = sum(all tlp1^2) +// nspin=2: same per-spin-channel, then pot_index *= 2 (split layout) +// nspin=4: offset = sum((tlp1*npol)^2), each atom = 4*tlp1^2 +// ===================================================================== + +class EffPotIndexTest : public ::testing::Test +{ + protected: + struct AtomSpec { int l; int na; }; // correlated orbital l, number of atoms + std::vector uterm_mat_index; + int pot_index; + + void compute_indices(const std::vector& atoms, int nspin) + { + pot_index = 0; + uterm_mat_index.resize(atoms.size()); + + for (size_t i = 0; i < atoms.size(); i++) + { + int tlp1 = 2 * atoms[i].l + 1; + int tlp1_npol = tlp1 * (nspin == 4 ? 2 : 1); + + if (nspin == 4) + { + uterm_mat_index[i] = pot_index; + pot_index += tlp1_npol * tlp1_npol; + } + else + { + uterm_mat_index[i] = pot_index; + pot_index += tlp1 * tlp1; + } + } + + if (nspin == 2) + pot_index *= 2; + } +}; + +TEST_F(EffPotIndexTest, Nspin1_MixedOrbitals) +{ + // 3 atoms: p(l=1), d(l=2), p(l=1) + std::vector atoms = {{1, 1}, {2, 1}, {1, 1}}; + compute_indices(atoms, 1); + + // p: 9, d: 25, p: 9 + EXPECT_EQ(uterm_mat_index[0], 0); + EXPECT_EQ(uterm_mat_index[1], 9); + EXPECT_EQ(uterm_mat_index[2], 34); + EXPECT_EQ(pot_index, 43); // 9 + 25 + 9 +} + +TEST_F(EffPotIndexTest, Nspin2and4_SplitAndPauli) +{ + // nspin=2: 2 d-atoms, split layout [up | dn] + std::vector atoms2 = {{2, 1}, {2, 1}}; + compute_indices(atoms2, 2); + EXPECT_EQ(uterm_mat_index[0], 0); + EXPECT_EQ(uterm_mat_index[1], 25); + EXPECT_EQ(pot_index, 100); // (25 + 25) * 2 + + // nspin=4: d + p atoms, Pauli blocks + std::vector atoms4 = {{2, 1}, {1, 1}}; + compute_indices(atoms4, 4); + EXPECT_EQ(uterm_mat_index[0], 0); // d: (5*2)^2 = 100 + EXPECT_EQ(uterm_mat_index[1], 100); // p: (3*2)^2 = 36 + EXPECT_EQ(pot_index, 136); +} + +// ===================================================================== +// copy_occ_mat <-> set_occ_mat roundtrip +// +// Tests the bidirectional conversion between nested occ_mat matrix +// and flat uom_array/uom_save arrays for all 3 nspin modes. +// ===================================================================== + +struct Matrix2D { + int nr, nc; + std::vector data; + Matrix2D() : nr(0), nc(0), data() {} + Matrix2D(int r, int c) : nr(r), nc(c), data(r * c, 0.0) {} + double& operator()(int i, int j) { return data[i * nc + j]; } + const double& operator()(int i, int j) const { return data[i * nc + j]; } +}; + +static void copy_occ_mat_to_flat( + const std::vector& occ_mat_up, + const std::vector& occ_mat_dn, + std::vector& uom_save, + const std::vector& uterm_mat_index, + int nspin) +{ + if (nspin == 4) + { + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; + } + } + else if (nspin == 2) // split layout: [up | dn] + { + int half_size = uom_save.size() / 2; + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + { + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; + uom_save[half_size + uterm_mat_index[iat] + mm] = occ_mat_dn[iat].data[mm]; + } + } + } + else // nspin=1: single spin channel + { + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + uom_save[uterm_mat_index[iat] + mm] = occ_mat_up[iat].data[mm]; + } + } +} + +static void set_occ_mat_from_flat( + const std::vector& uom_array, + std::vector& occ_mat_up, + std::vector& occ_mat_dn, + const std::vector& uterm_mat_index, + int nspin) +{ + if (nspin == 4) + { + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; + } + } + else if (nspin == 2) + { + int half_size = uom_array.size() / 2; + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + { + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; + occ_mat_dn[iat].data[mm] = uom_array[half_size + uterm_mat_index[iat] + mm]; + } + } + } + else // nspin=1 + { + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) + { + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; + for (int mm = 0; mm < size; mm++) + occ_mat_up[iat].data[mm] = uom_array[uterm_mat_index[iat] + mm]; + } + } +} + +class OccMatRoundtripTest : public ::testing::Test +{ + protected: + void SetUp() override {} +}; + +TEST_F(OccMatRoundtripTest, Nspin1and2_SingleAndSplitLayout) +{ + // nspin=1: single atom d-orbital roundtrip + const int l = 2; + const int size = (2 * l + 1) * (2 * l + 1); // 25 + + std::vector occ_mat_up(1, Matrix2D(2 * l + 1, 2 * l + 1)); + std::vector occ_mat_dn(1, Matrix2D(2 * l + 1, 2 * l + 1)); + for (int i = 0; i < size; i++) + occ_mat_up[0].data[i] = static_cast(i + 1); + + std::vector uterm_mat_index = {0}; + std::vector uom_save(size, 0.0); + copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 1); + set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 1); + for (int i = 0; i < size; i++) + EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); + + // nspin=2: split layout [up | dn] with distinct values + const int total = size * 2; + for (int i = 0; i < size; i++) + { + occ_mat_up[0].data[i] = static_cast(i + 1); + occ_mat_dn[0].data[i] = static_cast(i + 100); + } + uom_save.assign(total, 0.0); + copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, uterm_mat_index, 2); + // Verify split layout + for (int i = 0; i < size; i++) + { + EXPECT_DOUBLE_EQ(uom_save[i], static_cast(i + 1)); + EXPECT_DOUBLE_EQ(uom_save[size + i], static_cast(i + 100)); + } + set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, uterm_mat_index, 2); + for (int i = 0; i < size; i++) + { + EXPECT_DOUBLE_EQ(occ_mat_up[0].data[i], static_cast(i + 1)); + EXPECT_DOUBLE_EQ(occ_mat_dn[0].data[i], static_cast(i + 100)); + } +} + +TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) +{ + // 2 atoms: d(l=2), p(l=1) + struct AtomSpec { int l; }; + std::vector specs = {{2}, {1}}; + int npol = 2; + + std::vector sizes; + for (auto& s : specs) + { + int tlp1 = 2 * s.l + 1; + sizes.push_back((tlp1 * npol) * (tlp1 * npol)); + } + int total = std::accumulate(sizes.begin(), sizes.end(), 0); + + std::vector uterm_mat_index(specs.size()); + int offset = 0; + for (size_t i = 0; i < specs.size(); i++) + { + uterm_mat_index[i] = offset; + offset += sizes[i]; + } + + std::vector occ_mat(specs.size()); + for (size_t i = 0; i < specs.size(); i++) + { + int dim = (2 * specs[i].l + 1) * npol; + occ_mat[i] = Matrix2D(dim, dim); + for (int j = 0; j < sizes[i]; j++) + occ_mat[i].data[j] = static_cast(i * 1000 + j + 1); + } + + std::vector uom_array(total, 0.0); + std::vector occ_mat_dn(specs.size()); // unused for nspin=4 + + copy_occ_mat_to_flat(occ_mat, occ_mat_dn, uom_array, uterm_mat_index, 4); + set_occ_mat_from_flat(uom_array, occ_mat, occ_mat_dn, uterm_mat_index, 4); + + for (size_t i = 0; i < specs.size(); i++) + for (int j = 0; j < sizes[i]; j++) + EXPECT_DOUBLE_EQ(occ_mat[i].data[j], static_cast(i * 1000 + j + 1)); +} diff --git a/source/source_lcao/module_dftu/test/dftu_pw_test.cpp b/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp similarity index 79% rename from source/source_lcao/module_dftu/test/dftu_pw_test.cpp rename to source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp index c7c2ba5c0e9..d5a79f5d569 100644 --- a/source/source_lcao/module_dftu/test/dftu_pw_test.cpp +++ b/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp @@ -5,7 +5,7 @@ #include "source_io/module_parameter/parameter.h" #undef private #include "source_base/matrix.h" -#include "source_pw/module_pwdft/dftu_base_tools.h" +#include "source_pw/module_pwdft/dftu_pw_tools.h" /*********************************************************************** * Unit tests for DFT+U PW nspin=1/2/4 support (PR-2) @@ -83,7 +83,7 @@ TEST_F(DftuPwTest, PotOnsitePotNspin1_DiagonalLocale) occ_mat_c[m * m_size + m] = 0.3; // diagonal std::vector> pot_onsite(size, {0.0, 0.0}); - DFTU_BASE::compute_pot_onsite_scalar(pot_onsite.data(), occ_mat_c.data(), U_val, 0.5, 1.0, m_size); + pw::compute_pot_onsite_scalar(pot_onsite.data(), occ_mat_c.data(), U_val, 0.5, 1.0, m_size); // diagonal: U*(0.5 - 0.3) = 4.0*0.2 = 0.8 for (int m = 0; m < m_size; m++) @@ -107,8 +107,8 @@ TEST_F(DftuPwTest, PotOnsitePotNspin2_TwoSpinChannels) std::vector> pot_onsite_up(size, {0.0, 0.0}); std::vector> pot_onsite_dn(size, {0.0, 0.0}); - DFTU_BASE::compute_pot_onsite_scalar(pot_onsite_up.data(), occ_mat_up.data(), U_val, 0.5, 0.5, m_size); - DFTU_BASE::compute_pot_onsite_scalar(pot_onsite_dn.data(), occ_mat_dn.data(), U_val, 0.5, 0.5, m_size); + pw::compute_pot_onsite_scalar(pot_onsite_up.data(), occ_mat_up.data(), U_val, 0.5, 0.5, m_size); + pw::compute_pot_onsite_scalar(pot_onsite_dn.data(), occ_mat_dn.data(), U_val, 0.5, 0.5, m_size); // pot_onsite_up[0,0] = U*(0.5 - 0.4) = 0.5 EXPECT_DOUBLE_EQ(pot_onsite_up[0].real(), 0.5); @@ -133,7 +133,7 @@ TEST_F(DftuPwTest, PotOnsitePotNspin4_PauliTransform) pot_onsite[2] = {0.3, 0.0}; // sigma_y pot_onsite[3] = {0.2, 0.0}; // sigma_z - DFTU_BASE::pauli_to_spin_basis(pot_onsite, m_size); + pw::pauli_to_spin_basis(pot_onsite, m_size); EXPECT_DOUBLE_EQ(pot_onsite[0].real(), 0.6); // 0.5*(1.0+0.2) EXPECT_DOUBLE_EQ(pot_onsite[0].imag(), 0.0); @@ -164,7 +164,7 @@ TEST_F(DftuPwTest, EnergyNspin12_DiagonalLocale) // nspin=1: E = U * 1.0 * (0.5^2 + 0.3^2 + 0.2^2) = 4 * 0.38 = 1.52 std::vector> pot_onsite_nspin1(size, {0.0, 0.0}); - double energy_u = DFTU_BASE::compute_pot_onsite_scalar( + double energy_u = pw::compute_pot_onsite_scalar( pot_onsite_nspin1.data(), occ_mat_c.data(), U_val, 0.5, 1.0, m_size); EXPECT_DOUBLE_EQ(energy_u, 1.52); @@ -174,9 +174,9 @@ TEST_F(DftuPwTest, EnergyNspin12_DiagonalLocale) std::vector> pot_onsite_up(size, {0.0, 0.0}); std::vector> pot_onsite_dn(size, {0.0, 0.0}); energy_u = 0.0; - energy_u += DFTU_BASE::compute_pot_onsite_scalar( + energy_u += pw::compute_pot_onsite_scalar( pot_onsite_up.data(), occ_mat_up.data(), U_val, 0.5, 0.5, m_size); - energy_u += DFTU_BASE::compute_pot_onsite_scalar( + energy_u += pw::compute_pot_onsite_scalar( pot_onsite_dn.data(), occ_mat_dn.data(), U_val, 0.5, 0.5, m_size); // E = U*0.5*(0.4^2 + 0.6^2) = 4*0.5*(0.16+0.36) = 1.04 EXPECT_DOUBLE_EQ(energy_u, 1.04); @@ -200,7 +200,7 @@ TEST_F(DftuPwTest, EnergyNspin4_WithOffDiagonal) occ_mat_c[size + 2] = 0.0; occ_mat_c[size + 3] = 0.2; std::vector> pot_onsite(size * 4, {0.0, 0.0}); - double energy_u = DFTU_BASE::compute_pot_onsite_spinor( + double energy_u = pw::compute_pot_onsite_spinor( pot_onsite.data(), occ_mat_c.data(), U_val, 1.0, weight_eu, m_size); // is=0: 2*0.25*(0.5*0.5 + 0.1*0.1 + 0.1*0.1 + 0.5*0.5) = 0.26 @@ -227,7 +227,7 @@ TEST_F(DftuPwTest, LocaleAccumNspin12) wg(0, 1) = 0.5; std::vector occ_mat_c(m_size * m_size, 0.0); - DFTU_BASE::accumulate_occ_scalar( + pw::accumulate_occ_scalar( occ_mat_c.data(), becp.data(), nbands, nkb, begin_ih, m_begin, m_size, wg, ik); @@ -261,7 +261,7 @@ TEST_F(DftuPwTest, LocaleAccumNspin4_PauliComponents) ModuleBase::matrix wg(1, nbands); wg(0, 0) = 1.0; - DFTU_BASE::accumulate_occ_spinor( + pw::accumulate_occ_spinor( occ_mat_c.data(), becp.data(), nbands, npol, nkb, 0, 0, m_size, wg, ik); @@ -390,3 +390,77 @@ TEST_F(DftuPwTest, OnsitePsOpKernel_Nspin2_Npol1) EXPECT_DOUBLE_EQ(ps[0].real(), expected.real()); EXPECT_DOUBLE_EQ(ps[0].imag(), expected.imag()); } + +// ===================================================================== +// PW operator index setup (ip_iat, ip_m, pot_onsite_begin_iat) +// ip_m[ip] = m index if projector is correlated, else -1 +// ip_iat[ip] = atom index, pot_onsite_begin_iat[iat] = pot_onsite array offset +// ===================================================================== + +class PWIndexSetupTest : public ::testing::Test +{ + protected: + struct AtomInfo { int it, nh, target_l; }; // target_l=-1 if not correlated + + void setup_indices(const std::vector& atoms, + std::vector& ip_iat, std::vector& ip_m, + std::vector& pot_onsite_begin_iat, int& pot_onsite_total_size) + { + int ip0 = 0, pot_onsite_begin = 0, npol = 1; + ip_iat.resize(0); ip_m.resize(0); pot_onsite_begin_iat.resize(atoms.size()); + for (const auto& atom : atoms) + { + ip_iat.resize(ip_iat.size() + atom.nh); + ip_m.resize(ip_m.size() + atom.nh); + if (atom.target_l == -1) + { + for (int ip = 0; ip < atom.nh; ip++) + { ip_iat[ip0] = static_cast(&atom - &atoms[0]); ip_m[ip0++] = -1; } + pot_onsite_begin_iat[&atom - &atoms[0]] = 0; + } + else + { + int tlp1 = 2 * atom.target_l + 1; + pot_onsite_begin_iat[&atom - &atoms[0]] = pot_onsite_begin; + pot_onsite_begin += tlp1 * tlp1 * npol * npol; + int m_begin = atom.target_l * atom.target_l; + int m_end = (atom.target_l + 1) * (atom.target_l + 1); + for (int ip = 0; ip < atom.nh; ip++) + { + ip_iat[ip0] = static_cast(&atom - &atoms[0]); + ip_m[ip0++] = (ip >= m_begin && ip < m_end) ? ip - m_begin : -1; + } + } + } + pot_onsite_total_size = pot_onsite_begin; + } +}; + +TEST_F(PWIndexSetupTest, SingleCorrelatedAtom_DOrbital) +{ + std::vector atoms = {{0, 9, 2}}; // s(1)+p(3)+d(5) projectors, l=2 + std::vector ip_iat, ip_m, pot_onsite_begin_iat; int pot_onsite_total_size; + setup_indices(atoms, ip_iat, ip_m, pot_onsite_begin_iat, pot_onsite_total_size); + // Projectors 0-3 (s+p): m=-1; 4-8 (d): m=0..4 + EXPECT_EQ(ip_iat.size(), 9u); + for (int ip = 0; ip < 4; ip++) EXPECT_EQ(ip_m[ip], -1); + for (int ip = 4; ip < 9; ip++) { EXPECT_EQ(ip_iat[ip], 0); EXPECT_EQ(ip_m[ip], ip-4); } + EXPECT_EQ(pot_onsite_begin_iat[0], 0); + EXPECT_EQ(pot_onsite_total_size, 25); // 5*5 +} + +TEST_F(PWIndexSetupTest, MixedCorrelatedUncorrelated) +{ + std::vector atoms = {{0, 4, 1}, {1, 2, -1}}; // atom0: p-correlated, atom1: not + std::vector ip_iat, ip_m, pot_onsite_begin_iat; int pot_onsite_total_size; + setup_indices(atoms, ip_iat, ip_m, pot_onsite_begin_iat, pot_onsite_total_size); + // atom0: s(ip=0)->m=-1, p(ip=1,2,3)->m=0,1,2 + EXPECT_EQ(ip_iat[0], 0); EXPECT_EQ(ip_m[0], -1); + EXPECT_EQ(ip_iat[1], 0); EXPECT_EQ(ip_m[1], 0); + EXPECT_EQ(ip_iat[2], 0); EXPECT_EQ(ip_m[2], 1); + EXPECT_EQ(ip_iat[3], 0); EXPECT_EQ(ip_m[3], 2); + // atom1: all m=-1 + EXPECT_EQ(ip_iat[4], 1); EXPECT_EQ(ip_m[4], -1); + EXPECT_EQ(ip_iat[5], 1); EXPECT_EQ(ip_m[5], -1); + EXPECT_EQ(pot_onsite_total_size, 9); // 3*3 for p-orbital +} From b65ef28915fc8a682f2335687e18c26b607687eb Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 09:03:21 +0800 Subject: [PATCH 10/33] test: remove #define private public hack from test_dftu_pw_tools.cpp - Replace PARAM.inp.nspin with local variable c.nspin in EnergyWeightsAllNspin - Remove unnecessary parameter.h include --- source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp b/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp index d5a79f5d569..3c327479804 100644 --- a/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp +++ b/source/source_pw/module_pwdft/test/test_dftu_pw_tools.cpp @@ -1,9 +1,6 @@ #include "gtest/gtest.h" #include #include -#define private public -#include "source_io/module_parameter/parameter.h" -#undef private #include "source_base/matrix.h" #include "source_pw/module_pwdft/dftu_pw_tools.h" @@ -40,15 +37,14 @@ TEST_F(DftuPwTest, EnergyWeightsAllNspin) struct Case { int nspin; double expected_weight; double expected_diag; }; Case cases[] = {{1, 1.0, 0.5}, {2, 0.5, 0.5}, {4, 0.25, 1.0}}; for (const auto& c : cases) { - PARAM.input.nspin = c.nspin; double weight_eu = 1; - switch (PARAM.inp.nspin) { + switch (c.nspin) { case 1: weight_eu = 1.0; break; case 2: weight_eu = 0.5; break; case 4: weight_eu = 0.25; break; default: break; } - const double diag_coeff = PARAM.inp.nspin == 4 ? 1.0 : 0.5; + const double diag_coeff = c.nspin == 4 ? 1.0 : 0.5; EXPECT_DOUBLE_EQ(weight_eu, c.expected_weight); EXPECT_DOUBLE_EQ(diag_coeff, c.expected_diag); } From d900bec717cffd64621cb5a3bcc75a0432d58fc8 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 09:07:18 +0800 Subject: [PATCH 11/33] fix bug in Makefile --- source/Makefile.Objects | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Makefile.Objects b/source/Makefile.Objects index c6d2ec116e0..f1512b35770 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -837,8 +837,8 @@ OBJS_SRCPW=h_ewald_pw.o\ update_cell_pw.o\ dftu_base.o\ dftu_base_io.o\ - dftu_base_occ.o\ - dftu_base_tools.o\ + dftu_pw.o\ + dftu_pw_tools.o\ yukawa_screening.o\ setup_dftu_pw.o\ deltaspin_pw.o\ From 1aec099fa1377150615c07845ffd602ab66393de Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 10:06:36 +0800 Subject: [PATCH 12/33] refactor(dftu): demote pot_onsite/get_onsite_pot params to Plus_U_Base The three DFTU_LCAO free functions in dftu_nao_pots only use base-class accessors (occmat, get_l_channel, get_form, yukawa, get_u_current), so their dftu parameter can take Plus_U_Base& instead of the LCAO-derived Plus_U&. Callers still pass Plus_U, which upconverts implicitly, so this compiles standalone. This is step A1 of decoupling PW DFT+U from the LCAO-derived type. --- source/source_lcao/module_dftu/dftu_nao_pots.cpp | 6 +++--- source/source_lcao/module_dftu/dftu_nao_pots.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.cpp b/source/source_lcao/module_dftu/dftu_nao_pots.cpp index 94cf1a70f52..12a17e87926 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_pots.cpp @@ -7,7 +7,7 @@ #include "source_cell/unitcell.h" #ifdef __LCAO -void DFTU_LCAO::pot_onsite_complex(const Plus_U& dftu, +void DFTU_LCAO::pot_onsite_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int spin, @@ -80,7 +80,7 @@ void DFTU_LCAO::pot_onsite_complex(const Plus_U& dftu, return; } -void DFTU_LCAO::pot_onsite_real(const Plus_U& dftu, +void DFTU_LCAO::pot_onsite_real(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int spin, @@ -154,7 +154,7 @@ void DFTU_LCAO::pot_onsite_real(const Plus_U& dftu, return; } -double DFTU_LCAO::get_onsite_pot(const Plus_U& dftu, +double DFTU_LCAO::get_onsite_pot(const Plus_U_Base& dftu, const int T, const int iat, const int L, diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.h b/source/source_lcao/module_dftu/dftu_nao_pots.h index cd489c7e0d3..ee72e36868a 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.h +++ b/source/source_lcao/module_dftu/dftu_nao_pots.h @@ -3,7 +3,7 @@ #include -class Plus_U; +class Plus_U_Base; class UnitCell; class Parallel_Orbitals; @@ -27,7 +27,7 @@ namespace DFTU_LCAO { * @param new_occ_mat if true use occ_mat, otherwise use occ_mat_save * @return onsite potential matrix element */ -double get_onsite_pot(const Plus_U& dftu, +double get_onsite_pot(const Plus_U_Base& dftu, const int T, const int iat, const int L, @@ -51,7 +51,7 @@ double get_onsite_pot(const Plus_U& dftu, * @param pot_onsite output buffer (length pv->nloc) * @param npol number of polarizations */ -void pot_onsite_complex(const Plus_U& dftu, +void pot_onsite_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int spin, @@ -64,7 +64,7 @@ void pot_onsite_complex(const Plus_U& dftu, * * Real-valued counterpart of pot_onsite_complex. */ -void pot_onsite_real(const Plus_U& dftu, +void pot_onsite_real(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int spin, From f8d97885b105b93ae8112e251ecc6a9708d44d5a Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 10:26:31 +0800 Subject: [PATCH 13/33] refactor(dftu): demote pot_uterm_* params to Plus_U_Base The four pot_uterm free functions only use the base-class is_occmat_ready() plus the already-demoted pot_onsite_* helpers, so their dftu parameter can take Plus_U_Base&. Callers pass Plus_U, which upconverts implicitly. Step A2 of decoupling PW DFT+U from Plus_U. --- source/source_lcao/module_dftu/dftu_hamilt.cpp | 8 ++++---- source/source_lcao/module_dftu/dftu_hamilt.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_hamilt.cpp b/source/source_lcao/module_dftu/dftu_hamilt.cpp index 9c8b08b64be..f580f19fe0c 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.cpp +++ b/source/source_lcao/module_dftu/dftu_hamilt.cpp @@ -11,7 +11,7 @@ #ifdef __LCAO namespace DFTU_LCAO { -void pot_uterm_complex(Plus_U& dftu, +void pot_uterm_complex(Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ik, @@ -72,7 +72,7 @@ void pot_uterm_complex(Plus_U& dftu, return; } -void pot_uterm_real(Plus_U& dftu, +void pot_uterm_real(Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ik, @@ -130,7 +130,7 @@ void pot_uterm_real(Plus_U& dftu, /// @brief Accumulate the DFT+U term into the real-space HR (double). /// Wraps pot_onsite_real plus the (pot_onsite*SR + SR*pot_onsite)/2 GEMM pair. -void pot_uterm_HR_real(const Plus_U& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, double* SR, double* HR, const int npol) +void pot_uterm_HR_real(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, double* SR, double* HR, const int npol) { const char transN = 'N', transT = 'T'; const int one_int = 1; @@ -163,7 +163,7 @@ void pot_uterm_HR_real(const Plus_U& dftu, const UnitCell& ucell, const Parallel /// @brief Accumulate the DFT+U term into the real-space HR (complex). /// Wraps pot_onsite_complex plus the (pot_onsite*SR + SR*pot_onsite)/2 GEMM pair. -void pot_uterm_HR_complex(const Plus_U& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, std::complex* SR, std::complex* HR, const int npol) +void pot_uterm_HR_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, std::complex* SR, std::complex* HR, const int npol) { const char transN = 'N', transT = 'T'; const int one_int = 1; diff --git a/source/source_lcao/module_dftu/dftu_hamilt.h b/source/source_lcao/module_dftu/dftu_hamilt.h index 7b207c08f47..9525b9a7b89 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.h +++ b/source/source_lcao/module_dftu/dftu_hamilt.h @@ -4,7 +4,7 @@ #include #include -class Plus_U; +class Plus_U_Base; class Parallel_Orbitals; class UnitCell; @@ -13,7 +13,7 @@ namespace DFTU_LCAO { /// @brief Compute the LCAO-basis U-term effective potential matrix (complex). /// Calls DFTU_LCAO::pot_onsite_complex plus the S-projection GEMM. -void pot_uterm_complex(Plus_U& dftu, +void pot_uterm_complex(Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ik, @@ -24,7 +24,7 @@ void pot_uterm_complex(Plus_U& dftu, /// @brief Compute the LCAO-basis U-term effective potential matrix (real). /// Calls DFTU_LCAO::pot_onsite_real plus the S-projection GEMM. -void pot_uterm_real(Plus_U& dftu, +void pot_uterm_real(Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ik, @@ -35,7 +35,7 @@ void pot_uterm_real(Plus_U& dftu, /// @brief Accumulate the DFT+U term into the real-space HR (double). /// Wraps pot_onsite_real plus the (pot_onsite*SR + SR*pot_onsite)/2 GEMM pair. -void pot_uterm_HR_real(const Plus_U& dftu, +void pot_uterm_HR_real(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, @@ -45,7 +45,7 @@ void pot_uterm_HR_real(const Plus_U& dftu, /// @brief Accumulate the DFT+U term into the real-space HR (complex). /// Wraps pot_onsite_complex plus the (pot_onsite*SR + SR*pot_onsite)/2 GEMM pair. -void pot_uterm_HR_complex(const Plus_U& dftu, +void pot_uterm_HR_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, const int ispin, From 9630e236b332e92ecc8960d09f782acb5588e2d3 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 11:00:39 +0800 Subject: [PATCH 14/33] refactor(dftu): demote cal_energy_correction param to Plus_U_Base cal_energy_correction only uses base-class accessors (is_occmat_ready, occmat, get_l_channel, use_yukawa, yukawa, get_u_current, set_energy) plus the already-demoted get_onsite_pot, so its dftu parameter can take Plus_U_Base&. set_energy is mutable so the reference stays non-const. Step A3 of decoupling PW DFT+U from Plus_U. --- source/source_lcao/module_dftu/dftu_nao_energy.cpp | 2 +- source/source_lcao/module_dftu/dftu_nao_energy.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.cpp b/source/source_lcao/module_dftu/dftu_nao_energy.cpp index 2a6e0fa6f8a..d3eae444348 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_energy.cpp @@ -7,7 +7,7 @@ #include "source_io/module_parameter/parameter.h" #ifdef __LCAO -void DFTU_LCAO::cal_energy_correction(Plus_U& dftu, const UnitCell& ucell) +void DFTU_LCAO::cal_energy_correction(Plus_U_Base& dftu, const UnitCell& ucell) { ModuleBase::TITLE("DFTU_LCAO", "cal_energy_correction"); ModuleBase::timer::start("DFTU_LCAO", "cal_energy_correction"); diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.h b/source/source_lcao/module_dftu/dftu_nao_energy.h index efcecf6a4bd..4357c3d9dd7 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.h +++ b/source/source_lcao/module_dftu/dftu_nao_energy.h @@ -1,7 +1,7 @@ #ifndef DFTU_LCAO_ENERGY_H #define DFTU_LCAO_ENERGY_H -class Plus_U; +class Plus_U_Base; class UnitCell; #ifdef __LCAO @@ -14,10 +14,10 @@ namespace DFTU_LCAO { * result back to dftu via set_energy. The spin channel count is read from * the global input rather than a Plus_U member. * - * @param dftu Plus_U state (mutable: set_energy is called at the end) + * @param dftu Plus_U_Base state (mutable: set_energy is called at the end) * @param ucell unit cell */ -void cal_energy_correction(Plus_U& dftu, const UnitCell& ucell); +void cal_energy_correction(Plus_U_Base& dftu, const UnitCell& ucell); } // namespace DFTU_LCAO #endif From b58d509beb03cfa5a4090d8af8bc0f4723e8d9aa Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 11:10:46 +0800 Subject: [PATCH 15/33] refactor(dftu): demote cal_occ_mat_* params to Plus_U_Base cal_occ_mat, cal_occ_mat_k and cal_occ_mat_gamma only use base-class accessors (occmat, get_l_channel_vec, has_occ_mixer, occ_mixer, is_occmat_ready, set_occmat_ready), so their dftu parameter can take Plus_U_Base&. Step A4 of decoupling PW DFT+U from Plus_U. --- source/source_lcao/module_dftu/dftu_nao_occ.cpp | 10 +++++----- source/source_lcao/module_dftu/dftu_nao_occ.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.cpp b/source/source_lcao/module_dftu/dftu_nao_occ.cpp index f7bd77aa4b2..6f533ad78c8 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_occ.cpp @@ -9,7 +9,7 @@ #include "source_lcao/hamilt_lcao.h" #endif -// cal_occ_mat_k / cal_occ_mat_gamma take Plus_U& dftu directly and read all +// cal_occ_mat_k / cal_occ_mat_gamma take Plus_U_Base& dftu directly and read all // occupation-matrix state (occ/save arrays, lookup table, nspin/npol, and the // occmat_ready flag) from dftu.occmat() and the Plus_U_Base accessors. @@ -23,7 +23,7 @@ void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, const double& mixing_beta, hamilt::Hamilt>* p_ham, const bool gamma_only_local, - Plus_U& dftu) + Plus_U_Base& dftu) { ModuleBase::TITLE("DFTU_LCAO", "cal_occ_mat_k"); ModuleBase::timer::start("DFTU_LCAO", "cal_occ_mat_k"); @@ -279,7 +279,7 @@ void DFTU_LCAO::cal_occ_mat_gamma(const Parallel_Orbitals* pv, const std::vector> &dm_gamma, const double& mixing_beta, hamilt::Hamilt* p_ham, - Plus_U& dftu) + Plus_U_Base& dftu) { ModuleBase::TITLE("DFTU_LCAO", "cal_occ_mat_gamma"); ModuleBase::timer::start("DFTU_LCAO", "cal_occ_mat_gamma"); @@ -457,7 +457,7 @@ void cal_occ_mat(const Parallel_Orbitals* pv, const K_Vectors& kv, const double& mixing_beta, hamilt::Hamilt* p_ham, - Plus_U& dftu, + Plus_U_Base& dftu, const bool gamma_only_local, const int nspin) { @@ -473,7 +473,7 @@ void cal_occ_mat(const Parallel_Orbitals* pv, const K_Vectors& kv, const double& mixing_beta, hamilt::Hamilt>* p_ham, - Plus_U& dftu, + Plus_U_Base& dftu, const bool gamma_only_local, const int nspin) { diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.h b/source/source_lcao/module_dftu/dftu_nao_occ.h index eb2619499eb..bb026d29892 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.h +++ b/source/source_lcao/module_dftu/dftu_nao_occ.h @@ -11,7 +11,7 @@ #include #include -class Plus_U; +class Plus_U_Base; #ifdef __LCAO namespace DFTU_LCAO { @@ -30,7 +30,7 @@ void cal_occ_mat(const Parallel_Orbitals* pv, const K_Vectors& kv, const double& mixing_beta, hamilt::Hamilt* p_ham, - Plus_U& dftu, + Plus_U_Base& dftu, const bool gamma_only_local, const int nspin); @@ -43,7 +43,7 @@ void cal_occ_mat_k(const Parallel_Orbitals* pv, const double& mixing_beta, hamilt::Hamilt>* p_ham, const bool gamma_only_local, - Plus_U& dftu); + Plus_U_Base& dftu); // calculate the local occupation number matrix (gamma-point version) void cal_occ_mat_gamma(const Parallel_Orbitals* pv, @@ -52,7 +52,7 @@ void cal_occ_mat_gamma(const Parallel_Orbitals* pv, const std::vector>& dm_gamma, const double& mixing_beta, hamilt::Hamilt* p_ham, - Plus_U& dftu); + Plus_U_Base& dftu); } // namespace DFTU_LCAO #endif From c39519f8198ef9707be992753bf7dcb2ed45bb52 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 11:15:54 +0800 Subject: [PATCH 16/33] refactor(dftu): demote force_stress to Plus_U_Base via orb_cutoff param force_stress only used Plus_U for get_orb_cutoff(); all other state goes through base-class accessors (pot_onsite_*, get_l_channel_vec, occmat). The per-type orbital cutoff is LCAO-specific (PW uses onsite_radius), so pass it explicitly as a new orb_cutoff parameter instead of moving it to the base class. The internal cal_force_k/cal_stress_k/cal_stress_gamma already take orb_cutoff as a parameter. Caller passes orb.cutoffs(). Step A5 (B-beta) of decoupling PW DFT+U from Plus_U. --- source/source_lcao/force_stress_lcao.cpp | 2 +- source/source_lcao/module_dftu/dftu_nao_fs_k.cpp | 9 +++++---- source/source_lcao/module_dftu/dftu_nao_fs_k.h | 16 +++++----------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/source/source_lcao/force_stress_lcao.cpp b/source/source_lcao/force_stress_lcao.cpp index 895e03c1378..00c777fd9cc 100644 --- a/source/source_lcao/force_stress_lcao.cpp +++ b/source/source_lcao/force_stress_lcao.cpp @@ -457,7 +457,7 @@ void Force_Stress_LCAO::getForceStress(UnitCell& ucell, std::vector>* dmk_d = nullptr; std::vector>>* dmk_c = nullptr; assign_dmk_ptr(dmat.dm, dmk_d, dmk_c, PARAM.globalv.gamma_only_local); - DFTU_LCAO::force_stress(dftu, isforce, isstress, ucell, gd, dmk_d, dmk_c, pv, fsr_dftu, force_u, stress_u, kv, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); + DFTU_LCAO::force_stress(dftu, orb.cutoffs(), isforce, isstress, ucell, gd, dmk_d, dmk_c, pv, fsr_dftu, force_u, stress_u, kv, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); } else { diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp index 7361784bc42..e76b5585a60 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp @@ -15,7 +15,8 @@ namespace DFTU_LCAO { -void force_stress(Plus_U& dftu, +void force_stress(Plus_U_Base& dftu, + const std::vector& orb_cutoff, const bool cal_force, const bool cal_stress, const UnitCell& ucell, @@ -143,7 +144,7 @@ void force_stress(Plus_U& dftu, if (cal_stress) { cal_stress_gamma(nlocal, npol, - PARAM.inp.ks_solver, dftu.get_orb_cutoff(), + PARAM.inp.ks_solver, orb_cutoff, ucell, pv, &gd, fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z, fsr.DH_r, &rho_pot_onsite[0], stress_dftu); @@ -181,14 +182,14 @@ void force_stress(Plus_U& dftu, if (cal_force) { cal_force_k(nlocal, npol, - PARAM.inp.ks_solver, dftu.get_orb_cutoff(), + PARAM.inp.ks_solver, orb_cutoff, dftu.get_l_channel_vec(), dftu.occmat().iatlnmipol2iwt(), ucell, gd, fsr, pv, ik, &rho_pot_onsite[0], force_dftu, kv.kvec_d[ik]); } if (cal_stress) { cal_stress_k(nlocal, npol, - PARAM.inp.ks_solver, dftu.get_orb_cutoff(), + PARAM.inp.ks_solver, orb_cutoff, ucell, gd, fsr, pv, ik, &rho_pot_onsite[0], stress_dftu, kv.kvec_d[ik]); } } // ik diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.h b/source/source_lcao/module_dftu/dftu_nao_fs_k.h index e3ac9eeb41d..c381969c314 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.h +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.h @@ -1,10 +1,3 @@ -/// @file dftu_force.h -/// @brief Free-function helpers for DFT+U force and stress, extracted from -/// Plus_U. The top-level force_stress takes a Plus_U& because it needs -/// to call Plus_U::pot_onsite_real/complex; the four inner -/// functions are fully decoupled and take their dependencies as -/// explicit parameters (mirroring the folding helpers in the same -/// DFTU_LCAO namespace). #ifndef DFTU_FORCE_H #define DFTU_FORCE_H @@ -22,14 +15,15 @@ #ifdef __LCAO -class Plus_U; +class Plus_U_Base; namespace DFTU_LCAO { /// @brief Top-level entry: drives force/stress from DFT+U. -/// Takes Plus_U& because it calls dftu.pot_onsite_real/complex, -/// which are still members of Plus_U (defined in dftu_tools.cpp). -void force_stress(Plus_U& dftu, +/// Takes Plus_U_Base&; the per-type orbital cutoff is passed in explicitly +/// because it is an LCAO-specific quantity (PW uses onsite_radius instead). +void force_stress(Plus_U_Base& dftu, + const std::vector& orb_cutoff, const bool cal_force, const bool cal_stress, const UnitCell& ucell, From ffe63e028bfca89b3027845e60f72637eb0cceb5 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 11:24:12 +0800 Subject: [PATCH 17/33] refactor(dftu): demote spar_u cal_HR_dftu* params to Plus_U_Base cal_HR_dftu and cal_HR_dftu_soc only forward dftu to the already-demoted pot_uterm_HR_real/complex, so their parameter can take Plus_U_Base&. Step B1 of decoupling PW DFT+U from Plus_U. --- source/source_lcao/spar_u.cpp | 4 ++-- source/source_lcao/spar_u.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/source_lcao/spar_u.cpp b/source/source_lcao/spar_u.cpp index 4a04fe25c31..c18b77ed5aa 100644 --- a/source/source_lcao/spar_u.cpp +++ b/source/source_lcao/spar_u.cpp @@ -8,7 +8,7 @@ #include "source_lcao/module_dftu/dftu_hamilt.h" void sparse_format::cal_HR_dftu( - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 const UnitCell &ucell, const Parallel_Orbitals &pv, std::set> &all_R_coor, @@ -130,7 +130,7 @@ void sparse_format::cal_HR_dftu( void sparse_format::cal_HR_dftu_soc( - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 const UnitCell &ucell, const Parallel_Orbitals &pv, std::set> &all_R_coor, diff --git a/source/source_lcao/spar_u.h b/source/source_lcao/spar_u.h index b111e117cde..0fc4f994673 100644 --- a/source/source_lcao/spar_u.h +++ b/source/source_lcao/spar_u.h @@ -8,7 +8,7 @@ namespace sparse_format { void cal_HR_dftu( - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 const UnitCell &ucell, const Parallel_Orbitals &pv, std::set> &all_R_coor, @@ -18,7 +18,7 @@ namespace sparse_format const double &sparse_thr); void cal_HR_dftu_soc( - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 const UnitCell &ucell, const Parallel_Orbitals &pv, std::set> &all_R_coor, From 5653b403ae05234292d3f5cf5e9ab542b49818e4 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:01:31 +0800 Subject: [PATCH 18/33] refactor(dftu): hold Plus_U_Base* in DFTU/OperatorDFTU operators Both operator class templates now store and accept Plus_U_Base* instead of the LCAO-derived Plus_U*. OperatorDFTU only uses base-class interfaces (pot_uterm_*), so it demotes cleanly. DFTU still needs the LCAO-only get_dmr() for the density matrix, so the five get_dmr() call sites use a static_cast back to the derived type; the cast in cal_fs_nao_r is hoisted to a single local at function entry. This confines the base-to-derived cast to the operators' DM access, so upstream callers (HamiltLCAO, getForceStress) can pass base-class pointers. Step B (operators) of decoupling PW DFT+U from Plus_U. --- source/source_lcao/module_dftu/dftu_nao_fs_r.cpp | 7 ++++--- source/source_lcao/module_dftu/dftu_nao_op.cpp | 6 +++--- source/source_lcao/module_dftu/dftu_nao_op.h | 6 +++--- source/source_lcao/module_dftu/dftu_nao_op_legacy.h | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp b/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp index 6e170cd7527..80b36b9bb4c 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_fs_r.cpp @@ -21,18 +21,19 @@ void cal_fs_nao_r(DFTU>* dftu_op, ModuleBase::matrix& stress) { ModuleBase::TITLE("DFTU", "cal_fs_nao_r"); - if (dftu_op->get_dftu()->get_dmr(0) == nullptr) + const Plus_U* dftu = static_cast(dftu_op->get_dftu()); + if (dftu->get_dmr(0) == nullptr) { ModuleBase::WARNING_QUIT("DFTU", "dmr is not set"); } // try to get the density matrix, if the density matrix is empty, skip the calculation and return std::vector*> dmR_tmp(dftu_op->get_nspin(), nullptr); - dmR_tmp[0] = dftu_op->get_dftu()->get_dmr(0); + dmR_tmp[0] = dftu->get_dmr(0); if (dftu_op->get_nspin() == 2) { - dmR_tmp[1] = dftu_op->get_dftu()->get_dmr(1); + dmR_tmp[1] = dftu->get_dmr(1); } if (dmR_tmp[0]->size_atom_pairs() == 0) { diff --git a/source/source_lcao/module_dftu/dftu_nao_op.cpp b/source/source_lcao/module_dftu/dftu_nao_op.cpp index a1c8bdcddfc..42bb9267607 100644 --- a/source/source_lcao/module_dftu/dftu_nao_op.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_op.cpp @@ -18,7 +18,7 @@ hamilt::DFTU>::DFTU(HS_Matrix_K* hsk_in, const Grid_Driver* GridD_in, const TwoCenterIntegrator* intor, const std::vector& orb_cutoff, - Plus_U* p_dftu) + Plus_U_Base* p_dftu) : hamilt::OperatorLCAO(hsk_in, kvec_d_in, hR_in), intor_(intor), orb_cutoff_(orb_cutoff) { this->cal_type = calculation_type::lcao_dftu; @@ -229,7 +229,7 @@ void hamilt::DFTU>::contributeHR() // - get_dmr(0) == nullptr: DMR not available (typical in first iteration without file input) // - !is_occmat_ready(): occ_mat not read from file AND not yet computed from DMR // When both true, skip DFT+U contribution entirely (first iteration, no file input) - const bool dmr_null = (this->dftu->get_dmr(0) == nullptr); + const bool dmr_null = (static_cast(this->dftu)->get_dmr(0) == nullptr); const bool occ_mat_not_init = !this->dftu->is_occmat_ready(); if (dmr_null && occ_mat_not_init) @@ -287,7 +287,7 @@ void hamilt::DFTU>::contributeHR() // TODO: UNSAFE - get_dmr(current_spin) assumes DMR has correct spin indexing. // For nspin=2, current_spin must be correctly toggled (0 then 1). // If current_spin is wrong, wrong spin channel's DMR is used. - const hamilt::HContainer* dmR_current = this->dftu->get_dmr(this->current_spin); + const hamilt::HContainer* dmR_current = static_cast(this->dftu)->get_dmr(this->current_spin); for (int ad1 = 0; ad1 < adjs.adj_num + 1; ++ad1) { const int T1 = adjs.ntype[ad1]; diff --git a/source/source_lcao/module_dftu/dftu_nao_op.h b/source/source_lcao/module_dftu/dftu_nao_op.h index d7f6c51d16f..701b624691c 100644 --- a/source/source_lcao/module_dftu/dftu_nao_op.h +++ b/source/source_lcao/module_dftu/dftu_nao_op.h @@ -45,7 +45,7 @@ class DFTU> : public OperatorLCAO const Grid_Driver* gridD_in, const TwoCenterIntegrator* intor, const std::vector& orb_cutoff, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); ~DFTU>(); /** @@ -62,7 +62,7 @@ class DFTU> : public OperatorLCAO // Getters for free functions in dftu_nao_fs_r/dftu_nao_for_r/dftu_nao_str_r const UnitCell* get_ucell() const { return ucell; } - Plus_U* get_dftu() const { return dftu; } + Plus_U_Base* get_dftu() const { return dftu; } const TwoCenterIntegrator* get_intor() const { return intor_; } int get_nspin() const { return nspin; } std::vector& get_adjs_all() { return adjs_all; } @@ -77,7 +77,7 @@ class DFTU> : public OperatorLCAO private: const UnitCell* ucell = nullptr; - Plus_U* dftu = nullptr; + Plus_U_Base* dftu = nullptr; hamilt::HContainer* HR = nullptr; diff --git a/source/source_lcao/module_dftu/dftu_nao_op_legacy.h b/source/source_lcao/module_dftu/dftu_nao_op_legacy.h index e6e9168fa66..721be121f7f 100644 --- a/source/source_lcao/module_dftu/dftu_nao_op_legacy.h +++ b/source/source_lcao/module_dftu/dftu_nao_op_legacy.h @@ -25,7 +25,7 @@ class OperatorDFTU> : public OperatorLCAO const std::vector>& kvec_d_in, hamilt::HContainer* hR_in, const UnitCell& ucell_in, - Plus_U* dftu_in, + Plus_U_Base* dftu_in, const std::vector& isk_in, const int npol_in) : isk(isk_in), npol(npol_in), OperatorLCAO(hsk_in, kvec_d_in, hR_in) @@ -41,7 +41,7 @@ class OperatorDFTU> : public OperatorLCAO private: - Plus_U *dftu; + Plus_U_Base *dftu; const UnitCell* ucell = nullptr; From c80b8c45e1c1182ca5af892ef6fa8d4634f2bf7b Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:04:31 +0800 Subject: [PATCH 19/33] refactor(dftu): demote HamiltLCAO p_dftu param to Plus_U_Base The HamiltLCAO constructor only forwards p_dftu to the DFTU/OperatorDFTU operator constructors, which now accept Plus_U_Base*. Demote the parameter and switch the forward declaration from Plus_U to Plus_U_Base. Callers pass &this->dftu (a Plus_U) which upcasts implicitly. --- source/source_lcao/hamilt_lcao.cpp | 2 +- source/source_lcao/hamilt_lcao.h | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/source_lcao/hamilt_lcao.cpp b/source/source_lcao/hamilt_lcao.cpp index 8073516745b..e50761d912b 100644 --- a/source/source_lcao/hamilt_lcao.cpp +++ b/source/source_lcao/hamilt_lcao.cpp @@ -82,7 +82,7 @@ HamiltLCAO::HamiltLCAO(const UnitCell& ucell, const TwoCenterBundle& two_center_bundle, const LCAO_Orbitals& orb, elecstate::DensityMatrix* DM_in, - Plus_U* p_dftu, // mohan add 2025-11-05 + Plus_U_Base* p_dftu, // mohan add 2025-11-05 Setup_DeePKS &deepks, const int istep, Exx_NAO &exx_nao, diff --git a/source/source_lcao/hamilt_lcao.h b/source/source_lcao/hamilt_lcao.h index 62ed73df3ce..4e121d64e87 100644 --- a/source/source_lcao/hamilt_lcao.h +++ b/source/source_lcao/hamilt_lcao.h @@ -22,9 +22,8 @@ namespace elecstate { template class DensityMatrix; } // Setup_DeePKS forward declaration, full definition in setup_deepks.h (moved to .cpp) // mohan add 20260605 template class Setup_DeePKS; -// Plus_U forward declaration, full definition in module_dftu/dftu_nao.h (moved to .cpp) -// mohan add 20260605 -class Plus_U; +// Plus_U_Base forward declaration, full definition in source_pw/module_pwdft/dftu_base.h +class Plus_U_Base; // Exx_NAO forward declaration, full definition in setup_exx.h (moved to .cpp) // mohan add 20260605 @@ -61,7 +60,7 @@ class HamiltLCAO : public Hamilt const TwoCenterBundle& two_center_bundle, const LCAO_Orbitals& orb, elecstate::DensityMatrix* DM_in, - Plus_U* p_dftu, // mohan add 2025-11-05 + Plus_U_Base* p_dftu, // mohan add 2025-11-05 Setup_DeePKS &deepks, const int istep, Exx_NAO &exx_nao, From 90043552277d7c3b8a418843e232e3397515b02a Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:07:03 +0800 Subject: [PATCH 20/33] refactor(dftu): demote getForceStress dftu param to Plus_U_Base getForceStress only forwards dftu to the already-demoted force_stress and passes &dftu to the DFTU operator constructor (now Plus_U_Base*), so its parameter can take Plus_U_Base& with no cast needed. --- source/source_lcao/force_stress_lcao.cpp | 2 +- source/source_lcao/force_stress_lcao.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/source_lcao/force_stress_lcao.cpp b/source/source_lcao/force_stress_lcao.cpp index 00c777fd9cc..22316bc5b58 100644 --- a/source/source_lcao/force_stress_lcao.cpp +++ b/source/source_lcao/force_stress_lcao.cpp @@ -87,7 +87,7 @@ void Force_Stress_LCAO::getForceStress(UnitCell& ucell, const K_Vectors& kv, ModulePW::PW_Basis* rhopw, surchem& solvent, - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 Setup_DeePKS& deepks, Exx_NAO &exx_nao, ModuleSymmetry::Symmetry* symm, diff --git a/source/source_lcao/force_stress_lcao.h b/source/source_lcao/force_stress_lcao.h index 0df810ad5d3..cf3fa200390 100644 --- a/source/source_lcao/force_stress_lcao.h +++ b/source/source_lcao/force_stress_lcao.h @@ -58,7 +58,7 @@ class Force_Stress_LCAO const K_Vectors& kv, ModulePW::PW_Basis* rhopw, surchem& solvent, - Plus_U &dftu, // mohan add 2025-11-07 + Plus_U_Base &dftu, // mohan add 2025-11-07 Setup_DeePKS &deepks, Exx_NAO &exx_nao, ModuleSymmetry::Symmetry* symm, From 9cdde1b9218ee0d4899837707726a9b597fe1a6c Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:10:17 +0800 Subject: [PATCH 21/33] refactor(dftu): demote output_mat_sparse p_dftu param to Plus_U_Base The p_dftu parameter is unused inside output_mat_sparse (only forwarded between the two overloads), so demote it to Plus_U_Base* across both declarations, both definitions, and the four explicit instantiations. --- source/source_io/module_hs/output_mat_sparse.cpp | 12 ++++++------ source/source_io/module_hs/output_mat_sparse.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/source_io/module_hs/output_mat_sparse.cpp b/source/source_io/module_hs/output_mat_sparse.cpp index bb72477675b..269ea282fb9 100644 --- a/source/source_io/module_hs/output_mat_sparse.cpp +++ b/source/source_io/module_hs/output_mat_sparse.cpp @@ -16,7 +16,7 @@ void output_mat_sparse(const MatSparseOutputOptions& options, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu) + Plus_U_Base* p_dftu) { LCAO_HS_Arrays HS_Arrays; // store sparse arrays @@ -95,7 +95,7 @@ void output_mat_sparse(const bool& out_mat_dh, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu) + Plus_U_Base* p_dftu) { MatSparseOutputOptions options; options.out_mat_dh = out_mat_dh; @@ -128,7 +128,7 @@ template void output_mat_sparse(const bool& out_mat_dh, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); template void output_mat_sparse>(const bool& out_mat_dh, const bool& out_mat_ds, @@ -143,7 +143,7 @@ template void output_mat_sparse>(const bool& out_mat_dh, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt>* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); template void output_mat_sparse(const MatSparseOutputOptions& options, const int& istep, @@ -155,7 +155,7 @@ template void output_mat_sparse(const MatSparseOutputOptions& options, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); template void output_mat_sparse>(const MatSparseOutputOptions& options, const int& istep, @@ -167,6 +167,6 @@ template void output_mat_sparse>(const MatSparseOutputOptio const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt>* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); } // namespace ModuleIO diff --git a/source/source_io/module_hs/output_mat_sparse.h b/source/source_io/module_hs/output_mat_sparse.h index 7ee4ecd9068..985fa6d3e6d 100644 --- a/source/source_io/module_hs/output_mat_sparse.h +++ b/source/source_io/module_hs/output_mat_sparse.h @@ -36,7 +36,7 @@ void output_mat_sparse(const MatSparseOutputOptions& options, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); /// @brief legacy bool-only interface kept for source compatibility template @@ -53,7 +53,7 @@ void output_mat_sparse(const bool& out_mat_dh, const Grid_Driver& grid, const K_Vectors& kv, hamilt::Hamilt* p_ham, - Plus_U* p_dftu); + Plus_U_Base* p_dftu); } // namespace ModuleIO #endif // OUTPUT_MAT_SPARSE_H From 94300465d93f3b4b8eb7f7aeb3a72ad99b43b559 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:19:17 +0800 Subject: [PATCH 22/33] refactor(dftu): sink ctrl_scf_lcao dftu param to Plus_U_Base Change the ctrl_scf_lcao template and its three explicit specializations to take Plus_U_Base& instead of Plus_U&. The dftu argument is only forwarded (to output_mat_sparse, already on Plus_U_Base*), so no cast is needed. Switch the header include from dftu_nao.h to dftu_base.h. Verified: make -j 30 in build_max_para_test builds abacus_max_para. --- source/source_io/module_ctrl/ctrl_scf_lcao.cpp | 8 ++++---- source/source_io/module_ctrl/ctrl_scf_lcao.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index e67a19e09aa..51bfe945fc6 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -90,7 +90,7 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, Grid_Driver& gd, psi::Psi* psi, hamilt::HamiltLCAO* p_hamilt, - Plus_U& dftu, // mohan add 2025-11-07 + Plus_U_Base& dftu, // mohan add 2025-11-07 TwoCenterBundle& two_center_bundle, LCAO_Orbitals& orb, const ModulePW::PW_Basis_K* pw_wfc, // for berryphase @@ -752,7 +752,7 @@ template void ModuleIO::ctrl_scf_lcao( Grid_Driver& gd, psi::Psi* psi, hamilt::HamiltLCAO* p_hamilt, - Plus_U& dftu, // mohan add 2025-11-07 + Plus_U_Base& dftu, // mohan add 2025-11-07 TwoCenterBundle& two_center_bundle, LCAO_Orbitals& orb, const ModulePW::PW_Basis_K* pw_wfc, // for berryphase @@ -781,7 +781,7 @@ template void ModuleIO::ctrl_scf_lcao, double>( Grid_Driver& gd, psi::Psi>* psi, hamilt::HamiltLCAO, double>* p_hamilt, - Plus_U& dftu, // mohan add 2025-11-07 + Plus_U_Base& dftu, // mohan add 2025-11-07 TwoCenterBundle& two_center_bundle, LCAO_Orbitals& orb, const ModulePW::PW_Basis_K* pw_wfc, // for berryphase @@ -809,7 +809,7 @@ template void ModuleIO::ctrl_scf_lcao, std::complex Grid_Driver& gd, psi::Psi>* psi, hamilt::HamiltLCAO, std::complex>* p_hamilt, - Plus_U& dftu, // mohan add 2025-11-07 + Plus_U_Base& dftu, // mohan add 2025-11-07 TwoCenterBundle& two_center_bundle, LCAO_Orbitals& orb, const ModulePW::PW_Basis_K* pw_wfc, // for berryphase diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.h b/source/source_io/module_ctrl/ctrl_scf_lcao.h index 63688c08452..5d359d3fe28 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.h +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.h @@ -9,7 +9,7 @@ #include "source_estate/module_dm/density_matrix.h" // mohan add 2025-11-04 #include "source_hamilt/module_surchem/surchem.h" // use surchem (for dH veff pots) #include "source_lcao/hamilt_lcao.h" // use hamilt::HamiltLCAO -#include "source_lcao/module_dftu/dftu_nao.h" // mohan add 20251107 +#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base, mohan add 20251107 #include "source_lcao/module_rdmft/rdmft.h" // use RDMFT codes #include "source_lcao/setup_deepks.h" // for deepks, mohan add 20251008 #include "source_lcao/setup_exx.h" // for exx, mohan add 20251008 @@ -31,7 +31,7 @@ void ctrl_scf_lcao(UnitCell& ucell, Grid_Driver& gd, psi::Psi* psi, hamilt::HamiltLCAO* p_hamilt, - Plus_U& dftu, // mohan add 2025-11-07 + Plus_U_Base& dftu, // mohan add 2025-11-07 TwoCenterBundle& two_center_bundle, LCAO_Orbitals& orb, const ModulePW::PW_Basis_K* pw_wfc, // for berryphase From 1f294d474cb89a6fe183b5ebe005b3efefa99f0a Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 12:24:27 +0800 Subject: [PATCH 23/33] refactor(dftu): sink LCAO_domain::set_pot dftu param to Plus_U_Base set_pot only needs the LCAO-specific init(ucell, ..., &orb), which lives on the derived Plus_U. Take Plus_U_Base& at the interface and cast to Plus_U& at the single init call site, matching the existing set_dmr pattern. The header now forward-declares Plus_U_Base instead of including dftu_nao.h; the .cpp includes dftu_nao.h for the cast. Verified: make -j 30 in build_max_para_test builds abacus_max_para. --- source/source_lcao/lcao_set.cpp | 11 +++++++---- source/source_lcao/lcao_set.h | 6 ++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/source/source_lcao/lcao_set.cpp b/source/source_lcao/lcao_set.cpp index 92d674bb501..2ca815b5f60 100644 --- a/source/source_lcao/lcao_set.cpp +++ b/source/source_lcao/lcao_set.cpp @@ -7,6 +7,7 @@ #include "source_lcao/rho_tau_lcao.h" // use dm2rho #include "source_lcao/hamilt_lcao.h" // use HamiltLCAO for init_chg_hr #include "source_hsolver/hsolver_lcao.h" // use HSolverLCAO for init_chg_hr +#include "source_lcao/module_dftu/dftu_nao.h" // use Plus_U for the LCAO-specific init template void LCAO_domain::set_psi_occ_dm_chg( @@ -60,7 +61,7 @@ void LCAO_domain::set_pot( const LCAO_Orbitals& orb, Parallel_Orbitals &pv, // not const due to deepks pseudopot_cell_vl &locpp, - Plus_U &dftu, + Plus_U_Base &dftu, surchem& solvent, Exx_NAO &exx_nao, Setup_DeePKS &deepks, @@ -82,7 +83,9 @@ void LCAO_domain::set_pot( if (inp.dft_plus_u) { - dftu.init(ucell, &pv, + // set_pot receives the base-class reference; the LCAO-specific init + // (with LCAO_Orbitals) lives on the derived Plus_U, so cast here. + static_cast(dftu).init(ucell, &pv, PARAM.globalv.npol, inp.nspin, inp.l_channel, inp.yukawa_potential, inp.yukawa_lambda, PARAM.globalv.global_readin_dir, @@ -274,7 +277,7 @@ template void LCAO_domain::set_pot( const LCAO_Orbitals& orb, Parallel_Orbitals &pv, pseudopot_cell_vl &locpp, - Plus_U &dftu, + Plus_U_Base &dftu, surchem& solvent, Exx_NAO &exx_nao, Setup_DeePKS &deepks, @@ -291,7 +294,7 @@ template void LCAO_domain::set_pot>( const LCAO_Orbitals& orb, Parallel_Orbitals &pv, pseudopot_cell_vl &locpp, - Plus_U &dftu, + Plus_U_Base &dftu, surchem& solvent, Exx_NAO> &exx_nao, Setup_DeePKS> &deepks, diff --git a/source/source_lcao/lcao_set.h b/source/source_lcao/lcao_set.h index 7ed7a4cc9a0..4d5b6019c5e 100644 --- a/source/source_lcao/lcao_set.h +++ b/source/source_lcao/lcao_set.h @@ -12,10 +12,12 @@ #include "source_basis/module_pw/pw_basis.h" #include "source_hamilt/module_surchem/surchem.h" #include "source_pw/module_pwdft/vl_pw.h" -#include "source_lcao/module_dftu/dftu_nao.h" #include "source_lcao/setup_exx.h" #include "source_lcao/setup_deepks.h" +// Plus_U_Base forward declaration, full definition in source_pw/module_pwdft/dftu_base.h +class Plus_U_Base; + namespace LCAO_domain { @@ -48,7 +50,7 @@ void set_pot( const LCAO_Orbitals& orb, Parallel_Orbitals &pv, pseudopot_cell_vl &locpp, - Plus_U &dftu, + Plus_U_Base &dftu, surchem& solvent, Exx_NAO &exx_nao, Setup_DeePKS &deepks, From ca524e7a2910a0952add21385be58231b28547be Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 14:03:04 +0800 Subject: [PATCH 24/33] refactor(dftu): make Plus_U_Base destructor virtual Plus_U adds members (orb_cutoff_, dm_in_dftu_*) that require proper destruction. The upcoming esolver change holds the object through a Plus_U_Base* and deletes it in the base-class destructor, which is undefined behavior without a virtual destructor. Make it virtual now as a standalone, separately-compilable step. Verified: make -j 30 in build_max_para_test builds abacus_max_para. --- source/source_pw/module_pwdft/dftu_base.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index 0b6e970bae5..0ea60b278d6 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -32,7 +32,8 @@ class Plus_U_Base }; Plus_U_Base(); - ~Plus_U_Base(); + // virtual so that a derived Plus_U can be deleted through a Plus_U_Base* + virtual ~Plus_U_Base(); /// allocate relevant data structures (base part, no LCAO types) void init_base(UnitCell& cell, From 156a5d8d5faf5f37123d224e7eb49a83fa467674 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 14:15:33 +0800 Subject: [PATCH 25/33] Refactor: change ESolver_KS dftu member to base-class pointer Replace the value member `Plus_U dftu` with a base-class pointer `Plus_U_Base* dftu_` in ESolver_KS, so that the PW/LCAO layering no longer requires the base class to know the LCAO-derived Plus_U type. - esolver_ks.h: member -> Plus_U_Base* dftu_ = nullptr; include dftu_base.h instead of dftu_nao.h. - esolver_ks.cpp: delete dftu_ in ~ESolver_KS (virtual dtor on Plus_U_Base makes this safe); update u_converged() call. - esolver_ks_pw.cpp: allocate `new Plus_U_Base()` in ctor (PW basis). - esolver_ks_lcao.cpp: allocate `new Plus_U()` in ctor (LCAO basis); include dftu_nao.h for the derived type. - Adapt all call sites to the pointer/reference forms expected by the already-base-classified helpers (Hamilt*, setup_pot, chgmixing, ctrl_scf_lcao, init/finish_dftu_lcao void* API, force/stress/dfpt). Derived classes (TDDFT, DoubleXC, DFPT_PW, lcao_others) inherit the already-constructed dftu_ via the ESolver_KS_PW / ESolver_KS_LCAO constructors, so each object is allocated exactly once. Build: make -j 30 in build_max_para_test, abacus_max_para links OK. --- source/source_esolver/esolver_dfpt_pw.cpp | 2 +- source/source_esolver/esolver_double_xc.cpp | 4 ++-- source/source_esolver/esolver_ks.cpp | 2 +- source/source_esolver/esolver_ks.h | 5 +++-- source/source_esolver/esolver_ks_lcao.cpp | 17 +++++++++-------- source/source_esolver/esolver_ks_pw.cpp | 16 +++++++++------- source/source_esolver/lcao_others.cpp | 2 +- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/source/source_esolver/esolver_dfpt_pw.cpp b/source/source_esolver/esolver_dfpt_pw.cpp index 3fd2c195ed5..9da0be98029 100644 --- a/source/source_esolver/esolver_dfpt_pw.cpp +++ b/source/source_esolver/esolver_dfpt_pw.cpp @@ -354,7 +354,7 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) dfpt_->init(ucell, *this->stp.psi_cpu, this->pw_rho, this->pw_wfc, &this->sf, veff_r, this->pelec->wg, this->pelec->ekb, xc_adapter_, nelec_, ecutwfc_, - dft_plus_u_ ? &this->dftu : nullptr); + dft_plus_u_ ? this->dftu_ : nullptr); } void ESolver_DFPT_PW::run_post_process(UnitCell& ucell) diff --git a/source/source_esolver/esolver_double_xc.cpp b/source/source_esolver/esolver_double_xc.cpp index 7c3cf9a1c85..a787bc96c20 100644 --- a/source/source_esolver/esolver_double_xc.cpp +++ b/source/source_esolver/esolver_double_xc.cpp @@ -148,7 +148,7 @@ void ESolver_DoubleXC::before_scf(UnitCell& ucell, const int istep) this->two_center_bundle_, this->orb_, this->dmat_base.dm, - &this->dftu, + this->dftu_, this->deepks, istep, this->exx_nao, @@ -413,7 +413,7 @@ void ESolver_DoubleXC::cal_force(BaseCell& basecell, ModuleBase::matrix& this->kv, this->pw_rho, this->solvent, - this->dftu, + *this->dftu_, this->deepks, this->exx_nao, &ucell.symm, diff --git a/source/source_esolver/esolver_ks.cpp b/source/source_esolver/esolver_ks.cpp index dec3fdd5770..4139eb1f9f2 100644 --- a/source/source_esolver/esolver_ks.cpp +++ b/source/source_esolver/esolver_ks.cpp @@ -246,7 +246,7 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & #ifdef __LCAO if (this->inp_->dft_plus_u) { - converged_u = this->dftu.u_converged(); + converged_u = this->dftu_->u_converged(); } #endif diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index b10e4ef7307..a27e189715a 100644 --- a/source/source_esolver/esolver_ks.h +++ b/source/source_esolver/esolver_ks.h @@ -60,8 +60,9 @@ class ESolver_KS : public ESolver_FP //! nonlocal pseudopotentials pseudopot_cell_vnl ppcell; - //! DFT+U method, mohan add 2025-11-07 - Plus_U dftu; + //! DFT+U method (base-class pointer; PW news Plus_U_Base, LCAO news Plus_U), + //! allocated in the derived-class constructor, deleted in ~ESolver_KS. + Plus_U_Base* dftu_ = nullptr; std::string basisname; //! esolver_ks_lcao.cpp double esolver_KS_ne = 0.0; //! number of electrons diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index 880509021f5..c9d8a424405 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -5,6 +5,7 @@ #include "source_lcao/module_deltaspin/spin_constrain.h" #include "source_lcao/module_deltaspin/deltaspin_lcao.h" #include "source_lcao/setup_dftu_lcao.h" +#include "source_lcao/module_dftu/dftu_nao.h" // Plus_U (LCAO DFT+U derived class) #include "source_hamilt/hs_matrix_k.h" #include "source_estate/module_charge/symm_rho.h" #include "source_lcao/lcao_domain.h" // need DeePKS_init @@ -92,7 +93,7 @@ void ESolver_KS_LCAO::before_all_runners(BaseCell& basecell, const Input this->dmat, this->chr, inp); LCAO_domain::set_pot(ucell, this->kv, this->sf, *this->pw_rho, *this->pw_rhod, - this->pelec, this->orb_, this->pv, this->locpp, this->dftu, + this->pelec, this->orb_, this->pv, this->locpp, *this->dftu_, this->solvent, this->exx_nao, this->deepks, inp, this->exx_info_); //! if kpar is not divisible by nks, print a warning @@ -156,7 +157,7 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep) { this->p_hamilt = new hamilt::HamiltLCAO( ucell, this->gd, &this->pv, this->pelec->pot, this->kv, - two_center_bundle_, orb_, this->dmat.dm, &this->dftu, this->deepks, istep, exx_nao, this->exx_info_); + two_center_bundle_, orb_, this->dmat.dm, this->dftu_, this->deepks, istep, exx_nao, this->exx_info_); } // 9) for each ionic step, the overlap must be rebuilt @@ -256,7 +257,7 @@ void ESolver_KS_LCAO::cal_force(BaseCell& basecell, ModuleBase::matrix& this->gd, this->pv, this->pelec, this->dmat, this->psi, two_center_bundle_, orb_, force, this->scs, this->locpp, this->sf, this->kv, - this->pw_rho, this->solvent, this->dftu, this->deepks, + this->pw_rho, this->solvent, *this->dftu_, this->deepks, this->exx_nao, &ucell.symm, this->exx_info_, this->inp_->td_stype, static_cast*>(this->p_hamilt)); @@ -333,7 +334,7 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const // call iter_init() of ESolver_KS ESolver_KS::iter_init(ucell, istep, iter); - module_charge::chgmixing_ks_lcao(iter, this->p_chgmix, this->dftu, + module_charge::chgmixing_ks_lcao(iter, this->p_chgmix, *this->dftu_, this->dmat.dm->get_DMR_pointer(1)->get_nnr(), *this->inp_); if (iter == 1) @@ -387,7 +388,7 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const } #endif - init_dftu_lcao(istep, iter, this->inp_->dft_plus_u, &(this->dftu), this->dmat.dm, ucell, this->chr.rho, this->pw_rho->nrxx); + init_dftu_lcao(istep, iter, this->inp_->dft_plus_u, this->dftu_, this->dmat.dm, ucell, this->chr.rho, this->pw_rho->nrxx); #ifdef __MLALGO // the density matrixes of DeePKS have been updated in each iter @@ -508,14 +509,14 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& const std::vector>& dm_vec = this->dmat.dm->get_DMK_vector(); // 1) calculate the local occupation number matrix and energy correction in DFT+U - finish_dftu_lcao(iter, conv_esolver, this->inp_->dft_plus_u, this->inp_->out_chg[0], &(this->dftu), ucell, dm_vec, this->kv, this->p_chgmix->get_mixing_beta(), hamilt_lcao, PARAM.globalv.global_out_dir, this->inp_->nspin, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); + finish_dftu_lcao(iter, conv_esolver, this->inp_->dft_plus_u, this->inp_->out_chg[0], this->dftu_, ucell, dm_vec, this->kv, this->p_chgmix->get_mixing_beta(), hamilt_lcao, PARAM.globalv.global_out_dir, this->inp_->nspin, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); // mohan add 2025-11: push DFT+U energy from Plus_U instance to ElecState. // Covers both dft_plus_u==1 (new method, energy accumulated by DFTU::contributeHR // via cal_pot_onsite) and dft_plus_u==2 (old method, energy from cal_energy_correction). if (this->inp_->dft_plus_u) { - this->pelec->set_dftu_energy(this->dftu.get_energy()); + this->pelec->set_dftu_energy(this->dftu_->get_energy()); } // 2) for deepks, calculate delta_e, output labels during electronic steps @@ -579,7 +580,7 @@ void ESolver_KS_LCAO::after_scf(UnitCell& ucell, const int istep, const //! 2) output of lcao every few ionic steps ModuleIO::ctrl_scf_lcao(ucell, *this->inp_, this->kv, this->pelec, this->dmat.dm, this->pv, - this->gd, this->psi, hamilt_lcao, this->dftu, this->two_center_bundle_, + this->gd, this->psi, hamilt_lcao, *this->dftu_, this->two_center_bundle_, this->orb_, this->pw_wfc, this->pw_rho, this->pw_big, this->sf, this->pw_rhod, this->locpp.vloc, this->solvent, this->rdmft_solver, this->deepks, this->exx_nao, this->exx_info_, diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 048ce5eb4ee..82070c95e71 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -32,6 +32,8 @@ ESolver_KS_PW::ESolver_KS_PW() { this->classname = "ESolver_KS_PW"; this->basisname = "PW"; + // PW basis: the DFT+U object is the base class (no LCAO orbitals). + this->dftu_ = new Plus_U_Base(); } template @@ -65,7 +67,7 @@ void ESolver_KS_PW::allocate_hamilt(const UnitCell& ucell) this->pw_wfc, &this->kv, &this->ppcell, - &this->dftu, + this->dftu_, &ucell, &this->general_exx_info_); } @@ -171,7 +173,7 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) this->chr, this->locpp, this->ppcell, - this->dftu, + *this->dftu_, this->vsep_cell, this->stp.template get_psi_t(), this->p_hamilt, @@ -194,7 +196,7 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const { ESolver_KS::iter_init(ucell, istep, iter); - module_charge::chgmixing_ks_pw(iter, this->p_chgmix, this->dftu, *this->inp_); + module_charge::chgmixing_ks_pw(iter, this->p_chgmix, *this->dftu_, *this->inp_); // mohan move harris functional here, 2012-06-05 // use 'rho(in)' and 'v_h and v_xc'(in) @@ -204,7 +206,7 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const // should before lambda loop in DeltaSpin DFTU_BASE::iter_init_dftu_pw(iter, istep, - this->dftu, + *this->dftu_, this->stp.template get_psi_t(), this->pelec->wg, ucell, @@ -214,7 +216,7 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const // mohan add 2025-11: push DFT+U energy from Plus_U instance to ElecState if (this->inp_->dft_plus_u) { - this->pelec->set_dftu_energy(this->dftu.get_energy()); + this->pelec->set_dftu_energy(this->dftu_->get_energy()); } } @@ -383,7 +385,7 @@ void ESolver_KS_PW::cal_force(BaseCell& basecell, ModuleBase::matrix& &ucell.symm, &this->sf, this->solvent, - &this->dftu, + this->dftu_, &this->locpp, &this->ppcell, &this->kv, @@ -405,7 +407,7 @@ void ESolver_KS_PW::cal_stress(BaseCell& basecell, ModuleBase::matrix ss.cal_stress(stress, ucell, this->get_vdw_result(), - this->dftu, + *this->dftu_, this->locpp, this->ppcell, this->pw_rhod, diff --git a/source/source_esolver/lcao_others.cpp b/source/source_esolver/lcao_others.cpp index 9301ecd6fd6..2d6a3e5faf0 100644 --- a/source/source_esolver/lcao_others.cpp +++ b/source/source_esolver/lcao_others.cpp @@ -133,7 +133,7 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) two_center_bundle_, orb_, this->dmat.dm, - &this->dftu, + this->dftu_, this->deepks, istep, this->exx_nao, From ad28192629600bf8138cd48d1a86a567cc1573aa Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 14:37:09 +0800 Subject: [PATCH 26/33] Build: compile module_dftu sources only under ENABLE_LCAO All sources in source_lcao/module_dftu implement the LCAO-specific Plus_U derived class and the DFTU_LCAO operators; the PW DFT+U implementation lives in source_pw/module_pwdft/dftu_base.* and is compiled unconditionally. Move the seven previously-unconditional sources (dftu_nao, dftu_nao_fs_k, dftu_nao_folding, dftu_nao_pots, dftu_nao_occ, dftu_nao_energy, dftu_hamilt) into the existing if(ENABLE_LCAO) block, following the module_rt precedent. Because the dftu OBJECT library now has no sources when LCAO is off, wrap add_library/add_coverage/test in if(ENABLE_LCAO) and move the `dftu` entry in the final link list from the unconditional block into the if(ENABLE_LCAO) block in source/CMakeLists.txt, mirroring how `tddft` is handled. Verification: - LCAO build (build_max_para_test): cmake reconfigure + make -j 30, abacus_max_para links OK. - PW-only build: cmake -DENABLE_LCAO=OFF -DBUILD_TESTING=OFF, make -j 30 abacus_pw_para links OK with no dftu target. --- source/CMakeLists.txt | 2 +- source/source_lcao/module_dftu/CMakeLists.txt | 43 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 4dc0439a69d..ffd4272f71f 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -695,7 +695,6 @@ target_link_libraries( psi_overall_init psi_init psi - dftu deltaspin container device @@ -711,6 +710,7 @@ if(ENABLE_LCAO) PRIVATE hamilt_lcao tddft + dftu orb gint hcontainer diff --git a/source/source_lcao/module_dftu/CMakeLists.txt b/source/source_lcao/module_dftu/CMakeLists.txt index 479cda17c84..d43014ef076 100644 --- a/source/source_lcao/module_dftu/CMakeLists.txt +++ b/source/source_lcao/module_dftu/CMakeLists.txt @@ -1,33 +1,32 @@ -list(APPEND objects - dftu_nao.cpp - dftu_nao_fs_k.cpp - dftu_nao_folding.cpp - dftu_nao_pots.cpp - dftu_nao_occ.cpp - dftu_nao_energy.cpp - dftu_hamilt.cpp -) - +# All sources in this module are LCAO-specific (the Plus_U derived class and +# the DFTU_LCAO operators). The PW DFT+U implementation lives in +# source_pw/module_pwdft/dftu_base.* and is compiled unconditionally there. if(ENABLE_LCAO) list(APPEND objects + dftu_nao.cpp + dftu_nao_fs_k.cpp + dftu_nao_folding.cpp + dftu_nao_pots.cpp + dftu_nao_occ.cpp + dftu_nao_energy.cpp + dftu_hamilt.cpp dftu_nao_op.cpp dftu_nao_fs_r.cpp dftu_nao_for_r.cpp dftu_nao_str_r.cpp dftu_nao_op_legacy.cpp ) -endif() - -add_library( - dftu - OBJECT - ${objects} -) + add_library( + dftu + OBJECT + ${objects} + ) -if(ENABLE_COVERAGE) - add_coverage(dftu) -endif() + if(ENABLE_COVERAGE) + add_coverage(dftu) + endif() -if(BUILD_TESTING) - add_subdirectory(test) + if(BUILD_TESTING) + add_subdirectory(test) + endif() endif() From 75e53096bcf64cad684574ed198dde4697d727a6 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 14:56:17 +0800 Subject: [PATCH 27/33] Refactor: drop now-redundant #ifdef __LCAO in module_dftu sources These seven .cpp files are now compiled only when ENABLE_LCAO is on (see the previous CMakeLists change), so the #ifdef __LCAO guards inside them are always true and can be removed. Only the preprocessor lines are deleted; all function bodies are unchanged, and the pre-existing #ifdef __MPI blocks (ScalapackConnector calls) are kept intact. The header files keep their #ifdef __LCAO guards: dftu_nao.h is still included by PW-compiled code (esolver_ks.h) and must let Plus_U degrade to an empty shell when LCAO is off. Verification: - LCAO build (build_max_para_test): make -j 30 abacus_max_para links OK. - PW-only build (ENABLE_LCAO=OFF): abacus_pw_para links OK. Note: code_quality_score flags dftu_nao_fs_k.cpp (6) and dftu_nao_occ.cpp (49) for pre-existing debt (file length, parameter count, cyclomatic complexity) untouched by this change. --- source/source_lcao/module_dftu/dftu_hamilt.cpp | 4 ---- source/source_lcao/module_dftu/dftu_nao.cpp | 9 --------- source/source_lcao/module_dftu/dftu_nao_energy.cpp | 2 -- source/source_lcao/module_dftu/dftu_nao_folding.cpp | 2 -- source/source_lcao/module_dftu/dftu_nao_fs_k.cpp | 2 -- source/source_lcao/module_dftu/dftu_nao_occ.cpp | 4 ---- source/source_lcao/module_dftu/dftu_nao_pots.cpp | 2 -- 7 files changed, 25 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_hamilt.cpp b/source/source_lcao/module_dftu/dftu_hamilt.cpp index f580f19fe0c..bcec1211ae3 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.cpp +++ b/source/source_lcao/module_dftu/dftu_hamilt.cpp @@ -7,8 +7,6 @@ #include "source_base/tool_title.h" #include "source_basis/module_ao/parallel_orbitals.h" - -#ifdef __LCAO namespace DFTU_LCAO { void pot_uterm_complex(Plus_U_Base& dftu, @@ -195,5 +193,3 @@ void pot_uterm_HR_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const } } // namespace DFTU_LCAO - -#endif diff --git a/source/source_lcao/module_dftu/dftu_nao.cpp b/source/source_lcao/module_dftu/dftu_nao.cpp index 07c21f4843b..a94d6ff8a50 100644 --- a/source/source_lcao/module_dftu/dftu_nao.cpp +++ b/source/source_lcao/module_dftu/dftu_nao.cpp @@ -4,10 +4,8 @@ #include "source_base/tool_title.h" #include "source_base/timer.h" #include "source_basis/module_ao/parallel_orbitals.h" -#ifdef __LCAO #include "source_basis/module_ao/orb_read.h" #include "source_estate/module_dm/density_matrix.h" -#endif #include #include @@ -35,20 +33,16 @@ void Plus_U::init(UnitCell& cell, const double uramping, const int occ_mat_ctrl, const int mixing_dftu -#ifdef __LCAO , const LCAO_Orbitals* orb -#endif ) { ModuleBase::TITLE("Plus_U", "init"); -#ifdef __LCAO ptr_orb_ = orb; if(ptr_orb_ != nullptr) { orb_cutoff_ = orb->cutoffs(); } -#endif if (pv != nullptr) { @@ -84,8 +78,6 @@ void Plus_U::init(UnitCell& cell, // uramping_update() and u_converged() are now implemented in // dftu_base.cpp as Plus_U_Base methods (inherited by Plus_U). -#ifdef __LCAO - void Plus_U::set_dmr(const elecstate::DensityMatrix, double>* dmr) { this->dm_in_dftu_cd = dmr; @@ -114,4 +106,3 @@ const hamilt::HContainer* Plus_U::get_dmr(int ispin) const } } -#endif diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.cpp b/source/source_lcao/module_dftu/dftu_nao_energy.cpp index d3eae444348..91010892f2c 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_energy.cpp @@ -6,7 +6,6 @@ #include "source_cell/unitcell.h" #include "source_io/module_parameter/parameter.h" -#ifdef __LCAO void DFTU_LCAO::cal_energy_correction(Plus_U_Base& dftu, const UnitCell& ucell) { ModuleBase::TITLE("DFTU_LCAO", "cal_energy_correction"); @@ -165,4 +164,3 @@ void DFTU_LCAO::cal_energy_correction(Plus_U_Base& dftu, const UnitCell& ucell) ModuleBase::timer::end("DFTU_LCAO", "cal_energy_correction"); return; } -#endif diff --git a/source/source_lcao/module_dftu/dftu_nao_folding.cpp b/source/source_lcao/module_dftu/dftu_nao_folding.cpp index 71a50fab8ba..ba8173d6b6a 100644 --- a/source/source_lcao/module_dftu/dftu_nao_folding.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_folding.cpp @@ -1,4 +1,3 @@ -#ifdef __LCAO #include "dftu_nao_folding.h" #include "dftu_nao.h" #include "source_base/timer.h" @@ -295,4 +294,3 @@ void folding_matrix_k_new(const std::string& ks_solver, } // namespace DFTU_LCAO -#endif // __LCAO diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp index e76b5585a60..81402a92b85 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.cpp @@ -1,4 +1,3 @@ -#ifdef __LCAO #include "dftu_nao_fs_k.h" #include "dftu_nao_folding.h" #include "dftu_nao.h" @@ -664,4 +663,3 @@ void cal_stress_gamma(const int nlocal, } // namespace DFTU_LCAO -#endif diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.cpp b/source/source_lcao/module_dftu/dftu_nao_occ.cpp index 6f533ad78c8..ca30565e44f 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_occ.cpp @@ -5,15 +5,12 @@ #include "source_base/module_external/scalapack_connector.h" #include "source_estate/occ_matrix.h" #include "source_io/module_parameter/parameter.h" -#ifdef __LCAO #include "source_lcao/hamilt_lcao.h" -#endif // cal_occ_mat_k / cal_occ_mat_gamma take Plus_U_Base& dftu directly and read all // occupation-matrix state (occ/save arrays, lookup table, nspin/npol, and the // occmat_ready flag) from dftu.occmat() and the Plus_U_Base accessors. -#ifdef __LCAO void DFTU_LCAO::cal_occ_mat_k(const Parallel_Orbitals* pv, const int iter, @@ -481,4 +478,3 @@ void cal_occ_mat(const Parallel_Orbitals* pv, } } // namespace DFTU_LCAO -#endif diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.cpp b/source/source_lcao/module_dftu/dftu_nao_pots.cpp index 12a17e87926..9fc01e0f593 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.cpp +++ b/source/source_lcao/module_dftu/dftu_nao_pots.cpp @@ -6,7 +6,6 @@ #include "source_basis/module_ao/parallel_orbitals.h" #include "source_cell/unitcell.h" -#ifdef __LCAO void DFTU_LCAO::pot_onsite_complex(const Plus_U_Base& dftu, const UnitCell& ucell, const Parallel_Orbitals* pv, @@ -241,4 +240,3 @@ double DFTU_LCAO::get_onsite_pot(const Plus_U_Base& dftu, return pot_onsite; } -#endif From 59f729eb3510e6f26fe52fb42cca6a1c197b76e2 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 15:26:17 +0800 Subject: [PATCH 28/33] Refactor: drop redundant #ifdef __LCAO in module_dftu headers These six headers are only included from LCAO-only translation units (verified: no source_pw/ references), and the whole dftu module is now compiled only under ENABLE_LCAO. The __LCAO guard inside them is dead in both build flavors, so remove it; only preprocessor lines are dropped, declarations are unchanged. dftu_nao.h keeps its guards because the PW-shared esolver_ks.h still includes it. Verified: abacus_max_para links (ENABLE_LCAO=ON) and abacus_pw_para links (ENABLE_LCAO=OFF). The unrelated MODULE_IO_numerical_basis_test fails to link under ENABLE_LCAO=OFF because its CMakeLists links numerical_atomic_orbitals/orb outside if(ENABLE_LCAO) -- a pre-existing issue independent of this change. --- source/source_lcao/module_dftu/dftu_hamilt.h | 2 -- source/source_lcao/module_dftu/dftu_nao_energy.h | 2 -- source/source_lcao/module_dftu/dftu_nao_folding.h | 3 --- source/source_lcao/module_dftu/dftu_nao_fs_k.h | 3 --- source/source_lcao/module_dftu/dftu_nao_occ.h | 2 -- source/source_lcao/module_dftu/dftu_nao_pots.h | 2 -- 6 files changed, 14 deletions(-) diff --git a/source/source_lcao/module_dftu/dftu_hamilt.h b/source/source_lcao/module_dftu/dftu_hamilt.h index 9525b9a7b89..0b57cc72e28 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.h +++ b/source/source_lcao/module_dftu/dftu_hamilt.h @@ -8,7 +8,6 @@ class Plus_U_Base; class Parallel_Orbitals; class UnitCell; -#ifdef __LCAO namespace DFTU_LCAO { /// @brief Compute the LCAO-basis U-term effective potential matrix (complex). @@ -54,6 +53,5 @@ void pot_uterm_HR_complex(const Plus_U_Base& dftu, const int npol); } // namespace DFTU_LCAO -#endif #endif diff --git a/source/source_lcao/module_dftu/dftu_nao_energy.h b/source/source_lcao/module_dftu/dftu_nao_energy.h index 4357c3d9dd7..a33095f34ee 100644 --- a/source/source_lcao/module_dftu/dftu_nao_energy.h +++ b/source/source_lcao/module_dftu/dftu_nao_energy.h @@ -4,7 +4,6 @@ class Plus_U_Base; class UnitCell; -#ifdef __LCAO namespace DFTU_LCAO { /** @@ -20,6 +19,5 @@ namespace DFTU_LCAO { void cal_energy_correction(Plus_U_Base& dftu, const UnitCell& ucell); } // namespace DFTU_LCAO -#endif #endif diff --git a/source/source_lcao/module_dftu/dftu_nao_folding.h b/source/source_lcao/module_dftu/dftu_nao_folding.h index da3d2995a84..e566f7184d6 100644 --- a/source/source_lcao/module_dftu/dftu_nao_folding.h +++ b/source/source_lcao/module_dftu/dftu_nao_folding.h @@ -17,7 +17,6 @@ #include #include -#ifdef __LCAO namespace DFTU_LCAO { @@ -87,6 +86,4 @@ void folding_matrix_k_new(const std::string& ks_solver, } // namespace DFTU_LCAO -#endif // __LCAO - #endif // DFTU_FOLDING_H diff --git a/source/source_lcao/module_dftu/dftu_nao_fs_k.h b/source/source_lcao/module_dftu/dftu_nao_fs_k.h index c381969c314..ad38a9800a2 100644 --- a/source/source_lcao/module_dftu/dftu_nao_fs_k.h +++ b/source/source_lcao/module_dftu/dftu_nao_fs_k.h @@ -13,7 +13,6 @@ #include #include -#ifdef __LCAO class Plus_U_Base; @@ -98,6 +97,4 @@ void cal_stress_gamma(int nlocal, } // namespace DFTU_LCAO -#endif // __LCAO - #endif // DFTU_FORCE_H diff --git a/source/source_lcao/module_dftu/dftu_nao_occ.h b/source/source_lcao/module_dftu/dftu_nao_occ.h index bb026d29892..6199d9bf876 100644 --- a/source/source_lcao/module_dftu/dftu_nao_occ.h +++ b/source/source_lcao/module_dftu/dftu_nao_occ.h @@ -13,7 +13,6 @@ class Plus_U_Base; -#ifdef __LCAO namespace DFTU_LCAO { /// @brief Compute the occupation matrix and delegate to Plus_U member. @@ -55,6 +54,5 @@ void cal_occ_mat_gamma(const Parallel_Orbitals* pv, Plus_U_Base& dftu); } // namespace DFTU_LCAO -#endif #endif diff --git a/source/source_lcao/module_dftu/dftu_nao_pots.h b/source/source_lcao/module_dftu/dftu_nao_pots.h index ee72e36868a..62b7a897efb 100644 --- a/source/source_lcao/module_dftu/dftu_nao_pots.h +++ b/source/source_lcao/module_dftu/dftu_nao_pots.h @@ -7,7 +7,6 @@ class Plus_U_Base; class UnitCell; class Parallel_Orbitals; -#ifdef __LCAO namespace DFTU_LCAO { /** @@ -73,6 +72,5 @@ void pot_onsite_real(const Plus_U_Base& dftu, const int npol); } // namespace DFTU_LCAO -#endif #endif From 7f36438420ef29fe28239a1ea396bc8148072c1f Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 15:34:39 +0800 Subject: [PATCH 29/33] Build: guard MODULE_IO_numerical_basis_test behind ENABLE_LCAO This test links the LCAO-only libraries numerical_atomic_orbitals and orb and compiles source_lcao/center2orb.cpp, so it cannot build under ENABLE_LCAO=OFF. Wrap its AddTest in if(ENABLE_LCAO), matching the neighboring MODULE_IO_to_qo_test. Verified: ENABLE_LCAO=OFF full build completes (abacus_pw_para links) and the test still builds under ENABLE_LCAO=ON. --- source/source_io/test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/source_io/test/CMakeLists.txt b/source/source_io/test/CMakeLists.txt index 309aba37986..fb4b8f37fc2 100644 --- a/source/source_io/test/CMakeLists.txt +++ b/source/source_io/test/CMakeLists.txt @@ -180,6 +180,7 @@ add_test(NAME MODULE_IO_read_wf2rho_pw_parallel ) +if(ENABLE_LCAO) AddTest( TARGET MODULE_IO_numerical_basis_test LIBS parameter base device numerical_atomic_orbitals container orb @@ -187,6 +188,7 @@ AddTest( ../module_bessel/numerical_basis_jyjy.cpp ../../source_lcao/center2orb.cpp ) +endif() AddTest( From 41493eeea459320ff4ee5bf2eb602f0b2d2aa93c Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Mon, 7 Sep 2026 17:23:41 +0800 Subject: [PATCH 30/33] fix(dftu): restore INPUT parameter name orbital_corr and fix LCAO dftu_ null pointer The rename commit eabfabcc0 changed the INPUT parameter from orbital_corr to l_channel, but test cases (scf_u_spin2, scf_u_spin2_old, scf_u_yukawa) still use the old name. Restore the INPUT parameter name to orbital_corr while keeping the internal C++ member variable as l_channel. Additionally, the refactor to base-class pointer (156a5d8d5) left ESolver_KS_LCAO without initializing dftu_ (unlike PW path which news Plus_U_Base), causing a segfault on DFT+U LCAO calculations. Add the missing allocation in the ESolver_KS_LCAO constructor. Verified: scf_u_spin2 passes with exit code 0, SCF converges, final energy -11033.13 eV. --- docs/parameters.yaml | 2 +- source/source_esolver/esolver_ks_lcao.cpp | 1 + source/source_io/module_parameter/read_inp_exx_dftu.cpp | 6 +++--- source/source_io/test_serial/read_input_item_test.cpp | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 8f3c5e7f2be..4c097ada35e 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -4677,7 +4677,7 @@ parameters: default_value: "False" unit: "" availability: basis_type==lcao - - name: l_channel + - name: orbital_corr category: DFT+U correction type: Vector of Integer (n values where n is the number of atomic types) description: | diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index c9d8a424405..eedbd25ac74 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -36,6 +36,7 @@ ESolver_KS_LCAO::ESolver_KS_LCAO() { this->classname = "ESolver_KS_LCAO"; this->basisname = "LCAO"; + this->dftu_ = new Plus_U(); } template diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 29e67de771d..a0f6e728604 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -651,7 +651,7 @@ void ReadInput::item_dftu() this->add_item(item); } { - Input_Item item("l_channel"); + Input_Item item("orbital_corr"); item.annotation = "which correlated orbitals need corrected ; d:2 " ",f:3, do not need correction:-1"; item.category = "DFT+U correction"; @@ -679,14 +679,14 @@ void ReadInput::item_dftu() if (para.input.l_channel.size() != para.input.ntype) { ModuleBase::WARNING_QUIT("ReadInput", - "l_channel should have the same " + "orbital_corr should have the same " "number of elements as ntype"); } for (auto& val: para.input.l_channel) { if (val < -1 || val > 3) { - ModuleBase::WARNING_QUIT("ReadInput", "WRONG ARGUMENTS OF l_channel"); + ModuleBase::WARNING_QUIT("ReadInput", "WRONG ARGUMENTS OF orbital_corr"); } } }; diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 48ff0b6330f..3f4d6b8f567 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -1819,8 +1819,8 @@ TEST_F(InputTest, Item_test2) output = testing::internal::GetCapturedStdout(); EXPECT_THAT(output, testing::HasSubstr("NOTICE")); } - { // l_channel - auto it = find_label("l_channel", readinput.input_lists); + { // orbital_corr + auto it = find_label("orbital_corr", readinput.input_lists); param.input.ntype = 2; it->second.str_values = {"1", "2"}; param.input.l_channel = {1, 2}; From 12fff4c00f9cf4a78bbb6671028a46f23dff2aa2 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 8 Sep 2026 16:32:10 +0800 Subject: [PATCH 31/33] fix(esolver): manage dftu_ via std::unique_ptr to prevent memory leak ESolver_KS::dftu_ was allocated with new in both ESolver_KS_PW and ESolver_KS_LCAO constructors but never deleted in ~ESolver_KS, contradicting the member comment and commit 156a5d8. Convert dftu_ to std::unique_ptr so ownership is explicit and the object is released automatically on destruction. Call sites that pass raw pointers to downstream functions use .get(); C++11 baseline requires reset(new ...) instead of std::make_unique. --- source/source_esolver/esolver_dfpt_pw.cpp | 2 +- source/source_esolver/esolver_double_xc.cpp | 2 +- source/source_esolver/esolver_ks.h | 6 +++--- source/source_esolver/esolver_ks_lcao.cpp | 6 +++--- source/source_esolver/esolver_ks_pw.cpp | 6 +++--- source/source_esolver/lcao_others.cpp | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/source_esolver/esolver_dfpt_pw.cpp b/source/source_esolver/esolver_dfpt_pw.cpp index 9da0be98029..e125b1d431c 100644 --- a/source/source_esolver/esolver_dfpt_pw.cpp +++ b/source/source_esolver/esolver_dfpt_pw.cpp @@ -354,7 +354,7 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) dfpt_->init(ucell, *this->stp.psi_cpu, this->pw_rho, this->pw_wfc, &this->sf, veff_r, this->pelec->wg, this->pelec->ekb, xc_adapter_, nelec_, ecutwfc_, - dft_plus_u_ ? this->dftu_ : nullptr); + dft_plus_u_ ? this->dftu_.get() : nullptr); } void ESolver_DFPT_PW::run_post_process(UnitCell& ucell) diff --git a/source/source_esolver/esolver_double_xc.cpp b/source/source_esolver/esolver_double_xc.cpp index a787bc96c20..4e3a6f136de 100644 --- a/source/source_esolver/esolver_double_xc.cpp +++ b/source/source_esolver/esolver_double_xc.cpp @@ -148,7 +148,7 @@ void ESolver_DoubleXC::before_scf(UnitCell& ucell, const int istep) this->two_center_bundle_, this->orb_, this->dmat_base.dm, - this->dftu_, + this->dftu_.get(), this->deepks, istep, this->exx_nao, diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index a27e189715a..a06a5de656b 100644 --- a/source/source_esolver/esolver_ks.h +++ b/source/source_esolver/esolver_ks.h @@ -60,9 +60,9 @@ class ESolver_KS : public ESolver_FP //! nonlocal pseudopotentials pseudopot_cell_vnl ppcell; - //! DFT+U method (base-class pointer; PW news Plus_U_Base, LCAO news Plus_U), - //! allocated in the derived-class constructor, deleted in ~ESolver_KS. - Plus_U_Base* dftu_ = nullptr; + //! DFT+U method (base-class pointer; PW news Plus_U_Base, LCAO news Plus_U). + //! Owned by ESolver_KS via unique_ptr; released automatically in ~ESolver_KS. + std::unique_ptr dftu_; std::string basisname; //! esolver_ks_lcao.cpp double esolver_KS_ne = 0.0; //! number of electrons diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index eedbd25ac74..ce9072024e7 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -36,7 +36,7 @@ ESolver_KS_LCAO::ESolver_KS_LCAO() { this->classname = "ESolver_KS_LCAO"; this->basisname = "LCAO"; - this->dftu_ = new Plus_U(); + this->dftu_.reset(new Plus_U()); } template @@ -158,7 +158,7 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep) { this->p_hamilt = new hamilt::HamiltLCAO( ucell, this->gd, &this->pv, this->pelec->pot, this->kv, - two_center_bundle_, orb_, this->dmat.dm, this->dftu_, this->deepks, istep, exx_nao, this->exx_info_); + two_center_bundle_, orb_, this->dmat.dm, this->dftu_.get(), this->deepks, istep, exx_nao, this->exx_info_); } // 9) for each ionic step, the overlap must be rebuilt @@ -510,7 +510,7 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& const std::vector>& dm_vec = this->dmat.dm->get_DMK_vector(); // 1) calculate the local occupation number matrix and energy correction in DFT+U - finish_dftu_lcao(iter, conv_esolver, this->inp_->dft_plus_u, this->inp_->out_chg[0], this->dftu_, ucell, dm_vec, this->kv, this->p_chgmix->get_mixing_beta(), hamilt_lcao, PARAM.globalv.global_out_dir, this->inp_->nspin, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); + finish_dftu_lcao(iter, conv_esolver, this->inp_->dft_plus_u, this->inp_->out_chg[0], this->dftu_.get(), ucell, dm_vec, this->kv, this->p_chgmix->get_mixing_beta(), hamilt_lcao, PARAM.globalv.global_out_dir, this->inp_->nspin, PARAM.globalv.npol, PARAM.globalv.gamma_only_local); // mohan add 2025-11: push DFT+U energy from Plus_U instance to ElecState. // Covers both dft_plus_u==1 (new method, energy accumulated by DFTU::contributeHR diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 82070c95e71..c2c9d14177d 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -33,7 +33,7 @@ ESolver_KS_PW::ESolver_KS_PW() this->classname = "ESolver_KS_PW"; this->basisname = "PW"; // PW basis: the DFT+U object is the base class (no LCAO orbitals). - this->dftu_ = new Plus_U_Base(); + this->dftu_.reset(new Plus_U_Base()); } template @@ -67,7 +67,7 @@ void ESolver_KS_PW::allocate_hamilt(const UnitCell& ucell) this->pw_wfc, &this->kv, &this->ppcell, - this->dftu_, + this->dftu_.get(), &ucell, &this->general_exx_info_); } @@ -385,7 +385,7 @@ void ESolver_KS_PW::cal_force(BaseCell& basecell, ModuleBase::matrix& &ucell.symm, &this->sf, this->solvent, - this->dftu_, + this->dftu_.get(), &this->locpp, &this->ppcell, &this->kv, diff --git a/source/source_esolver/lcao_others.cpp b/source/source_esolver/lcao_others.cpp index 2d6a3e5faf0..34b7ce823e0 100644 --- a/source/source_esolver/lcao_others.cpp +++ b/source/source_esolver/lcao_others.cpp @@ -133,7 +133,7 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) two_center_bundle_, orb_, this->dmat.dm, - this->dftu_, + this->dftu_.get(), this->deepks, istep, this->exx_nao, From e22c1b1ed63357f44d8e56eaeb9017b9f42c3221 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Tue, 8 Sep 2026 16:45:46 +0800 Subject: [PATCH 32/33] fix(esolver): add .get() for unique_ptr dftu_ in init_dftu_lcao call Merge from develop reverted the raw pointer back to unique_ptr member in init_dftu_lcao call site, causing compile error on void* parameter. --- source/source_esolver/esolver_ks_lcao.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index 4b335585e7e..84b209743f7 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -389,7 +389,7 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const } #endif - init_dftu_lcao(istep, iter, this->inp_->dft_plus_u, this->dftu_, this->dmat.dm, ucell, this->chr.rho, this->pw_rho->nrxx); + init_dftu_lcao(istep, iter, this->inp_->dft_plus_u, this->dftu_.get(), this->dmat.dm, ucell, this->chr.rho, this->pw_rho->nrxx); #ifdef __MLALGO // the density matrixes of DeePKS have been updated in each iter From 6e1cadb71d2da66ada3eb59b47c7a93d4fccb802 Mon Sep 17 00:00:00 2001 From: abacus_fixer Date: Wed, 9 Sep 2026 16:18:44 +0800 Subject: [PATCH 33/33] fix --- source/source_esolver/esolver_ks.cpp | 2 +- source/source_esolver/esolver_ks.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/source_esolver/esolver_ks.cpp b/source/source_esolver/esolver_ks.cpp index 79534ec3acc..65bcd52665f 100644 --- a/source/source_esolver/esolver_ks.cpp +++ b/source/source_esolver/esolver_ks.cpp @@ -13,7 +13,7 @@ #include "source_hamilt/module_xc/xc_functional.h" #include "source_io/module_output/output_log.h" // use write_head #include "source_estate/elecstate_print.h" // print_etot -#include "source_lcao/module_dftu/dftu_nao.h" // mohan add 2025-11-07 +#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base::u_converged in iter_finish #include "source_hamilt/module_xc/general_exx_info.h" // for init_general_exx_info namespace ModuleESolver diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index a06a5de656b..eb9f76ce4b5 100644 --- a/source/source_esolver/esolver_ks.h +++ b/source/source_esolver/esolver_ks.h @@ -8,9 +8,11 @@ #include "source_hamilt/hamilt.h" // use Hamiltonian #include "source_hamilt/hamilt_base.h" // use Hamiltonian base class #include "source_hamilt/module_xc/general_exx_info.h" // ESolver owns General_Exx_Info value -#include "source_lcao/module_dftu/dftu_nao.h" // mohan add 20251107 +#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base for dftu_ member #include "source_pw/module_pwdft/vnl_pw.h" +#include // std::unique_ptr for dftu_ member + namespace ModuleESolver {