diff --git a/source/Makefile.Objects b/source/Makefile.Objects index 2928e5935b..1d196dc8b5 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -742,7 +742,8 @@ OBJS_SRCPW=h_ewald_pw.o\ update_cell_pw.o\ dftu_base.o\ dftu_output.o\ - dftu_pw.o\ + dftu_tools_pw.o\ + dftu_cal_occ_pw.o\ setup_dftu_pw.o\ deltaspin_pw.o\ force_pw.o\ diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index 83612f5d26..c91b9380a2 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -510,7 +510,7 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& // 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_v_of_u) and dft_plus_u==2 (old method, energy from cal_energy_correction). + // 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()); diff --git a/source/source_estate/module_charge/charge_mixing.cpp b/source/source_estate/module_charge/charge_mixing.cpp index 1324975ec5..32c7b4f87e 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 - // (eff_pot_pw.size() = pot_index * 2 for nspin=2) + // (pot_uterm_pw.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/module_charge/chgmixing.cpp b/source/source_estate/module_charge/chgmixing.cpp index b15f28a8d7..617579c4c1 100644 --- a/source/source_estate/module_charge/chgmixing.cpp +++ b/source/source_estate/module_charge/chgmixing.cpp @@ -133,7 +133,7 @@ void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number // enable mixing_dftu for DFT+U occupation mixing dftu.enable_mixing(); // allocate memory for uom_mdata - p_chgmix->allocate_mixing_uom(dftu.get_size_eff_pot_pw()); + p_chgmix->allocate_mixing_uom(dftu.get_size_pot_uterm_pw()); } } @@ -145,11 +145,11 @@ void module_charge::chgmixing_ks_pw(const int iter, // scf iteration number if (inp.dft_plus_u) { - if (dftu.uramping > 0.01 && !dftu.u_converged()) + if (dftu.get_uramping() > 0.01 && !dftu.u_converged()) { p_chgmix->mixing_restart_step = inp.scf_nmax + 1; } - if (dftu.uramping > 0.01) + if (dftu.get_uramping() > 0.01) { bool do_uramping = true; if (inp.sc_mag_switch) @@ -197,7 +197,7 @@ void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number dftu.enable_mixing(); } // this output will be removed once the feeature is stable - if (dftu.uramping > 0.01) + if (dftu.get_uramping() > 0.01) { std::cout << " U-Ramping! Current U = "; for (int i = 0; i < dftu.get_num_u_types(); i++) @@ -216,7 +216,7 @@ void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number if (inp.dft_plus_u) { dftu.uramping_update(); // update U by uramping if uramping > 0.01 - if (dftu.uramping > 0.01) + if (dftu.get_uramping() > 0.01) { std::cout << " U-Ramping! Current U = "; for (int i = 0; i < dftu.get_num_u_types(); i++) @@ -225,7 +225,7 @@ void module_charge::chgmixing_ks_lcao(const int iter, // scf iteration number } std::cout << " eV " << std::endl; } - if (dftu.uramping > 0.01 && !dftu.u_converged()) + if (dftu.get_uramping() > 0.01 && !dftu.u_converged()) { p_chgmix->mixing_restart_step = inp.scf_nmax + 1; } diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index c5890b4dc3..96189eadf9 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -112,7 +112,7 @@ struct Input_para double mixing_gg0_min = 0.1; double mixing_angle = -10.0; bool mixing_tau = false; ///< whether to mix tau in mgga - bool mixing_dftu = false; ///< whether to mix locale in DFT+U + bool mixing_dftu = false; ///< whether to mix occ_mat in DFT+U bool mixing_dmr = false; ///< whether to mix real space density matrix bool gamma_only = false; ///< for plane wave. diff --git a/source/source_io/module_parameter/read_inp_estruc.cpp b/source/source_io/module_parameter/read_inp_estruc.cpp index 463ea6e47f..ff6a5a7b57 100644 --- a/source/source_io/module_parameter/read_inp_estruc.cpp +++ b/source/source_io/module_parameter/read_inp_estruc.cpp @@ -757,7 +757,7 @@ This setting takes effect only when the selected exchange-correlation functional } { Input_Item item("mixing_dftu"); - item.annotation = "whether to mix locale in DFT+U calculation"; + item.annotation = "whether to mix occ_mat in DFT+U calculation"; item.category = "Electronic structure"; item.type = "Boolean"; item.description = R"(Whether to mix the occupation matrices. diff --git a/source/source_lcao/force_stress_lcao.cpp b/source/source_lcao/force_stress_lcao.cpp index ae5635f5ce..fd9f701ec7 100644 --- a/source/source_lcao/force_stress_lcao.cpp +++ b/source/source_lcao/force_stress_lcao.cpp @@ -2,6 +2,7 @@ #include "source_base/parallel_reduce.h" #include "source_lcao/module_dftu/dftu_lcao.h" //Quxin add for DFT+U on 20201029 +#include "source_lcao/module_dftu/dftu_force.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" // new @@ -456,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.force_stress(ucell, gd, dmk_d, dmk_c, pv, fsr_dftu, force_u, stress_u, kv, PARAM.globalv.npol); + DFTU_LCAO::force_stress(dftu, ucell, gd, dmk_d, dmk_c, pv, fsr_dftu, force_u, stress_u, kv, PARAM.globalv.npol); } else { diff --git a/source/source_lcao/module_dftu/dftu_folding.cpp b/source/source_lcao/module_dftu/dftu_folding.cpp index 4958f9ad59..fc09e23ae8 100644 --- a/source/source_lcao/module_dftu/dftu_folding.cpp +++ b/source/source_lcao/module_dftu/dftu_folding.cpp @@ -1,44 +1,92 @@ #ifdef __LCAO +#include "dftu_folding.h" #include "dftu_lcao.h" #include "source_base/timer.h" -#include "source_io/module_parameter/parameter.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" #include "source_lcao/hamilt_lcao.h" -#include "source_hamilt/module_hcontainer/hcontainer.h" -#include "source_hamilt/module_hcontainer/hcontainer_funcs.h" - -void Plus_U::fold_dSR_gamma(const UnitCell& ucell, - const Parallel_Orbitals& pv, - const Grid_Driver* gd, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - double* dh_r, - const int dim1, - const int dim2, - double* dSR_gamma) + +namespace DFTU_LCAO { + +bool is_adjacent_pair(const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + const int T1, + const int T2, + const ModuleBase::Vector3& tau1, + const ModuleBase::Vector3& tau2) +{ + const ModuleBase::Vector3 dtau = tau2 - tau1; + const double distance = dtau.norm() * ucell.lat0; + const double rcut = orb_cutoff[T1] + orb_cutoff[T2]; + if (distance < rcut) + { + return true; + } + // Three-body bridging: pair is not directly adjacent but shares a + // common nonlocal projector center T0 that overlaps both orbitals. + for (int ad0 = 0; ad0 < gd.getAdjacentNum() + 1; ++ad0) + { + const int T0 = gd.getType(ad0); + const int I0 = gd.getNatom(ad0); + const ModuleBase::Vector3 tau0 = gd.getAdjacentTau(ad0); + const double distance1 = (tau0 - tau1).norm() * ucell.lat0; + const double distance2 = (tau0 - tau2).norm() * ucell.lat0; + const double rcut1 = orb_cutoff[T1] + ucell.infoNL->get_rcut_max(T0); + const double rcut2 = orb_cutoff[T2] + ucell.infoNL->get_rcut_max(T0); + if (distance1 < rcut1 && distance2 < rcut2) + { + return true; + } + } + return false; +} + +int get_linear_index(const std::string& ks_solver, + const int mu, + const int nu, + const Parallel_Orbitals& pv) +{ + if (ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(ks_solver)) + { + return mu + nu * pv.nrow; + } + return mu * pv.ncol + nu; +} + +void fold_dSR_gamma(int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const Grid_Driver* gd, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + double* dh_r, + const int dim1, + const int dim2, + double* dSR_gamma) { ModuleBase::TITLE("Plus_U", "fold_dSR_gamma"); ModuleBase::GlobalFunc::ZEROS(dSR_gamma, pv.nloc); double* dS_ptr = nullptr; - if(dim1 == 0) - { - dS_ptr = dsloc_x; - } - else if(dim1 == 1) - { - dS_ptr = dsloc_y; - } - else if (dim1 == 2) - { - dS_ptr = dsloc_z; - } + if (dim1 == 0) + { + dS_ptr = dsloc_x; + } + else if (dim1 == 1) + { + dS_ptr = dsloc_y; + } + else if (dim1 == 2) + { + dS_ptr = dsloc_z; + } int nnr = 0; - ModuleBase::Vector3 tau1, tau2, dtau; - ModuleBase::Vector3 dtau1, dtau2, tau0; + ModuleBase::Vector3 tau1, tau2; for (int T1 = 0; T1 < ucell.ntype; ++T1) { @@ -52,68 +100,41 @@ void Plus_U::fold_dSR_gamma(const UnitCell& ucell, { const int T2 = gd->getType(ad); const int I2 = gd->getNatom(ad); - const int start2 = ucell.itiaiw2iwt(T2, I2, 0); Atom* atom2 = &ucell.atoms[T2]; tau2 = gd->getAdjacentTau(ad); - dtau = tau2 - tau1; - double distance = dtau.norm() * ucell.lat0; - double rcut = orb_cutoff_[T1] + orb_cutoff_[T2]; - bool adj = false; - if (distance < rcut) - { - adj = true; - } - else if (distance >= rcut) + + if (!is_adjacent_pair(orb_cutoff, ucell, *gd, T1, T2, tau1, tau2)) { - for (int ad0 = 0; ad0 < gd->getAdjacentNum() + 1; ++ad0) - { - const int T0 = gd->getType(ad0); - const int I0 = gd->getNatom(ad0); - const int iat0 = ucell.itia2iat(T0, I0); - const int start0 = ucell.itiaiw2iwt(T0, I0, 0); - tau0 = gd->getAdjacentTau(ad0); - dtau1 = tau0 - tau1; - dtau2 = tau0 - tau2; - double distance1 = dtau1.norm() * ucell.lat0; - double distance2 = dtau2.norm() * ucell.lat0; - double rcut1 = orb_cutoff_[T1] + ucell.infoNL->get_rcut_max(T0); - double rcut2 = orb_cutoff_[T2] + ucell.infoNL->get_rcut_max(T0); - if (distance1 < rcut1 && distance2 < rcut2) - { - adj = true; - break; - } - } + continue; } - if (adj) + const int start2 = ucell.itiaiw2iwt(T2, I2, 0); + for (int jj = 0; jj < atom1->nw * npol; ++jj) { - for (int jj = 0; jj < atom1->nw * this->npol; ++jj) + const int jj0 = jj / npol; + const int iw1_all = start1 + jj0; + const int mu = pv.global2local_row(iw1_all); + if (mu < 0) { - const int jj0 = jj / this->npol; - const int iw1_all = start1 + jj0; - const int mu = pv.global2local_row(iw1_all); - if (mu < 0) - { - continue; - } - - for (int kk = 0; kk < atom2->nw * this->npol; ++kk) + continue; + } + + for (int kk = 0; kk < atom2->nw * npol; ++kk) + { + const int kk0 = kk / npol; + const int iw2_all = start2 + kk0; + const int nu = pv.global2local_col(iw2_all); + if (nu < 0) { - const int kk0 = kk / this->npol; - const int iw2_all = start2 + kk0; - const int nu = pv.global2local_col(iw2_all); - if (nu < 0) - { - continue; - } - - dSR_gamma[nu * pv.nrow + mu] += dS_ptr[nnr] * dh_r[nnr * 3 + dim2]; - - ++nnr; - } // kk - } // jj - } // adj + continue; + } + + const int iic = get_linear_index(ks_solver, mu, nu, pv); + dSR_gamma[iic] += dS_ptr[nnr] * dh_r[nnr * 3 + dim2]; + + ++nnr; + } // kk + } // jj } // ad } // I1 } // T1 @@ -121,15 +142,18 @@ void Plus_U::fold_dSR_gamma(const UnitCell& ucell, return; } -void Plus_U::folding_matrix_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const int dim1, - const int dim2, - std::complex* mat_k, - const ModuleBase::Vector3& kvec_d) +void folding_matrix_k(int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + const int ik, + const int dim1, + const int dim2, + std::complex* mat_k, + const ModuleBase::Vector3& kvec_d) { ModuleBase::TITLE("Plus_U", "folding_matrix_k"); ModuleBase::timer::start("Plus_U", "folding_matrix_k"); @@ -150,14 +174,9 @@ void Plus_U::folding_matrix_k(const UnitCell& ucell, } int nnr = 0; - ModuleBase::Vector3 dtau; ModuleBase::Vector3 tau1; ModuleBase::Vector3 tau2; - ModuleBase::Vector3 dtau1; - ModuleBase::Vector3 dtau2; - ModuleBase::Vector3 tau0; - for (int T1 = 0; T1 < ucell.ntype; ++T1) { Atom* atom1 = &ucell.atoms[T1]; @@ -165,7 +184,6 @@ void Plus_U::folding_matrix_k(const UnitCell& ucell, { tau1 = atom1->tau[I1]; gd.Find_atom(ucell, tau1, T1, I1); - Atom* atom1 = &ucell.atoms[T1]; const int start1 = ucell.itiaiw2iwt(T1, I1, 0); // (2) search among all adjacent atoms. @@ -176,100 +194,59 @@ void Plus_U::folding_matrix_k(const UnitCell& ucell, Atom* atom2 = &ucell.atoms[T2]; tau2 = gd.getAdjacentTau(ad); - dtau = tau2 - tau1; - double distance = dtau.norm() * ucell.lat0; - double rcut = orb_cutoff_[T1] + orb_cutoff_[T2]; - - bool adj = false; - if (distance < rcut) + if (!is_adjacent_pair(orb_cutoff, ucell, gd, T1, T2, tau1, tau2)) { - adj = true; + continue; } - else if (distance >= rcut) + + // (3) calculate the nu of atom (T2, I2) + const int start2 = ucell.itiaiw2iwt(T2, I2, 0); + //------------------------------------------------ + // exp(k dot dR) + // dR is the index of box in Crystal coordinates + //------------------------------------------------ + ModuleBase::Vector3 dR(gd.getBox(ad).x, gd.getBox(ad).y, gd.getBox(ad).z); + const double arg = (kvec_d * dR) * ModuleBase::TWO_PI; + const std::complex kphase = std::complex(cos(arg), sin(arg)); + + //-------------------------------------------------- + // calculate how many matrix elements are in + // this processor. + //-------------------------------------------------- + for (int ii = 0; ii < atom1->nw * npol; ii++) { - for (int ad0 = 0; ad0 < gd.getAdjacentNum() + 1; ++ad0) + // the index of orbitals in this processor + const int iw1_all = start1 + ii; + const int mu = pv.global2local_row(iw1_all); + if (mu < 0) { - const int T0 = gd.getType(ad0); - const int I0 = gd.getNatom(ad0); - - tau0 = gd.getAdjacentTau(ad0); - dtau1 = tau0 - tau1; - dtau2 = tau0 - tau2; + continue; + } - double distance1 = dtau1.norm() * ucell.lat0; - double distance2 = dtau2.norm() * ucell.lat0; + for (int jj = 0; jj < atom2->nw * npol; jj++) + { + int iw2_all = start2 + jj; + const int nu = pv.global2local_col(iw2_all); + if (nu < 0) + { + continue; + } - double rcut1 = orb_cutoff_[T1] + ucell.infoNL->get_rcut_max(T0); - double rcut2 = orb_cutoff_[T2] + ucell.infoNL->get_rcut_max(T0); + const int iic = get_linear_index(ks_solver, mu, nu, pv); - if (distance1 < rcut1 && distance2 < rcut2) + if (dim1 <= 3) { - adj = true; - break; + mat_k[iic] += mat_ptr[nnr] * kphase; } - } - } - - if (adj) - { - // (3) calculate the nu of atom (T2, I2) - const int start2 = ucell.itiaiw2iwt(T2, I2, 0); - //------------------------------------------------ - // exp(k dot dR) - // dR is the index of box in Crystal coordinates - //------------------------------------------------ - ModuleBase::Vector3 dR(gd.getBox(ad).x, gd.getBox(ad).y, gd.getBox(ad).z); - const double arg = (kvec_d * dR) * ModuleBase::TWO_PI; - const std::complex kphase = std::complex(cos(arg), sin(arg)); - - //-------------------------------------------------- - // calculate how many matrix elements are in - // this processor. - //-------------------------------------------------- - for (int ii = 0; ii < atom1->nw * this->npol; ii++) - { - // the index of orbitals in this processor - const int iw1_all = start1 + ii; - const int mu = pv.global2local_row(iw1_all); - if (mu < 0) - { - continue; - } - - for (int jj = 0; jj < atom2->nw * this->npol; jj++) + else { - int iw2_all = start2 + jj; - const int nu = pv.global2local_col(iw2_all); - if (nu < 0) - { - continue; - } - - int iic = 0; - if (ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(this->ks_solver)) - { - iic = mu + nu * pv.nrow; - } - else - { - iic = mu * pv.ncol + nu; - } - - if (dim1 <= 3) - { - mat_k[iic] += mat_ptr[nnr] * kphase; - } - else - { - mat_k[iic] += mat_ptr[nnr] * fsr.DH_r[nnr * 3 + dim2] * kphase; - } - - ++nnr; - } // kk - } // jj - } // adj + mat_k[iic] += mat_ptr[nnr] * fsr.DH_r[nnr * 3 + dim2] * kphase; + } + ++nnr; + } // jj + } // ii } // ad } // I1 } // T1 @@ -278,27 +255,30 @@ void Plus_U::folding_matrix_k(const UnitCell& ucell, return; } -void Plus_U::folding_matrix_k_new(const int ik, - hamilt::Hamilt>* p_ham) +void folding_matrix_k_new(const std::string& ks_solver, + bool gamma_only_local, + int nspin, + const int ik, + hamilt::Hamilt>* p_ham) { ModuleBase::TITLE("Plus_U", "folding_matrix_k_new"); ModuleBase::timer::start("Plus_U", "folding_matrix_k_new"); int hk_type = 0; - if (ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(this->ks_solver)) + if (ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(ks_solver)) { hk_type = 1; } // get SR and fold to mat_k - if(this->gamma_only_local) + if (gamma_only_local) { dynamic_cast*>(p_ham) ->updateSk(ik, hk_type); } else { - if(this->nspin != 4) + if (nspin != 4) { dynamic_cast, double>*>(p_ham) ->updateSk(ik, hk_type); @@ -313,4 +293,6 @@ void Plus_U::folding_matrix_k_new(const int ik, ModuleBase::timer::end("Plus_U", "folding_matrix_k_new"); } +} // namespace DFTU_LCAO + #endif // __LCAO diff --git a/source/source_lcao/module_dftu/dftu_folding.h b/source/source_lcao/module_dftu/dftu_folding.h new file mode 100644 index 0000000000..da3d2995a8 --- /dev/null +++ b/source/source_lcao/module_dftu/dftu_folding.h @@ -0,0 +1,92 @@ +/// @file dftu_folding.h +/// @brief Free-function helpers for folding S/dS matrices, extracted from +/// Plus_U. Each function takes the data it needs (orb_cutoff, +/// ks_solver, npol, gamma_only_local, nspin) as direct parameters; +/// no Plus_U reference is required, so the helpers are fully decoupled +/// from the class and unit-testable. +#ifndef DFTU_FOLDING_H +#define DFTU_FOLDING_H + +#include "source_basis/module_ao/parallel_orbitals.h" +#include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_cell/unitcell.h" +#include "source_lcao/force_stress_arrays.h" +#include "source_hamilt/hamilt.h" + +#include +#include +#include + +#ifdef __LCAO + +namespace DFTU_LCAO { + +/// @brief Judge whether atom pair (T1,I1) and (T2,I2,tau2) are adjacent +/// by direct orbital cutoff overlap or three-body bridging via a +/// common nonlocal projector center T0. +/// @param orb_cutoff orbital cutoff radii per atom type +/// @return true if the pair should be processed +bool is_adjacent_pair(const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + int T1, + int T2, + const ModuleBase::Vector3& tau1, + const ModuleBase::Vector3& tau2); + +/// @brief Get the linear index of local matrix element (mu, nu) based on +/// ks_solver (column-major or row-major). +int get_linear_index(const std::string& ks_solver, + int mu, + int nu, + const Parallel_Orbitals& pv); + +/// @brief Fold the dSR matrix for gamma-only calculations. +/// npol is the spin-polarization factor; orb_cutoff and ks_solver +/// are forwarded to is_adjacent_pair and get_linear_index. +void fold_dSR_gamma(int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const Grid_Driver* gd, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + double* dh_r, + int dim1, + int dim2, + double* dSR_gamma); + +// dim1 = 0 : S, for Hamiltonian +// dim1 = 1-3 : dS, for force +// dim1 = 4-6 : dS * dR, for stress +void folding_matrix_k(int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + int ik, + int dim1, + int dim2, + std::complex* mat_k, + const ModuleBase::Vector3& kvec_d); + +/** + * @brief new function of folding_S_matrix + * only for Hamiltonian now, for force and stress will be developed later + * use HContainer as input and output in mat_k +*/ +void folding_matrix_k_new(const std::string& ks_solver, + bool gamma_only_local, + int nspin, + int ik, + hamilt::Hamilt>* p_ham); + +} // namespace DFTU_LCAO + +#endif // __LCAO + +#endif // DFTU_FOLDING_H diff --git a/source/source_lcao/module_dftu/dftu_force.cpp b/source/source_lcao/module_dftu/dftu_force.cpp index 3f119721bb..8df6bd2c3d 100644 --- a/source/source_lcao/module_dftu/dftu_force.cpp +++ b/source/source_lcao/module_dftu/dftu_force.cpp @@ -1,40 +1,32 @@ -#include "source_io/module_parameter/parameter.h" - #ifdef __LCAO +#include "dftu_force.h" +#include "dftu_folding.h" #include "dftu_lcao.h" -#include "source_base/constants.h" #include "source_base/global_function.h" -#include "source_base/inverse_matrix.h" #include "source_base/module_external/scalapack_connector.h" #include "source_base/parallel_reduce.h" #include "source_base/timer.h" -#include "source_estate/elecstate_lcao.h" -#include "source_cell/magnetism.h" -#include "source_estate/module_charge/charge.h" -#include #include -#include -#include -#include -#include -#include -#include - - -void Plus_U::force_stress(const UnitCell& ucell, - const Grid_Driver& gd, - std::vector>* dmk_d, - std::vector>>* dmk_c, - const Parallel_Orbitals& pv, - ForceStressArrays& fsr, - ModuleBase::matrix& force_dftu, - ModuleBase::matrix& stress_dftu, - const K_Vectors& kv, - const int npol) +#include + + +namespace DFTU_LCAO { + +void force_stress(Plus_U& dftu, + const UnitCell& ucell, + const Grid_Driver& gd, + std::vector>* dmk_d, + std::vector>>* dmk_c, + const Parallel_Orbitals& pv, + ForceStressArrays& fsr, + ModuleBase::matrix& force_dftu, + ModuleBase::matrix& stress_dftu, + const K_Vectors& kv, + const int npol) { - ModuleBase::TITLE("Plus_U", "force_stress"); - ModuleBase::timer::start("Plus_U", "force_stress"); + ModuleBase::TITLE("DFTU_LCAO", "force_stress"); + ModuleBase::timer::start("DFTU_LCAO", "force_stress"); // Defensive null check: the legacy dft_plus_u==2 force/stress path // requires fsr.DSloc_x/y/z (gamma_only) or fsr.DSloc_Rx/Ry/Rz (multik) @@ -43,20 +35,20 @@ void Plus_U::force_stress(const UnitCell& ucell, // fsr_dftu is created without allocation), we fail early with a clear // message instead of letting pdgemm_ dereference nullptr and crash. // See force_stress_lcao.cpp for the historical background. - if (this->gamma_only_local) + if (dftu.is_gamma_only_local()) { - if (this->cal_force + if (dftu.is_cal_force() && (fsr.DSloc_x == nullptr || fsr.DSloc_y == nullptr || fsr.DSloc_z == nullptr)) { - ModuleBase::WARNING_QUIT("Plus_U::force_stress", + ModuleBase::WARNING_QUIT("DFTU_LCAO::force_stress", "fsr.DSloc_x/y/z are nullptr in gamma_only path; the caller must allocate and fill them. " "See notes in source/source_lcao/force_stress_lcao.cpp."); } - if (this->cal_stress + if (dftu.is_cal_stress() && (fsr.DSloc_x == nullptr || fsr.DSloc_y == nullptr || fsr.DSloc_z == nullptr || fsr.DH_r == nullptr)) { - ModuleBase::WARNING_QUIT("Plus_U::force_stress", + ModuleBase::WARNING_QUIT("DFTU_LCAO::force_stress", "fsr.DSloc_x/y/z or fsr.DH_r is nullptr in gamma_only path; " "the caller must allocate and fill them. " "See notes in source/source_lcao/force_stress_lcao.cpp."); @@ -64,36 +56,36 @@ void Plus_U::force_stress(const UnitCell& ucell, } else { - if (this->cal_force + if (dftu.is_cal_force() && (fsr.DSloc_Rx == nullptr || fsr.DSloc_Ry == nullptr || fsr.DSloc_Rz == nullptr)) { - ModuleBase::WARNING_QUIT("Plus_U::force_stress", + ModuleBase::WARNING_QUIT("DFTU_LCAO::force_stress", "fsr.DSloc_Rx/Ry/Rz are nullptr in multik path; the caller must allocate and fill them. " "See notes in source/source_lcao/force_stress_lcao.cpp."); } - if (this->cal_stress + if (dftu.is_cal_stress() && (fsr.DSloc_Rx == nullptr || fsr.DSloc_Ry == nullptr || fsr.DSloc_Rz == nullptr || fsr.DH_r == nullptr)) { - ModuleBase::WARNING_QUIT("Plus_U::force_stress", + ModuleBase::WARNING_QUIT("DFTU_LCAO::force_stress", "fsr.DSloc_Rx/Ry/Rz or fsr.DH_r is nullptr in multik path; " "the caller must allocate and fill them. " "See notes in source/source_lcao/force_stress_lcao.cpp."); } } - const int nlocal = this->nlocal; + const int nlocal = dftu.get_nlocal(); - if (this->cal_force) + if (dftu.is_cal_force()) { force_dftu.zero_out(); } - if (this->cal_stress) + if (dftu.is_cal_stress()) { stress_dftu.zero_out(); } - if (this->gamma_only_local) + if (dftu.is_gamma_only_local()) { const char transN = 'N'; const char transT = 'T'; @@ -101,43 +93,42 @@ void Plus_U::force_stress(const UnitCell& ucell, const double alpha = 1.0; const double beta = 0.0; - std::vector rho_VU(pv.nloc); + std::vector rho_pot_onsite(pv.nloc); for (int ik = 0; ik < kv.get_nks(); ik++) { const int spin = kv.isk[ik]; - double* VU = new double[pv.nloc]; + double* pot_onsite = new double[pv.nloc]; - this->cal_VU_pot_mat_real(spin, false, VU, npol); + dftu.pot_onsite_real(spin, false, pot_onsite, npol); #ifdef __MPI ScalapackConnector::gemm(transT, transN, nlocal, nlocal, nlocal, alpha, (*dmk_d)[spin].data(), 1, 1, - pv.desc, VU, 1, 1, - pv.desc, beta, &rho_VU[0], + pv.desc, pot_onsite, 1, 1, + pv.desc, beta, &rho_pot_onsite[0], 1, 1, pv.desc); #endif - delete[] VU; + delete[] pot_onsite; - if (this->cal_force) + if (dftu.is_cal_force()) { - this->cal_force_gamma(ucell,&rho_VU[0], pv, fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z, force_dftu); + cal_force_gamma(dftu.get_nlocal(), dftu.get_npol(), + dftu.get_orbital_corr_vec(), dftu.get_iatlnmipol2iwt(), + ucell, &rho_pot_onsite[0], pv, + fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z, force_dftu); } - if (this->cal_stress) + if (dftu.is_cal_stress()) { - this->cal_stress_gamma(ucell, - pv, - &gd, - fsr.DSloc_x, - fsr.DSloc_y, - fsr.DSloc_z, - fsr.DH_r, - &rho_VU[0], - stress_dftu); + cal_stress_gamma(dftu.get_nlocal(), dftu.get_npol(), + dftu.get_ks_solver(), dftu.get_orb_cutoff(), + ucell, pv, &gd, + fsr.DSloc_x, fsr.DSloc_y, fsr.DSloc_z, fsr.DH_r, + &rho_pot_onsite[0], stress_dftu); } } // ik } @@ -149,43 +140,48 @@ void Plus_U::force_stress(const UnitCell& ucell, const std::complex alpha(1.0, 0.0); const std::complex beta(0.0, 0.0); - std::vector> rho_VU(pv.nloc); + std::vector> rho_pot_onsite(pv.nloc); for (int ik = 0; ik < kv.get_nks(); ik++) { const int spin = kv.isk[ik]; - std::complex* VU = new std::complex[pv.nloc]; + std::complex* pot_onsite = new std::complex[pv.nloc]; - this->cal_VU_pot_mat_complex(spin, false, VU, npol); + dftu.pot_onsite_complex(spin, false, pot_onsite, npol); #ifdef __MPI ScalapackConnector::gemm(transT, transN, nlocal, nlocal, nlocal, alpha, (*dmk_c)[ik].data(), one_int, one_int, - pv.desc, VU, one_int, one_int, pv.desc, beta, - &rho_VU[0], one_int, one_int, pv.desc); + pv.desc, pot_onsite, one_int, one_int, pv.desc, beta, + &rho_pot_onsite[0], one_int, one_int, pv.desc); #endif - delete[] VU; + delete[] pot_onsite; - if (this->cal_force) + if (dftu.is_cal_force()) { - cal_force_k(ucell, gd, fsr, pv, ik, &rho_VU[0], force_dftu, kv.kvec_d[ik]); + cal_force_k(dftu.get_nlocal(), dftu.get_npol(), + dftu.get_ks_solver(), dftu.get_orb_cutoff(), + dftu.get_orbital_corr_vec(), dftu.get_iatlnmipol2iwt(), + ucell, gd, fsr, pv, ik, &rho_pot_onsite[0], force_dftu, kv.kvec_d[ik]); } - if (this->cal_stress) + if (dftu.is_cal_stress()) { - cal_stress_k(ucell, gd, fsr, pv, ik, &rho_VU[0], stress_dftu, kv.kvec_d[ik]); + cal_stress_k(dftu.get_nlocal(), dftu.get_npol(), + dftu.get_ks_solver(), dftu.get_orb_cutoff(), + ucell, gd, fsr, pv, ik, &rho_pot_onsite[0], stress_dftu, kv.kvec_d[ik]); } } // ik } - if (this->cal_force) + if (dftu.is_cal_force()) { Parallel_Reduce::reduce_pool(force_dftu.c, force_dftu.nr * force_dftu.nc); } - if (this->cal_stress) + if (dftu.is_cal_stress()) { Parallel_Reduce::reduce_pool(stress_dftu.c, stress_dftu.nr * stress_dftu.nc); @@ -206,22 +202,28 @@ void Plus_U::force_stress(const UnitCell& ucell, } } } - ModuleBase::timer::end("Plus_U", "force_stress"); + ModuleBase::timer::end("DFTU_LCAO", "force_stress"); return; } -void Plus_U::cal_force_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const std::complex* rho_VU, - ModuleBase::matrix& force_dftu, - const ModuleBase::Vector3& kvec_d) +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>>>>& iatlnmipol2iwt, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + const int ik, + const std::complex* rho_pot_onsite, + ModuleBase::matrix& force_dftu, + const ModuleBase::Vector3& kvec_d) { - ModuleBase::TITLE("Plus_U", "cal_force_k"); - ModuleBase::timer::start("Plus_U", "cal_force_k"); + ModuleBase::TITLE("DFTU_LCAO", "cal_force_k"); + ModuleBase::timer::start("DFTU_LCAO", "cal_force_k"); const char transN = 'N'; const char transC = 'C'; @@ -229,15 +231,15 @@ void Plus_U::cal_force_k(const UnitCell& ucell, const std::complex zero(0.0, 0.0); const std::complex one(1.0, 0.0); - const int nlocal = this->nlocal; assert(nlocal>0); - std::vector> dm_VU_dSm(pv.nloc); + std::vector> dm_pot_onsite_dSm(pv.nloc); std::vector> dSm_k(pv.nloc); for (int dim = 0; dim < 3; dim++) { - this->folding_matrix_k(ucell, gd, fsr, pv, ik, dim + 1, 0, &dSm_k[0], kvec_d); + DFTU_LCAO::folding_matrix_k(npol, ks_solver, orb_cutoff, + ucell, gd, fsr, pv, ik, dim + 1, 0, &dSm_k[0], kvec_d); #ifdef __MPI ScalapackConnector::gemm(transN, @@ -250,12 +252,12 @@ void Plus_U::cal_force_k(const UnitCell& ucell, one_int, one_int, pv.desc, - rho_VU, + rho_pot_onsite, one_int, one_int, pv.desc, zero, - &dm_VU_dSm[0], + &dm_pot_onsite_dSm[0], one_int, one_int, pv.desc); @@ -272,7 +274,7 @@ void Plus_U::cal_force_k(const UnitCell& ucell, const int irc = ic * pv.nrow + ir; if (iwt1 == iwt2) - force_dftu(iat1, dim) += dm_VU_dSm[irc].real(); + force_dftu(iat1, dim) += dm_pot_onsite_dSm[irc].real(); } // end ic } // end ir @@ -288,12 +290,12 @@ void Plus_U::cal_force_k(const UnitCell& ucell, one_int, one_int, pv.desc, - rho_VU, + rho_pot_onsite, one_int, one_int, pv.desc, zero, - &dm_VU_dSm[0], + &dm_pot_onsite_dSm[0], one_int, one_int, pv.desc); @@ -302,7 +304,7 @@ void Plus_U::cal_force_k(const UnitCell& ucell, for (int it = 0; it < ucell.ntype; it++) { const int NL = ucell.atoms[it].nwl + 1; - const int LC = get_orbital_corr(it); + const int LC = orbital_corr[it]; if (LC == -1) continue; @@ -312,7 +314,7 @@ void Plus_U::cal_force_k(const UnitCell& ucell, for (int l = 0; l < NL; l++) { - if (l != get_orbital_corr(it)) + if (l != orbital_corr[it]) continue; const int N = ucell.atoms[it].l_nchi[l]; @@ -323,15 +325,15 @@ void Plus_U::cal_force_k(const UnitCell& ucell, for (int m = 0; m < 2 * l + 1; m++) { - for (int ipol = 0; ipol < this->npol; ipol++) + for (int ipol = 0; ipol < npol; ipol++) { - const int iwt = this->iatlnmipol2iwt[iat][l][n][m][ipol]; + const int iwt = iatlnmipol2iwt[iat][l][n][m][ipol]; const int mu = pv.global2local_row(iwt); const int nu = pv.global2local_col(iwt); if (mu < 0 || nu < 0) continue; - force_dftu(iat, dim) += dm_VU_dSm[nu * pv.nrow + mu].real(); + force_dftu(iat, dim) += dm_pot_onsite_dSm[nu * pv.nrow + mu].real(); } } // } // n @@ -339,24 +341,26 @@ void Plus_U::cal_force_k(const UnitCell& ucell, } // ia } // it } // end dim - ModuleBase::timer::end("Plus_U", "cal_force_k"); + ModuleBase::timer::end("DFTU_LCAO", "cal_force_k"); return; } -void Plus_U::cal_stress_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const std::complex* rho_VU, - ModuleBase::matrix& stress_dftu, - const ModuleBase::Vector3& kvec_d) +void cal_stress_k(const int nlocal, + const int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + const int ik, + const std::complex* rho_pot_onsite, + ModuleBase::matrix& stress_dftu, + const ModuleBase::Vector3& kvec_d) { - ModuleBase::TITLE("Plus_U", "cal_stress_k"); - ModuleBase::timer::start("Plus_U", "cal_stress_k"); - - const int nlocal = this->nlocal; + ModuleBase::TITLE("DFTU_LCAO", "cal_stress_k"); + ModuleBase::timer::start("DFTU_LCAO", "cal_stress_k"); const char transN = 'N'; const int one_int = 1; @@ -364,14 +368,15 @@ void Plus_U::cal_stress_k(const UnitCell& ucell, const std::complex zero(0.0, 0.0); const std::complex one(1.0, 0.0); - std::vector> dm_VU_sover(pv.nloc); + std::vector> dm_pot_onsite_sover(pv.nloc); std::vector> dSR_k(pv.nloc); for (int dim1 = 0; dim1 < 3; dim1++) { for (int dim2 = dim1; dim2 < 3; dim2++) { - this->folding_matrix_k(ucell, gd, fsr, pv, ik, dim1 + 4, dim2, &dSR_k[0], kvec_d); + DFTU_LCAO::folding_matrix_k(npol, ks_solver, orb_cutoff, + ucell, gd, fsr, pv, ik, dim1 + 4, dim2, &dSR_k[0], kvec_d); #ifdef __MPI ScalapackConnector::gemm(transN, @@ -380,7 +385,7 @@ void Plus_U::cal_stress_k(const UnitCell& ucell, nlocal, nlocal, minus_half, - rho_VU, + rho_pot_onsite, one_int, one_int, pv.desc, @@ -389,7 +394,7 @@ void Plus_U::cal_stress_k(const UnitCell& ucell, one_int, pv.desc, zero, - &dm_VU_sover[0], + &dm_pot_onsite_sover[0], one_int, one_int, pv.desc); @@ -404,37 +409,40 @@ void Plus_U::cal_stress_k(const UnitCell& ucell, const int irc = ic * pv.nrow + ir; if (iwt1 == iwt2) - stress_dftu(dim1, dim2) += 2.0 * dm_VU_sover[irc].real(); + stress_dftu(dim1, dim2) += 2.0 * dm_pot_onsite_sover[irc].real(); } // end ic } // end ir } // end dim2 } // end dim1 - ModuleBase::timer::end("Plus_U", "cal_stress_k"); + ModuleBase::timer::end("DFTU_LCAO", "cal_stress_k"); return; } -void Plus_U::cal_force_gamma(const UnitCell& ucell, - const double* rho_VU, - const Parallel_Orbitals& pv, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - ModuleBase::matrix& force_dftu) +void cal_force_gamma(const int nlocal, + const int npol, + const std::vector& orbital_corr, + const std::vector>>>>& iatlnmipol2iwt, + const UnitCell& ucell, + const double* rho_pot_onsite, + const Parallel_Orbitals& pv, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + ModuleBase::matrix& force_dftu) { - ModuleBase::TITLE("Plus_U", "cal_force_gamma"); - ModuleBase::timer::start("Plus_U", "cal_force_gamma"); + ModuleBase::TITLE("DFTU_LCAO", "cal_force_gamma"); + ModuleBase::timer::start("DFTU_LCAO", "cal_force_gamma"); const char transN = 'N'; const char transT = 'T'; const int one_int = 1; const double one = 1.0; const double zero = 0.0; const double minus_one = -1.0; - const int nlocal = this->nlocal; assert(nlocal>0); - std::vector dm_VU_dSm(pv.nloc); + std::vector dm_pot_onsite_dSm(pv.nloc); for (int dim = 0; dim < 3; dim++) { @@ -463,12 +471,12 @@ void Plus_U::cal_force_gamma(const UnitCell& ucell, 1, 1, pv.desc, - rho_VU, + rho_pot_onsite, 1, 1, pv.desc, zero, - &dm_VU_dSm[0], + &dm_pot_onsite_dSm[0], 1, 1, pv.desc); @@ -485,7 +493,7 @@ void Plus_U::cal_force_gamma(const UnitCell& ucell, const int irc = ic * pv.nrow + ir; if (iwt1 == iwt2) - force_dftu(iat1, dim) += dm_VU_dSm[irc]; + force_dftu(iat1, dim) += dm_pot_onsite_dSm[irc]; } // end ic } // end ir @@ -501,12 +509,12 @@ void Plus_U::cal_force_gamma(const UnitCell& ucell, 1, 1, pv.desc, - rho_VU, + rho_pot_onsite, 1, 1, pv.desc, zero, - &dm_VU_dSm[0], + &dm_pot_onsite_dSm[0], 1, 1, pv.desc); @@ -538,15 +546,15 @@ void Plus_U::cal_force_gamma(const UnitCell& ucell, // Calculate the local occupation number matrix for (int m = 0; m < 2 * l + 1; m++) { - for (int ipol = 0; ipol < this->npol; ipol++) + for (int ipol = 0; ipol < npol; ipol++) { - const int iwt = this->iatlnmipol2iwt[iat][l][n][m][ipol]; + const int iwt = iatlnmipol2iwt[iat][l][n][m][ipol]; const int mu = pv.global2local_row(iwt); const int nu = pv.global2local_col(iwt); if (mu < 0 || nu < 0) continue; - force_dftu(iat, dim) += dm_VU_dSm[nu * pv.nrow + mu]; + force_dftu(iat, dim) += dm_pot_onsite_dSm[nu * pv.nrow + mu]; } } // } // n @@ -555,23 +563,27 @@ void Plus_U::cal_force_gamma(const UnitCell& ucell, } // it } // end dim - ModuleBase::timer::end("Plus_U", "cal_force_gamma"); + ModuleBase::timer::end("DFTU_LCAO", "cal_force_gamma"); return; } -void Plus_U::cal_stress_gamma(const UnitCell& ucell, - const Parallel_Orbitals& pv, - const Grid_Driver* gd, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - double* dh_r, - const double* rho_VU, - ModuleBase::matrix& stress_dftu) +void cal_stress_gamma(const int nlocal, + const int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const Grid_Driver* gd, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + double* dh_r, + const double* rho_pot_onsite, + ModuleBase::matrix& stress_dftu) { - ModuleBase::TITLE("Plus_U", "cal_stress_gamma"); - ModuleBase::timer::start("Plus_U", "cal_stress_gamma"); + ModuleBase::TITLE("DFTU_LCAO", "cal_stress_gamma"); + ModuleBase::timer::start("DFTU_LCAO", "cal_stress_gamma"); const char transN = 'N'; const int one_int = 1; @@ -580,15 +592,14 @@ void Plus_U::cal_stress_gamma(const UnitCell& ucell, const double one = 1.0; std::vector dSR_gamma(pv.nloc); - std::vector dm_VU_sover(pv.nloc); - - const int nlocal = this->nlocal; + std::vector dm_pot_onsite_sover(pv.nloc); for (int dim1 = 0; dim1 < 3; dim1++) { for (int dim2 = dim1; dim2 < 3; dim2++) { - this->fold_dSR_gamma(ucell, pv, gd, dsloc_x, dsloc_y, dsloc_z, dh_r, dim1, dim2, &dSR_gamma[0]); + DFTU_LCAO::fold_dSR_gamma(npol, ks_solver, orb_cutoff, + ucell, pv, gd, dsloc_x, dsloc_y, dsloc_z, dh_r, dim1, dim2, &dSR_gamma[0]); #ifdef __MPI ScalapackConnector::gemm(transN, @@ -597,7 +608,7 @@ void Plus_U::cal_stress_gamma(const UnitCell& ucell, nlocal, nlocal, minus_half, - rho_VU, + rho_pot_onsite, 1, 1, pv.desc, @@ -606,29 +617,32 @@ void Plus_U::cal_stress_gamma(const UnitCell& ucell, 1, pv.desc, zero, - &dm_VU_sover[0], + &dm_pot_onsite_sover[0], 1, 1, pv.desc); #endif - for (int ir = 0; ir < this->paraV->nrow; ir++) + for (int ir = 0; ir < pv.nrow; ir++) { - const int iwt1 = this->paraV->local2global_row(ir); + const int iwt1 = pv.local2global_row(ir); - for (int ic = 0; ic < this->paraV->ncol; ic++) + for (int ic = 0; ic < pv.ncol; ic++) { - const int iwt2 = this->paraV->local2global_col(ic); - const int irc = ic * this->paraV->nrow + ir; + const int iwt2 = pv.local2global_col(ic); + const int irc = ic * pv.nrow + ir; if (iwt1 == iwt2) - stress_dftu(dim1, dim2) += 2.0 * dm_VU_sover[irc]; + stress_dftu(dim1, dim2) += 2.0 * dm_pot_onsite_sover[irc]; } // end ic } // end ir } // end dim2 } // end dim1 - ModuleBase::timer::end("Plus_U", "cal_stress_gamma"); + ModuleBase::timer::end("DFTU_LCAO", "cal_stress_gamma"); return; } + +} // namespace DFTU_LCAO + #endif diff --git a/source/source_lcao/module_dftu/dftu_force.h b/source/source_lcao/module_dftu/dftu_force.h new file mode 100644 index 0000000000..f71c94c111 --- /dev/null +++ b/source/source_lcao/module_dftu/dftu_force.h @@ -0,0 +1,106 @@ +/// @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 + +#include "source_basis/module_ao/parallel_orbitals.h" +#include "source_base/matrix.h" +#include "source_base/vector3.h" +#include "source_cell/klist.h" +#include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_cell/unitcell.h" +#include "source_lcao/force_stress_arrays.h" + +#include +#include +#include + +#ifdef __LCAO + +class Plus_U; + +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, + const UnitCell& ucell, + const Grid_Driver& gd, + std::vector>* dmk_d, + std::vector>>* dmk_c, + const Parallel_Orbitals& pv, + ForceStressArrays& fsr, + ModuleBase::matrix& force_dftu, + ModuleBase::matrix& stress_dftu, + const K_Vectors& kv, + const int npol); + +/// @brief Force contribution at a k-point (multik path). +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>>>>& iatlnmipol2iwt, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + const int ik, + const std::complex* rho_VU, + ModuleBase::matrix& force_dftu, + const ModuleBase::Vector3& kvec_d); + +/// @brief Stress contribution at a k-point (multik path). +void cal_stress_k(int nlocal, + int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Grid_Driver& gd, + ForceStressArrays& fsr, + const Parallel_Orbitals& pv, + const int ik, + const std::complex* rho_VU, + ModuleBase::matrix& stress_dftu, + const ModuleBase::Vector3& kvec_d); + +/// @brief Force contribution at gamma point. +void cal_force_gamma(int nlocal, + int npol, + const std::vector& orbital_corr, + const std::vector>>>>& iatlnmipol2iwt, + const UnitCell& ucell, + const double* rho_VU, + const Parallel_Orbitals& pv, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + ModuleBase::matrix& force_dftu); + +/// @brief Stress contribution at gamma point. +void cal_stress_gamma(int nlocal, + int npol, + const std::string& ks_solver, + const std::vector& orb_cutoff, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const Grid_Driver* gd, + double* dsloc_x, + double* dsloc_y, + double* dsloc_z, + double* dh_r, + const double* rho_VU, + ModuleBase::matrix& stress_dftu); + +} // namespace DFTU_LCAO + +#endif // __LCAO + +#endif // DFTU_FORCE_H diff --git a/source/source_lcao/module_dftu/dftu_fs.cpp b/source/source_lcao/module_dftu/dftu_fs.cpp index 72f2ffcce0..ddd4955dbe 100644 --- a/source/source_lcao/module_dftu/dftu_fs.cpp +++ b/source/source_lcao/module_dftu/dftu_fs.cpp @@ -140,11 +140,11 @@ void DFTU>::cal_force_stress(const bool cal_force, std::vector occ(tlp1 * tlp1 * this->nspin, 0); this->dftu->get_occ_mat_flat(iat0, target_L, occ); - // calculate VU - const double u_value = this->dftu->u_current[T0]; - std::vector VU(occ.size()); + // calculate pot_onsite + const double u_value = this->dftu->get_u_current(T0); + std::vector pot_onsite(occ.size()); double eu_tmp = 0; - this->cal_v_of_u(occ, tlp1, u_value, &VU[0], eu_tmp); + this->cal_pot_onsite(occ, tlp1, u_value, &pot_onsite[0], eu_tmp); // second iteration to calculate force and stress // calculate Force for atom J @@ -190,7 +190,7 @@ void DFTU>::cal_force_stress(const bool cal_force, paraV, nlm_tot[ad1], nlm_tot[ad2], - VU, + pot_onsite, tmp, this->nspin, force_tmp1, @@ -204,7 +204,7 @@ void DFTU>::cal_force_stress(const bool cal_force, paraV, nlm_tot[ad1], nlm_tot[ad2], - VU, + pot_onsite, tmp, this->nspin, dis1, @@ -275,7 +275,7 @@ void DFTU>::cal_force_IJR(const int& iat1, const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, double* force1, @@ -290,7 +290,7 @@ void DFTU>::cal_force_IJR(const int& iat1, // --------------------------------------------- auto row_indexes = paraV->get_indexes_row(iat1); auto col_indexes = paraV->get_indexes_col(iat2); - const int m_size = int(sqrt(vu_in.size() / nspin)); + const int m_size = int(sqrt(pot_onsite_in.size() / nspin)); const int m_size2 = m_size * m_size; // step_trace = 0 for NSPIN=1,2; ={0, 1, local_col, local_col+1} for NSPIN=4 @@ -323,14 +323,14 @@ void DFTU>::cal_force_IJR(const int& iat1, { for (int m2 = 0; m2 < m_size; m2++) { - tmp[0] = vu_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size] + tmp[0] = pot_onsite_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size] * nlm2[m2] * dm_pointer[step_trace[step_is]]; - tmp[1] = vu_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size * 2] + tmp[1] = pot_onsite_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size * 2] * nlm2[m2] * dm_pointer[step_trace[step_is]]; - tmp[2] = vu_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size * 3] + tmp[2] = pot_onsite_in[m1 * m_size + m2 + is * m_size2] * nlm1[m1 + m_size * 3] * nlm2[m2] * dm_pointer[step_trace[step_is]]; - // force1 = - VU * * - // force2 = - VU * * } + // force1 = - pot_onsite * * + // force2 = - pot_onsite * * } force1[0] += tmp[0]; force1[1] += tmp[1]; force1[2] += tmp[2]; @@ -352,7 +352,7 @@ void DFTU>::cal_stress_IJR(const int& iat1, const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, const ModuleBase::Vector3& dis1, @@ -368,7 +368,7 @@ void DFTU>::cal_stress_IJR(const int& iat1, // --------------------------------------------- auto row_indexes = paraV->get_indexes_row(iat1); auto col_indexes = paraV->get_indexes_col(iat2); - const int m_size = int(sqrt(vu_in.size() / nspin)); + const int m_size = int(sqrt(pot_onsite_in.size() / nspin)); const int m_size2 = m_size * m_size; // step_trace = 0 for NSPIN=1,2; ={0, 1, local_col, local_col+1} for NSPIN=4 @@ -400,7 +400,7 @@ void DFTU>::cal_stress_IJR(const int& iat1, { for (int m2 = 0; m2 < m_size; m2++) { - double tmp = vu_in[m1 * m_size + m2 + is * m_size2] * dm_pointer[step_trace[step_is]]; + double tmp = pot_onsite_in[m1 * m_size + m2 + is * m_size2] * dm_pointer[step_trace[step_is]]; // std::cout<<__FILE__<<__LINE__<<" "<>::cal_force_IJR( const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, double* force1, double* force2); @@ -450,7 +450,7 @@ template void DFTU, double>>::cal_force_IJR( const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, double* force1, double* force2); @@ -459,7 +459,7 @@ template void DFTU, std::complex>>::ca const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, double* force1, double* force2); @@ -469,7 +469,7 @@ template void DFTU>::cal_stress_IJR( const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, const ModuleBase::Vector3& dis1, @@ -480,7 +480,7 @@ template void DFTU, double>>::cal_stress_IJR( const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, const ModuleBase::Vector3& dis1, @@ -491,7 +491,7 @@ template void DFTU, std::complex>>::ca const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, const ModuleBase::Vector3& dis1, diff --git a/source/source_lcao/module_dftu/dftu_hamilt.cpp b/source/source_lcao/module_dftu/dftu_hamilt.cpp index c8362bc749..692a221490 100644 --- a/source/source_lcao/module_dftu/dftu_hamilt.cpp +++ b/source/source_lcao/module_dftu/dftu_hamilt.cpp @@ -1,27 +1,32 @@ #include "dftu_lcao.h" +#include "dftu_hamilt.h" #include "source_base/module_external/scalapack_connector.h" -#include "source_io/module_parameter/parameter.h" #include "source_base/timer.h" #ifdef __LCAO -void Plus_U::cal_eff_pot_mat_complex(const int ik, - std::complex* eff_pot, - const std::vector& isk, - const std::complex* sk, - const int npol) +namespace DFTU_LCAO { + +void pot_uterm_complex(Plus_U& dftu, + const int ik, + std::complex* pot_uterm, + const std::vector& isk, + const std::complex* sk, + const int npol) { - ModuleBase::TITLE("Plus_U", "cal_eff_pot_c"); - if (!is_occ_mat_initialized()) + ModuleBase::TITLE("DFTU_LCAO", "pot_uterm_complex"); + if (!dftu.is_occ_mat_initialized()) { return; } - ModuleBase::timer::start("Plus_U", "cal_eff_pot_c"); + ModuleBase::timer::start("DFTU_LCAO", "pot_uterm_complex"); int spin = isk[ik]; - ModuleBase::GlobalFunc::ZEROS(eff_pot, this->paraV->nloc); + const Parallel_Orbitals* paraV = dftu.get_paraV(); + const int nlocal = dftu.get_nlocal(); + ModuleBase::GlobalFunc::ZEROS(pot_uterm, paraV->nloc); //============================================================= // PART2: call pblas to calculate effective potential matrix @@ -32,48 +37,55 @@ void Plus_U::cal_eff_pot_mat_complex(const int ik, const std::complex half = 0.5; const std::complex zero = 0.0; - std::vector> VU(this->paraV->nloc); - this->cal_VU_pot_mat_complex(spin, true, &VU[0], npol); + std::vector> pot_onsite(paraV->nloc); + dftu.pot_onsite_complex(spin, true, &pot_onsite[0], npol); #ifdef __MPI - ScalapackConnector::gemm(transN, transN, - this->nlocal, this->nlocal, this->nlocal, - half, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), one_int, one_int, this->paraV->desc, - sk, one_int, one_int, this->paraV->desc, + ScalapackConnector::gemm(transN, transN, + nlocal, nlocal, nlocal, + half, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), one_int, one_int, paraV->desc, + sk, one_int, one_int, paraV->desc, zero, - eff_pot, one_int, one_int, this->paraV->desc); + pot_uterm, one_int, one_int, paraV->desc); #endif - for (int irc = 0; irc < this->paraV->nloc; irc++) - { - VU[irc] = eff_pot[irc]; - } + for (int irc = 0; irc < paraV->nloc; irc++) + { + pot_onsite[irc] = pot_uterm[irc]; + } #ifdef __MPI - ScalapackConnector::tranu(this->nlocal, this->nlocal, - one, - &VU[0], one_int, one_int, this->paraV->desc, - one, - eff_pot, one_int, one_int, this->paraV->desc); + ScalapackConnector::tranu(nlocal, nlocal, + one, + &pot_onsite[0], one_int, one_int, paraV->desc, + one, + pot_uterm, one_int, one_int, paraV->desc); #endif - ModuleBase::timer::end("Plus_U", "cal_eff_pot_c"); + ModuleBase::timer::end("DFTU_LCAO", "pot_uterm_complex"); return; } -void Plus_U::cal_eff_pot_mat_real(const int ik, double* eff_pot, const std::vector& isk, const double* sk, const int npol) +void pot_uterm_real(Plus_U& dftu, + const int ik, + double* pot_uterm, + const std::vector& isk, + const double* sk, + const int npol) { - ModuleBase::TITLE("Plus_U", "cal_eff_pot_r"); - if (!is_occ_mat_initialized()) + ModuleBase::TITLE("DFTU_LCAO", "pot_uterm_real"); + if (!dftu.is_occ_mat_initialized()) { return; } - ModuleBase::timer::start("Plus_U", "cal_eff_pot_r"); + ModuleBase::timer::start("DFTU_LCAO", "pot_uterm_real"); int spin = isk[ik]; - ModuleBase::GlobalFunc::ZEROS(eff_pot, this->paraV->nloc); + const Parallel_Orbitals* paraV = dftu.get_paraV(); + const int nlocal = dftu.get_nlocal(); + ModuleBase::GlobalFunc::ZEROS(pot_uterm, paraV->nloc); //============================================================= // PART2: call pblas to calculate effective potential matrix @@ -82,48 +94,50 @@ void Plus_U::cal_eff_pot_mat_real(const int ik, double* eff_pot, const std::vect int one_int = 1; double alpha = 1.0, beta = 0.0, half = 0.5, one = 1.0; - std::vector VU(this->paraV->nloc); - this->cal_VU_pot_mat_real(spin, 1, &VU[0], npol); + std::vector pot_onsite(paraV->nloc); + dftu.pot_onsite_real(spin, 1, &pot_onsite[0], npol); #ifdef __MPI - ScalapackConnector::gemm(transN, transN, - this->nlocal, this->nlocal, this->nlocal, - half, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), 1, 1, this->paraV->desc, - sk, 1, 1, this->paraV->desc, + ScalapackConnector::gemm(transN, transN, + nlocal, nlocal, nlocal, + half, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), 1, 1, paraV->desc, + sk, 1, 1, paraV->desc, beta, - eff_pot, 1, 1, this->paraV->desc); + pot_uterm, 1, 1, paraV->desc); #endif - for (int irc = 0; irc < this->paraV->nloc; irc++) - VU[irc] = eff_pot[irc]; + for (int irc = 0; irc < paraV->nloc; irc++) + pot_onsite[irc] = pot_uterm[irc]; #ifdef __MPI - pdtran_(&this->nlocal, &this->nlocal, - &one, - &VU[0], &one_int, &one_int, const_cast(this->paraV->desc), - &one, - eff_pot, &one_int, &one_int, const_cast(this->paraV->desc)); + pdtran_(&nlocal, &nlocal, + &one, + &pot_onsite[0], &one_int, &one_int, const_cast(paraV->desc), + &one, + pot_uterm, &one_int, &one_int, const_cast(paraV->desc)); #endif - ModuleBase::timer::end("Plus_U", "cal_eff_pot_r"); + ModuleBase::timer::end("DFTU_LCAO", "pot_uterm_real"); return; } +} // namespace DFTU_LCAO + void Plus_U::cal_eff_pot_mat_R_double(const int ispin, double* SR, double* HR, const int npol) { const char transN = 'N', transT = 'T'; const int one_int = 1; const double alpha = 1.0, beta = 0.0, one = 1.0, half = 0.5; - std::vector VU(this->paraV->nloc); - this->cal_VU_pot_mat_real(ispin, 1, &VU[0], npol); + std::vector pot_onsite(this->paraV->nloc); + this->pot_onsite_real(ispin, 1, &pot_onsite[0], npol); #ifdef __MPI ScalapackConnector::gemm(transN, transN, this->nlocal, this->nlocal, this->nlocal, half, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), 1, 1, this->paraV->desc, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), 1, 1, this->paraV->desc, SR, 1, 1, this->paraV->desc, beta, HR, 1, 1, this->paraV->desc); @@ -132,7 +146,7 @@ void Plus_U::cal_eff_pot_mat_R_double(const int ispin, double* SR, double* HR, c this->nlocal, this->nlocal, this->nlocal, half, SR, 1, 1, this->paraV->desc, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), 1, 1, this->paraV->desc, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), 1, 1, this->paraV->desc, one, HR, 1, 1, this->paraV->desc); #endif @@ -146,14 +160,14 @@ void Plus_U::cal_eff_pot_mat_R_complex_double(const int ispin, std::complex zero = 0.0, one = 1.0, half = 0.5; - std::vector> VU(this->paraV->nloc); - this->cal_VU_pot_mat_complex(ispin, 1, &VU[0], npol); + std::vector> pot_onsite(this->paraV->nloc); + this->pot_onsite_complex(ispin, 1, &pot_onsite[0], npol); #ifdef __MPI ScalapackConnector::gemm(transN, transN, this->nlocal, this->nlocal, this->nlocal, half, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), one_int, one_int, this->paraV->desc, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), one_int, one_int, this->paraV->desc, SR, one_int, one_int, this->paraV->desc, zero, HR, one_int, one_int, this->paraV->desc); @@ -162,7 +176,7 @@ void Plus_U::cal_eff_pot_mat_R_complex_double(const int ispin, std::complexnlocal, this->nlocal, this->nlocal, half, SR, one_int, one_int, this->paraV->desc, - ModuleBase::GlobalFunc::VECTOR_TO_PTR(VU), one_int, one_int, this->paraV->desc, + ModuleBase::GlobalFunc::VECTOR_TO_PTR(pot_onsite), one_int, one_int, this->paraV->desc, one, HR, one_int, one_int, this->paraV->desc); #endif diff --git a/source/source_lcao/module_dftu/dftu_hamilt.h b/source/source_lcao/module_dftu/dftu_hamilt.h new file mode 100644 index 0000000000..4fbe7dad26 --- /dev/null +++ b/source/source_lcao/module_dftu/dftu_hamilt.h @@ -0,0 +1,33 @@ +#ifndef DFTU_HAMILT_H +#define DFTU_HAMILT_H + +#include +#include + +class Plus_U; + +#ifdef __LCAO +namespace DFTU_LCAO { + +/// @brief Compute the LCAO-basis U-term effective potential matrix (complex). +/// Wraps Plus_U::pot_onsite_complex plus the S-projection GEMM. +void pot_uterm_complex(Plus_U& dftu, + const int ik, + std::complex* pot_uterm, + const std::vector& isk, + const std::complex* sk, + const int npol); + +/// @brief Compute the LCAO-basis U-term effective potential matrix (real). +/// Wraps Plus_U::pot_onsite_real plus the S-projection GEMM. +void pot_uterm_real(Plus_U& dftu, + const int ik, + double* pot_uterm, + const std::vector& isk, + const double* sk, + const int npol); + +} // namespace DFTU_LCAO +#endif + +#endif diff --git a/source/source_lcao/module_dftu/dftu_lcao.cpp b/source/source_lcao/module_dftu/dftu_lcao.cpp index 67e915e071..bb0529d22d 100644 --- a/source/source_lcao/module_dftu/dftu_lcao.cpp +++ b/source/source_lcao/module_dftu/dftu_lcao.cpp @@ -1,29 +1,14 @@ #include "dftu_lcao.h" +#include "dftu_occup.h" -#include "source_io/module_parameter/parameter.h" -#include "source_base/constants.h" -#include "source_base/global_function.h" -#include "source_base/inverse_matrix.h" -#include "source_base/memory_recorder.h" +#include "source_base/matrix.h" // occ_mat uses ModuleBase::matrix::operator() +#include "source_base/tool_quit.h" +#include "source_base/tool_title.h" #include "source_base/timer.h" -#include "source_cell/magnetism.h" -#include "source_estate/module_charge/charge.h" -#include -#include #include -#include -#include -#include -#include -#include -#include #include - // mohan add 2025-11-06 -// Static member definitions moved to dftu_base.cpp (Plus_U_Base::) -// Plus_U inherits these from Plus_U_Base. - Plus_U::Plus_U() {} @@ -175,7 +160,7 @@ void Plus_U::cal_energy_correction(const UnitCell& ucell, * this->occ_mat[iat][l][n][spin](m1, m0); } } - if (use_yukawa) + if (use_yukawa_) { this->energy_u += 0.5 * (this->U_Yukawa[T][l][n] - this->J_Yukawa[T][l][n]) * (nm_trace - nm2_trace); @@ -210,7 +195,7 @@ void Plus_U::cal_energy_correction(const UnitCell& ucell, } } } - if (use_yukawa) + if (use_yukawa_) { this->energy_u += 0.5 * (this->U_Yukawa[T][l][n] - this->J_Yukawa[T][l][n]) * (nm_trace - nm2_trace); @@ -236,16 +221,16 @@ void Plus_U::cal_energy_correction(const UnitCell& ucell, { for (int is = 0; is < 2; is++) { - double VU = 0.0; - VU = get_onebody_eff_pot(T, iat, l, n, is, m1_all, m2_all, false); - energy_dc += VU * this->occ_mat[iat][l][n][is](m1_all, m2_all); + double pot_onsite = 0.0; + pot_onsite = get_onebody_eff_pot(T, iat, l, n, is, m1_all, m2_all, false); + energy_dc += pot_onsite * this->occ_mat[iat][l][n][is](m1_all, m2_all); } } else if (this->nspin == 4) { - double VU = 0.0; - VU = get_onebody_eff_pot(T, iat, l, n, 0, m1_all, m2_all, false); - energy_dc += VU * this->occ_mat[iat][l][n][0](m1_all, m2_all); + double pot_onsite = 0.0; + pot_onsite = get_onebody_eff_pot(T, iat, l, n, 0, m1_all, m2_all, false); + energy_dc += pot_onsite * this->occ_mat[iat][l][n][0](m1_all, m2_all); } } } @@ -298,30 +283,34 @@ const hamilt::HContainer* Plus_U::get_dmr(int ispin) const } } +namespace DFTU_LCAO { + //! dftu occupation matrix for gamma only using dm(double) template <> -void dftu_cal_occup_m(const int iter, - const UnitCell& ucell, - const std::vector>& dm, - const K_Vectors& kv, - const double& mixing_beta, - hamilt::Hamilt* p_ham, - Plus_U &dftu) +void cal_occ_mat(const int iter, + const UnitCell& ucell, + const std::vector>& dm, + const K_Vectors& kv, + const double& mixing_beta, + hamilt::Hamilt* p_ham, + Plus_U& dftu) { - dftu.cal_occup_m_gamma(iter, ucell ,dm, mixing_beta, p_ham); + dftu.cal_occ_mat_gamma(iter, ucell, dm, mixing_beta, p_ham); } //! dftu occupation matrix for multiple k-points using dm(complex) template <> -void dftu_cal_occup_m(const int iter, - const UnitCell& ucell, - const std::vector>>& dm, - const K_Vectors& kv, - const double& mixing_beta, - hamilt::Hamilt>* p_ham, - Plus_U &dftu) +void cal_occ_mat(const int iter, + const UnitCell& ucell, + const std::vector>>& dm, + const K_Vectors& kv, + const double& mixing_beta, + hamilt::Hamilt>* p_ham, + Plus_U& dftu) { - dftu.cal_occup_m_k(iter,ucell, dm, kv, mixing_beta, p_ham); + dftu.cal_occ_mat_k(iter, ucell, dm, kv, mixing_beta, p_ham); } +} // namespace DFTU_LCAO + #endif diff --git a/source/source_lcao/module_dftu/dftu_lcao.h b/source/source_lcao/module_dftu/dftu_lcao.h index d617814a87..11e5cca0bb 100644 --- a/source/source_lcao/module_dftu/dftu_lcao.h +++ b/source/source_lcao/module_dftu/dftu_lcao.h @@ -1,17 +1,15 @@ -#ifndef DFTU_H -#define DFTU_H +#ifndef DFTU_LCAO_H +#define DFTU_LCAO_H #include "source_cell/klist.h" #include "source_cell/unitcell.h" #include "source_basis/module_ao/parallel_orbitals.h" -#include "source_estate/module_charge/charge_mixing.h" #include "source_pw/module_pwdft/dftu_base.h" #ifdef __LCAO #include "source_basis/module_ao/orb_read.h" #include "source_hamilt/hamilt.h" #include "source_hamilt/module_hcontainer/hcontainer.h" #include "source_estate/module_dm/density_matrix.h" -#include "source_lcao/force_stress_arrays.h" // mohan add 2024-06-15 #endif #include @@ -79,18 +77,6 @@ class Plus_U : public Plus_U_Base // For calculating contribution to Hamiltonian matrices //============================================================= public: - void cal_eff_pot_mat_complex(const int ik, - std::complex* eff_pot, - const std::vector& isk, - const std::complex* sk, - const int npol); - - void cal_eff_pot_mat_real(const int ik, - double* eff_pot, - const std::vector& isk, - const double* sk, - const int npol); - void cal_eff_pot_mat_R_double(const int ispin, double* SR, double* HR, const int npol); void cal_eff_pot_mat_R_complex_double(const int ispin, @@ -101,14 +87,14 @@ class Plus_U : public Plus_U_Base #ifdef __LCAO // calculate the local occupation number matrix - void cal_occup_m_k(const int iter, + void cal_occ_mat_k(const int iter, const UnitCell& ucell, const std::vector>>& dm_k, const K_Vectors& kv, const double& mixing_beta, hamilt::Hamilt>* p_ham); - void cal_occup_m_gamma(const int iter, + void cal_occ_mat_gamma(const int iter, const UnitCell& ucell, const std::vector>& dm_gamma, const double& mixing_beta, @@ -116,16 +102,16 @@ class Plus_U : public Plus_U_Base #endif #ifdef __LCAO -private: //============================================================= // In dftu_tools.cpp // For calculating onsite potential, which is used // for both Hamiltonian and force/stress //============================================================= + public: + void pot_onsite_complex(const int spin, const bool newlocale, std::complex* pot_onsite, const int npol); + void pot_onsite_real(const int spin, const bool newlocale, double* pot_onsite, const int npol); - void cal_VU_pot_mat_complex(const int spin, const bool newlocale, std::complex* VU, const int npol); - void cal_VU_pot_mat_real(const int spin, const bool newlocale, double* VU, const int npol); - + private: double get_onebody_eff_pot(const int T, const int iat, const int L, @@ -135,96 +121,6 @@ class Plus_U : public Plus_U_Base const int m1, const bool newlocale); - //============================================================= - // In dftu_folding.cpp - // Subroutines for folding S and dS matrix - //============================================================= - - void fold_dSR_gamma(const UnitCell& ucell, - const Parallel_Orbitals& pv, - const Grid_Driver* gd, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - double* dh_r, - const int dim1, - const int dim2, - double* dSR_gamma); - - // dim = 0 : S, for Hamiltonian - // dim = 1-3 : dS, for force - // dim = 4-6 : dS * dR, for stress - - void folding_matrix_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const int dim1, - const int dim2, - std::complex* mat_k, - const ModuleBase::Vector3& kvec_d); - - /** - * @brief new function of folding_S_matrix - * only for Hamiltonian now, for force and stress will be developed later - * use HContainer as input and output in mat_k - */ - void folding_matrix_k_new(const int ik, - hamilt::Hamilt>* p_ham); - - //============================================================= - // In dftu_force.cpp - // For calculating force and stress fomr DFT+U - //============================================================= - public: - void force_stress(const UnitCell& ucell, - const Grid_Driver& gd, - std::vector>* dmk_d, - std::vector>>* dmk_c, - const Parallel_Orbitals& pv, - ForceStressArrays& fsr, - ModuleBase::matrix& force_dftu, - ModuleBase::matrix& stress_dftu, - const K_Vectors& kv, - const int npol); - - private: - void cal_force_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const std::complex* rho_VU, - ModuleBase::matrix& force_dftu, - const ModuleBase::Vector3& kvec_d); - - void cal_stress_k(const UnitCell& ucell, - const Grid_Driver& gd, - ForceStressArrays& fsr, - const Parallel_Orbitals& pv, - const int ik, - const std::complex* rho_VU, - ModuleBase::matrix& stress_dftu, - const ModuleBase::Vector3& kvec_d); - - void cal_force_gamma(const UnitCell& ucell, - const double* rho_VU, - const Parallel_Orbitals& pv, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - ModuleBase::matrix& force_dftu); - - void cal_stress_gamma(const UnitCell& ucell, - const Parallel_Orbitals& pv, - const Grid_Driver* gd, - double* dsloc_x, - double* dsloc_y, - double* dsloc_z, - double* dh_r, - const double* rho_VU, - ModuleBase::matrix& stress_dftu); #endif //============================================================= @@ -257,6 +153,16 @@ class Plus_U : public Plus_U_Base void set_dmr(const elecstate::DensityMatrix* dm_in_dftu_d); void set_dmr(const elecstate::DensityMatrix, double>* dm_in_dftu_cd); + /// read-only accessors for state needed by DFTU_LCAO free functions + const Parallel_Orbitals* get_paraV() const { return paraV; } + int get_npol() const { return npol; } + int get_nlocal() const { return nlocal; } + const std::string& get_ks_solver() const { return ks_solver; } + const std::vector& get_orb_cutoff() const { return orb_cutoff_; } + bool is_gamma_only_local() const { return gamma_only_local; } + bool is_cal_force() const { return cal_force; } + bool is_cal_stress() const { return cal_stress; } + private: const UnitCell* ucell = nullptr; const elecstate::DensityMatrix* dm_in_dftu_d = nullptr; @@ -265,16 +171,4 @@ class Plus_U : public Plus_U_Base }; -#ifdef __LCAO -template -void dftu_cal_occup_m(const int iter, - const UnitCell& ucell, - const std::vector>& dm, - const K_Vectors& kv, - const double& mixing_beta, - hamilt::Hamilt* p_ham, - Plus_U &dftu); -#endif - - #endif diff --git a/source/source_lcao/module_dftu/dftu_lcao_op.cpp b/source/source_lcao/module_dftu/dftu_lcao_op.cpp index 9497cacabc..c657bbd1cf 100644 --- a/source/source_lcao/module_dftu/dftu_lcao_op.cpp +++ b/source/source_lcao/module_dftu/dftu_lcao_op.cpp @@ -4,11 +4,7 @@ #include "source_base/tool_title.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" -#include "source_hamilt/module_hcontainer/hcontainer_funcs.h" #include "source_io/module_parameter/parameter.h" -#ifdef _OPENMP -#include -#endif #include "source_base/parallel_reduce.h" template @@ -186,14 +182,14 @@ void hamilt::DFTU>::cal_nlm_all(const Parallel_Orbi * * Uses get_dmr(current_spin) to get real-space density matrix * * Accumulates contributions from all atom pairs via cal_occ() * * Performs MPI reduction to sum occ across processes - * * Stores result via set_occ_mat_flat() for use in VU calculation + * * Stores result via set_occ_mat_flat() for use in pot_onsite calculation * * 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) * - First electronic iteration: uses pre-read occ_mat directly without DMR calculation * * Skips DMR-based occ calculation entirely - * * Reads locale from stored data via get_occ_mat() + * * 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 * @@ -365,26 +361,26 @@ void hamilt::DFTU>::contributeHR() } ModuleBase::timer::end("DFTU", "cal_occ"); - // 3. Calculate Hubbard potential VU from occupation matrix - // VU = U * (1/2 * delta(m,m') - occ(m,m')) for each spin channel + // 3. Calculate Hubbard potential pot_onsite from occupation matrix + // pot_onsite = U * (1/2 * delta(m,m') - occ(m,m')) for each spin channel // Energy: EU = U * 1/2 * occ(m,m') * occ(m',m) - ModuleBase::timer::start("DFTU", "cal_vu"); - const double u_value = this->dftu->u_current[T0]; - std::vector VU_tmp(occ.size()); + ModuleBase::timer::start("DFTU", "cal_pot_onsite"); + const double u_value = this->dftu->get_u_current(T0); + std::vector pot_onsite_tmp(occ.size()); // mohan update 2025-11: get_energy/set_energy are now instance methods // via this->dftu pointer, no longer global static state. double u_energy = this->dftu->get_energy(); - this->cal_v_of_u(occ, tlp1, u_value, VU_tmp.data(), u_energy); + this->cal_pot_onsite(occ, tlp1, u_value, pot_onsite_tmp.data(), u_energy); this->dftu->set_energy(u_energy); - // 4. Convert VU to appropriate data type (real or complex) - // For nspin=4 with complex Hamiltonian, VU needs Pauli matrix transformation - std::vector VU(occ.size()); - this->transfer_vu(VU_tmp, VU); + // 4. Convert pot_onsite to appropriate data type (real or complex) + // For nspin=4 with complex Hamiltonian, pot_onsite needs Pauli matrix transformation + std::vector pot_onsite(occ.size()); + this->transfer_pot_onsite(pot_onsite_tmp, pot_onsite); // 5. Second iteration: Calculate Hamiltonian matrix contribution - // HR += * VU(m,m') * + // HR += * pot_onsite(m,m') * // for all atom pairs within cutoff // Note: different iat0 may contribute to the same HR(iat1, iat2, R), so we need to protect the update // to avoid race conditions in multithreading. Reference: nonlocal.cpp for the atom_row_list pattern. @@ -419,12 +415,12 @@ void hamilt::DFTU>::contributeHR() #pragma omp critical(dftu_hr_update) #endif { - this->cal_HR_IJR(iat1, iat2, paraV, nlm1, nlm2, VU, tmp->get_pointer()); + this->cal_HR_IJR(iat1, iat2, paraV, nlm1, nlm2, pot_onsite, tmp->get_pointer()); } } } } - ModuleBase::timer::end("DFTU", "cal_vu"); + ModuleBase::timer::end("DFTU", "cal_pot_onsite"); } // 6. Post-processing: Energy correction and occ_mat state management @@ -474,7 +470,7 @@ void hamilt::DFTU>::cal_HR_IJR( const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& VU, + const std::vector& pot_onsite, TR* data_pointer) { @@ -487,7 +483,7 @@ void hamilt::DFTU>::cal_HR_IJR( // --------------------------------------------- auto row_indexes = paraV->get_indexes_row(iat1); auto col_indexes = paraV->get_indexes_col(iat2); - const int m_size = int(sqrt(VU.size()) / npol); + const int m_size = int(sqrt(pot_onsite.size()) / npol); // step_trace = 0 for NSPIN=1,2; ={0, 1, local_col, local_col+1} for NSPIN=4 std::vector step_trace(npol * npol, 0); for (int is = 0; is < npol; is++) @@ -516,7 +512,7 @@ void hamilt::DFTU>::cal_HR_IJR( { for (int m2 = 0; m2 < m_size; m2++) { - nlm_tmp += nlm1[m1] * nlm2[m2] * VU[m1 * m_size + m2 + start]; + nlm_tmp += nlm1[m1] * nlm2[m2] * pot_onsite[m1 * m_size + m2 + start]; } } data_pointer[step_trace[is]] += nlm_tmp; @@ -591,24 +587,24 @@ void hamilt::DFTU>::cal_occ(const int& iat1, } template -void hamilt::DFTU>::transfer_vu(std::vector& vu_tmp, std::vector& vu) +void hamilt::DFTU>::transfer_pot_onsite(std::vector& pot_onsite_tmp, std::vector& pot_onsite) { #ifdef __DEBUG - assert(vu.size() == vu_tmp.size()); + assert(pot_onsite.size() == pot_onsite_tmp.size()); #endif - for (int i = 0; i < vu_tmp.size(); i++) + for (int i = 0; i < pot_onsite_tmp.size(); i++) { - vu[i] = vu_tmp[i]; + pot_onsite[i] = pot_onsite_tmp[i]; } } template <> -void hamilt::DFTU, std::complex>>::transfer_vu( - std::vector& vu_tmp, - std::vector>& vu) +void hamilt::DFTU, std::complex>>::transfer_pot_onsite( + std::vector& pot_onsite_tmp, + std::vector>& pot_onsite) { #ifdef __DEBUG - assert(vu.size() == vu_tmp.size()); + assert(pot_onsite.size() == pot_onsite_tmp.size()); #endif // Pauli-to-spinor conversion for DFT+U potential: @@ -619,9 +615,9 @@ void hamilt::DFTU, std::complex, std::complex(0.0, 1.0) * vu_tmp[index[2]]); - vu[index[2]] = 0.5 * (vu_tmp[index[1]] + std::complex(0.0, 1.0) * vu_tmp[index[2]]); + pot_onsite[index[0]] = 0.5 * (pot_onsite_tmp[index[0]] + pot_onsite_tmp[index[3]]); + pot_onsite[index[3]] = 0.5 * (pot_onsite_tmp[index[0]] - pot_onsite_tmp[index[3]]); + pot_onsite[index[1]] = 0.5 * (pot_onsite_tmp[index[1]] - std::complex(0.0, 1.0) * pot_onsite_tmp[index[2]]); + pot_onsite[index[2]] = 0.5 * (pot_onsite_tmp[index[1]] + std::complex(0.0, 1.0) * pot_onsite_tmp[index[2]]); } } } template -void hamilt::DFTU>::cal_v_of_u(const std::vector& occ, +void hamilt::DFTU>::cal_pot_onsite(const std::vector& occ, const int m_size, const double u_value, - double* vu, + double* pot_onsite, double& eu) { // calculate the local matrix @@ -656,7 +652,7 @@ void hamilt::DFTU>::cal_v_of_u(const std::vector>::cal_v_of_u(const std::vector>::cal_v_of_u(const std::vector> : public OperatorLCAO const double* data_pointer, std::vector& occupations); - /// transfer VU format from pauli matrix to normal for non-collinear spin case - void transfer_vu(std::vector& vu_tmp, std::vector& vu); - /// VU_{m, m'} = sum_{m,m'} (1/2*delta_{m, m'} - occ_{m, m'}) * U + /// transfer pot_onsite format from pauli matrix to normal for non-collinear spin case + void transfer_pot_onsite(std::vector& pot_onsite_tmp, std::vector& pot_onsite); + /// pot_onsite_{m, m'} = sum_{m,m'} (1/2*delta_{m, m'} - occ_{m, m'}) * U /// EU = sum_{m,m'} 1/2 * U * occ_{m, m'} * occ_{m', m} - void cal_v_of_u(const std::vector& occ, const int m_size, const double u_value, double* vu, double& eu); + void cal_pot_onsite(const std::vector& occ, const int m_size, const double u_value, double* pot_onsite, double& eu); /** * @brief calculate the HR local matrix of atom pair @@ -113,7 +112,7 @@ class DFTU> : public OperatorLCAO const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, TR* data_pointer); /** @@ -124,7 +123,7 @@ class DFTU> : public OperatorLCAO const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, double* force1, @@ -137,7 +136,7 @@ class DFTU> : public OperatorLCAO const Parallel_Orbitals* paraV, const std::unordered_map>& nlm1_all, const std::unordered_map>& nlm2_all, - const std::vector& vu_in, + const std::vector& pot_onsite_in, const hamilt::BaseMatrix** dmR_pointer, const int nspin, const ModuleBase::Vector3& dis1, diff --git a/source/source_lcao/module_dftu/dftu_lcao_op_legacy.cpp b/source/source_lcao/module_dftu/dftu_lcao_op_legacy.cpp index 643a42f677..ed79940290 100644 --- a/source/source_lcao/module_dftu/dftu_lcao_op_legacy.cpp +++ b/source/source_lcao/module_dftu/dftu_lcao_op_legacy.cpp @@ -1,7 +1,7 @@ #include "dftu_lcao_op_legacy.h" +#include "dftu_hamilt.h" #include "source_base/timer.h" #include "source_base/tool_title.h" -#include "source_lcao/module_dftu/dftu_lcao.h" namespace hamilt { @@ -25,15 +25,15 @@ void OperatorDFTU>::contributeHk(int ik) ModuleBase::TITLE("OperatorDFTU", "contributeHk"); ModuleBase::timer::start("OperatorDFTU", "contributeHk"); // Effective potential of DFT+U is added to total Hamiltonian here; Quxin adds on 20201029 - std::vector eff_pot(this->hsk->get_pv()->nloc); + std::vector pot_uterm(this->hsk->get_pv()->nloc); - this->dftu->cal_eff_pot_mat_real(ik, &eff_pot[0], isk, this->hsk->get_sk(), this->npol); + DFTU_LCAO::pot_uterm_real(*this->dftu, ik, &pot_uterm[0], isk, this->hsk->get_sk(), this->npol); double* hk = this->hsk->get_hk(); for (int irc = 0; irc < this->hsk->get_pv()->nloc; irc++) { - hk[irc] += eff_pot[irc]; + hk[irc] += pot_uterm[irc]; } ModuleBase::timer::end("OperatorDFTU", "contributeHk"); @@ -46,15 +46,15 @@ void OperatorDFTU, double>>::contributeHk(int ModuleBase::timer::start("OperatorDFTU", "contributeHk"); // Effective potential of DFT+U is added to total Hamiltonian here; Quxin adds on 20201029 - std::vector> eff_pot(this->hsk->get_pv()->nloc); + std::vector> pot_uterm(this->hsk->get_pv()->nloc); - this->dftu->cal_eff_pot_mat_complex(ik, &eff_pot[0], isk, this->hsk->get_sk(), this->npol); + DFTU_LCAO::pot_uterm_complex(*this->dftu, ik, &pot_uterm[0], isk, this->hsk->get_sk(), this->npol); std::complex* hk = this->hsk->get_hk(); for (int irc = 0; irc < this->hsk->get_pv()->nloc; irc++) { - hk[irc] += eff_pot[irc]; + hk[irc] += pot_uterm[irc]; } ModuleBase::timer::end("OperatorDFTU", "contributeHk"); @@ -66,14 +66,14 @@ void OperatorDFTU, std::complex>>::con ModuleBase::TITLE("OperatorDFTU", "contributeHk"); ModuleBase::timer::start("OperatorDFTU", "contributeHk"); // Effective potential of DFT+U is added to total Hamiltonian here; Quxin adds on 20201029 - std::vector> eff_pot(this->hsk->get_pv()->nloc); + std::vector> pot_uterm(this->hsk->get_pv()->nloc); - this->dftu->cal_eff_pot_mat_complex(ik, &eff_pot[0], isk, this->hsk->get_sk(), this->npol); + DFTU_LCAO::pot_uterm_complex(*this->dftu, ik, &pot_uterm[0], isk, this->hsk->get_sk(), this->npol); std::complex* hk = this->hsk->get_hk(); for (int irc = 0; irc < this->hsk->get_pv()->nloc; irc++) { - hk[irc] += eff_pot[irc]; + hk[irc] += pot_uterm[irc]; } ModuleBase::timer::end("OperatorDFTU", "contributeHk"); diff --git a/source/source_lcao/module_dftu/dftu_lcao_op_legacy.h b/source/source_lcao/module_dftu/dftu_lcao_op_legacy.h index 8bf8e8260d..8f68592cd8 100644 --- a/source/source_lcao/module_dftu/dftu_lcao_op_legacy.h +++ b/source/source_lcao/module_dftu/dftu_lcao_op_legacy.h @@ -1,7 +1,6 @@ #ifndef OPDFTULCAO_H #define OPDFTULCAO_H -#include "source_base/timer.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" #include "source_lcao/module_dftu/dftu_lcao.h" // mohan add 20251107 diff --git a/source/source_lcao/module_dftu/dftu_occup.cpp b/source/source_lcao/module_dftu/dftu_occup.cpp index ff9c5529ee..1f332797d9 100644 --- a/source/source_lcao/module_dftu/dftu_occup.cpp +++ b/source/source_lcao/module_dftu/dftu_occup.cpp @@ -1,10 +1,10 @@ #include "dftu_lcao.h" +#include "dftu_folding.h" #include "source_base/timer.h" -#include "source_io/module_parameter/parameter.h" +#include "source_base/module_external/scalapack_connector.h" #ifdef __LCAO #include "source_lcao/hamilt_lcao.h" #endif -#include "source_base/module_external/scalapack_connector.h" // copy_occ_mat(), zero_occ_mat(), mix_occ_mat(), set_occ_mat(ucell), // get_occ_mat_flat(), set_occ_mat_flat() @@ -12,15 +12,15 @@ #ifdef __LCAO -void Plus_U::cal_occup_m_k(const int iter, +void Plus_U::cal_occ_mat_k(const int iter, const UnitCell& ucell, const std::vector>>& dm_k, const K_Vectors& kv, const double& mixing_beta, hamilt::Hamilt>* p_ham) { - ModuleBase::TITLE("Plus_U", "cal_occup_m_k"); - ModuleBase::timer::start("Plus_U", "cal_occup_m_k"); + ModuleBase::TITLE("Plus_U", "cal_occ_mat_k"); + ModuleBase::timer::start("Plus_U", "cal_occ_mat_k"); this->copy_occ_mat(ucell); this->zero_occ_mat(ucell); @@ -37,7 +37,7 @@ void Plus_U::cal_occup_m_k(const int iter, for (int ik = 0; ik < kv.get_nks(); ik++) { // srho(mu,nu) = \sum_{iw} S(mu,iw)*dm_k(iw,nu) - this->folding_matrix_k_new(ik, p_ham); + DFTU_LCAO::folding_matrix_k_new(this->ks_solver, this->gamma_only_local, this->nspin, ik, p_ham); std::complex* s_k_pointer = nullptr; @@ -242,18 +242,18 @@ void Plus_U::cal_occup_m_k(const int iter, } mark_occ_mat_initialized(); - ModuleBase::timer::end("Plus_U", "cal_occup_m_k"); + ModuleBase::timer::end("Plus_U", "cal_occ_mat_k"); return; } -void Plus_U::cal_occup_m_gamma(const int iter, +void Plus_U::cal_occ_mat_gamma(const int iter, const UnitCell &ucell, const std::vector> &dm_gamma, const double& mixing_beta, hamilt::Hamilt* p_ham) { - ModuleBase::TITLE("Plus_U", "cal_occup_m_gamma"); - ModuleBase::timer::start("Plus_U", "cal_occup_m_gamma"); + ModuleBase::TITLE("Plus_U", "cal_occ_mat_gamma"); + ModuleBase::timer::start("Plus_U", "cal_occ_mat_gamma"); this->copy_occ_mat(ucell); this->zero_occ_mat(ucell); @@ -399,7 +399,7 @@ void Plus_U::cal_occup_m_gamma(const int iter, } mark_occ_mat_initialized(); - ModuleBase::timer::end("Plus_U", "cal_occup_m_gamma"); + ModuleBase::timer::end("Plus_U", "cal_occ_mat_gamma"); return; } #endif diff --git a/source/source_lcao/module_dftu/dftu_occup.h b/source/source_lcao/module_dftu/dftu_occup.h new file mode 100644 index 0000000000..ceb1564d45 --- /dev/null +++ b/source/source_lcao/module_dftu/dftu_occup.h @@ -0,0 +1,30 @@ +#ifndef DFTU_OCCUP_H +#define DFTU_OCCUP_H + +#include "source_cell/klist.h" +#include "source_cell/unitcell.h" +#include "source_hamilt/hamilt.h" + +#include + +class Plus_U; + +#ifdef __LCAO +namespace DFTU_LCAO { + +/// @brief Compute the occupation matrix and delegate to Plus_U member. +/// Dispatches to Plus_U::cal_occ_mat_gamma (gamma-only, double) or +/// Plus_U::cal_occ_mat_k (multi-k, std::complex) via template. +template +void cal_occ_mat(const int iter, + const UnitCell& ucell, + const std::vector>& dm, + const K_Vectors& kv, + const double& mixing_beta, + hamilt::Hamilt* p_ham, + Plus_U& dftu); + +} // namespace DFTU_LCAO +#endif + +#endif diff --git a/source/source_lcao/module_dftu/dftu_tools.cpp b/source/source_lcao/module_dftu/dftu_tools.cpp index 6e86daeccf..2c69b78c8f 100644 --- a/source/source_lcao/module_dftu/dftu_tools.cpp +++ b/source/source_lcao/module_dftu/dftu_tools.cpp @@ -1,12 +1,10 @@ #include "dftu_lcao.h" -#include "source_base/timer.h" -#include "source_io/module_parameter/parameter.h" #ifdef __LCAO -void Plus_U::cal_VU_pot_mat_complex(const int spin, const bool new_occ_mat, std::complex* VU, const int npol) +void Plus_U::pot_onsite_complex(const int spin, const bool new_occ_mat, std::complex* pot_onsite, const int npol) { - ModuleBase::TITLE("Plus_U", "cal_VU_pot_mat_complex"); - ModuleBase::GlobalFunc::ZEROS(VU, this->paraV->nloc); + ModuleBase::TITLE("Plus_U", "pot_onsite_complex"); + ModuleBase::GlobalFunc::ZEROS(pot_onsite, this->paraV->nloc); for (int it = 0; it < this->ucell->ntype; ++it) { @@ -54,7 +52,7 @@ void Plus_U::cal_VU_pot_mat_complex(const int spin, const bool new_occ_mat, std: int m1_all = m1 + (2 * L + 1) * ipol1; int m2_all = m2 + (2 * L + 1) * ipol2; double val = get_onebody_eff_pot(it, iat, L, n, spin, m1_all, m2_all, new_occ_mat); - VU[nu * this->paraV->nrow + mu] = std::complex(val, 0.0); + pot_onsite[nu * this->paraV->nrow + mu] = std::complex(val, 0.0); } // ipol2 } // m2 } // ipol1 @@ -67,10 +65,10 @@ void Plus_U::cal_VU_pot_mat_complex(const int spin, const bool new_occ_mat, std: return; } -void Plus_U::cal_VU_pot_mat_real(const int spin, const bool new_occ_mat, double* VU, const int npol) +void Plus_U::pot_onsite_real(const int spin, const bool new_occ_mat, double* pot_onsite, const int npol) { - ModuleBase::TITLE("Plus_U", "cal_VU_pot_mat_real"); - ModuleBase::GlobalFunc::ZEROS(VU, this->paraV->nloc); + ModuleBase::TITLE("Plus_U", "pot_onsite_real"); + ModuleBase::GlobalFunc::ZEROS(pot_onsite, this->paraV->nloc); for (int it = 0; it < this->ucell->ntype; ++it) { @@ -117,7 +115,7 @@ void Plus_U::cal_VU_pot_mat_real(const int spin, const bool new_occ_mat, double* int m1_all = m1 + (2 * L + 1) * ipol1; int m2_all = m2 + (2 * L + 1) * ipol2; - VU[nu * this->paraV->nrow + mu] + pot_onsite[nu * this->paraV->nrow + mu] = this->get_onebody_eff_pot(it, iat, L, n, spin, m1_all, m2_all, new_occ_mat); } // ipol2 @@ -143,7 +141,7 @@ double Plus_U::get_onebody_eff_pot(const int T, { ModuleBase::TITLE("Plus_U", "get_onebody_eff_pot"); - double VU = 0.0; + double pot_onsite = 0.0; switch (cal_type) { @@ -158,43 +156,43 @@ double Plus_U::get_onebody_eff_pot(const int T, case 3: // simplified formalism and FLL double counting if (new_occ_mat) { - if (use_yukawa) + if (use_yukawa_) { if (m0 == m1) { - VU = (this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) + pot_onsite = (this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) * (0.5 - this->occ_mat[iat][L][N][spin](m0, m1)); } else { - VU = -(this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) * this->occ_mat[iat][L][N][spin](m0, m1); + pot_onsite = -(this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) * this->occ_mat[iat][L][N][spin](m0, m1); } } else { if (m0 == m1) { - VU = (this->u_current[T]) * (0.5 - this->occ_mat[iat][L][N][spin](m0, m1)); + pot_onsite = (this->u_current[T]) * (0.5 - this->occ_mat[iat][L][N][spin](m0, m1)); } else { - VU = -(this->u_current[T]) * this->occ_mat[iat][L][N][spin](m0, m1); + pot_onsite = -(this->u_current[T]) * this->occ_mat[iat][L][N][spin](m0, m1); } } } else { - if (use_yukawa) + if (use_yukawa_) { if (m0 == m1) { - VU = (this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) + pot_onsite = (this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) * (0.5 - this->occ_mat_save[iat][L][N][spin](m0, m1)); } else { - VU = -(this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) + pot_onsite = -(this->U_Yukawa[T][L][N] - this->J_Yukawa[T][L][N]) * this->occ_mat_save[iat][L][N][spin](m0, m1); } } else { if (m0 == m1) { - VU = (this->u_current[T]) * (0.5 - this->occ_mat_save[iat][L][N][spin](m0, m1)); + pot_onsite = (this->u_current[T]) * (0.5 - this->occ_mat_save[iat][L][N][spin](m0, m1)); } else { - VU = -(this->u_current[T]) * this->occ_mat_save[iat][L][N][spin](m0, m1); + pot_onsite = -(this->u_current[T]) * this->occ_mat_save[iat][L][N][spin](m0, m1); } } } @@ -206,6 +204,6 @@ double Plus_U::get_onebody_eff_pot(const int T, break; } - return VU; + return pot_onsite; } #endif diff --git a/source/source_lcao/module_dftu/dftu_yukawa.cpp b/source/source_lcao/module_dftu/dftu_yukawa.cpp index e743909243..6eadc32c4a 100644 --- a/source/source_lcao/module_dftu/dftu_yukawa.cpp +++ b/source/source_lcao/module_dftu/dftu_yukawa.cpp @@ -1,17 +1,9 @@ #ifdef __LCAO -#include "source_io/module_parameter/parameter.h" #include "source_base/constants.h" #include "source_base/global_function.h" #include "dftu_lcao.h" #include -#include -#include -#include -#include -#include -#include -#include void Plus_U::cal_yukawa_lambda(double** rho, const int& nrxx) @@ -64,7 +56,7 @@ void Plus_U::cal_slater_Fk(const UnitCell& ucell, { ModuleBase::TITLE("Plus_U", "cal_slater_Fk"); - if (use_yukawa) + if (use_yukawa_) { for (int chi = 0; chi < ucell.atoms[T].l_nchi[L]; chi++) { @@ -111,7 +103,7 @@ void Plus_U::cal_slater_Fk(const UnitCell& ucell, void Plus_U::cal_slater_UJ(const UnitCell& ucell, double** rho, const int& nrxx) { ModuleBase::TITLE("Plus_U", "cal_slater_UJ"); - if (!use_yukawa) + if (!use_yukawa_) { return; } diff --git a/source/source_lcao/module_dftu/test/CMakeLists.txt b/source/source_lcao/module_dftu/test/CMakeLists.txt index 506ee79523..bad024242c 100644 --- a/source/source_lcao/module_dftu/test/CMakeLists.txt +++ b/source/source_lcao/module_dftu/test/CMakeLists.txt @@ -4,6 +4,7 @@ AddTest( TARGET dftu_pw_test LIBS base device parameter SOURCES dftu_pw_test.cpp + ../../../source_pw/module_pwdft/dftu_tools_pw.cpp ) AddTest( 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 ab40aded66..60500ac5f0 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. eff_pot_pw_index calculation for mixed atom types and nspin modes + * 1. pot_uterm_pw_index calculation for mixed atom types and nspin modes * 2. copy_occ_mat <-> set_occ_mat roundtrip (3 data layouts) - * 3. VU effective potential formula (cal_type=3, FLL) + * 3. pot_onsite effective potential formula (cal_type=3, FLL) * 4. Energy correction and double-counting terms ***********************************************************************/ // ===================================================================== -// 1. eff_pot_pw_index calculation +// 1. pot_uterm_pw_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 eff_pot_pw_index; + std::vector pot_uterm_pw_index; int pot_index; void compute_indices(const std::vector& atoms, int nspin) { pot_index = 0; - eff_pot_pw_index.resize(atoms.size()); + pot_uterm_pw_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) { - eff_pot_pw_index[i] = pot_index; + pot_uterm_pw_index[i] = pot_index; pot_index += tlp1_npol * tlp1_npol; } else { - eff_pot_pw_index[i] = pot_index; + pot_uterm_pw_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(eff_pot_pw_index[0], 0); - EXPECT_EQ(eff_pot_pw_index[1], 9); - EXPECT_EQ(eff_pot_pw_index[2], 34); + 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(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(eff_pot_pw_index[0], 0); - EXPECT_EQ(eff_pot_pw_index[1], 25); + EXPECT_EQ(pot_uterm_pw_index[0], 0); + EXPECT_EQ(pot_uterm_pw_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(eff_pot_pw_index[0], 0); // d: (5*2)^2 = 100 - EXPECT_EQ(eff_pot_pw_index[1], 100); // p: (3*2)^2 = 36 + 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(pot_index, 136); } @@ -104,81 +104,81 @@ struct Matrix2D { }; static void copy_occ_mat_to_flat( - const std::vector& locale_up, - const std::vector& locale_dn, + const std::vector& occ_mat_up, + const std::vector& occ_mat_dn, std::vector& uom_save, - const std::vector& eff_pot_pw_index, + const std::vector& pot_uterm_pw_index, int nspin) { if (nspin == 4) { - for (size_t iat = 0; iat < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - uom_save[eff_pot_pw_index[iat] + mm] = locale_up[iat].data[mm]; + uom_save[pot_uterm_pw_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 < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) { - uom_save[eff_pot_pw_index[iat] + mm] = locale_up[iat].data[mm]; - uom_save[half_size + eff_pot_pw_index[iat] + mm] = locale_dn[iat].data[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]; } } } else // nspin=1: single spin channel { - for (size_t iat = 0; iat < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - uom_save[eff_pot_pw_index[iat] + mm] = locale_up[iat].data[mm]; + uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat_up[iat].data[mm]; } } } static void set_occ_mat_from_flat( const std::vector& uom_array, - std::vector& locale_up, - std::vector& locale_dn, - const std::vector& eff_pot_pw_index, + std::vector& occ_mat_up, + std::vector& occ_mat_dn, + const std::vector& pot_uterm_pw_index, int nspin) { if (nspin == 4) { - for (size_t iat = 0; iat < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - locale_up[iat].data[mm] = uom_array[eff_pot_pw_index[iat] + mm]; + occ_mat_up[iat].data[mm] = uom_array[pot_uterm_pw_index[iat] + mm]; } } else if (nspin == 2) { int half_size = uom_array.size() / 2; - for (size_t iat = 0; iat < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) { - locale_up[iat].data[mm] = uom_array[eff_pot_pw_index[iat] + mm]; - locale_dn[iat].data[mm] = uom_array[half_size + eff_pot_pw_index[iat] + 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]; } } } else // nspin=1 { - for (size_t iat = 0; iat < locale_up.size(); iat++) + for (size_t iat = 0; iat < occ_mat_up.size(); iat++) { - int size = locale_up[iat].nr * locale_up[iat].nc; + int size = occ_mat_up[iat].nr * occ_mat_up[iat].nc; for (int mm = 0; mm < size; mm++) - locale_up[iat].data[mm] = uom_array[eff_pot_pw_index[iat] + mm]; + occ_mat_up[iat].data[mm] = uom_array[pot_uterm_pw_index[iat] + mm]; } } } @@ -195,38 +195,38 @@ TEST_F(OccMatRoundtripTest, Nspin1and2_SingleAndSplitLayout) const int l = 2; const int size = (2 * l + 1) * (2 * l + 1); // 25 - std::vector locale_up(1, Matrix2D(2 * l + 1, 2 * l + 1)); - std::vector locale_dn(1, Matrix2D(2 * l + 1, 2 * l + 1)); + 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++) - locale_up[0].data[i] = static_cast(i + 1); + occ_mat_up[0].data[i] = static_cast(i + 1); - std::vector eff_pot_pw_index = {0}; + std::vector pot_uterm_pw_index = {0}; std::vector uom_save(size, 0.0); - copy_occ_mat_to_flat(locale_up, locale_dn, uom_save, eff_pot_pw_index, 1); - set_occ_mat_from_flat(uom_save, locale_up, locale_dn, eff_pot_pw_index, 1); + 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); for (int i = 0; i < size; i++) - EXPECT_DOUBLE_EQ(locale_up[0].data[i], static_cast(i + 1)); + 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++) { - locale_up[0].data[i] = static_cast(i + 1); - locale_dn[0].data[i] = static_cast(i + 100); + 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(locale_up, locale_dn, uom_save, eff_pot_pw_index, 2); + copy_occ_mat_to_flat(occ_mat_up, occ_mat_dn, uom_save, pot_uterm_pw_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, locale_up, locale_dn, eff_pot_pw_index, 2); + set_occ_mat_from_flat(uom_save, occ_mat_up, occ_mat_dn, pot_uterm_pw_index, 2); for (int i = 0; i < size; i++) { - EXPECT_DOUBLE_EQ(locale_up[0].data[i], static_cast(i + 1)); - EXPECT_DOUBLE_EQ(locale_dn[0].data[i], static_cast(i + 100)); + 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)); } } @@ -245,77 +245,77 @@ TEST_F(OccMatRoundtripTest, Nspin4_PauliBlocks) } int total = std::accumulate(sizes.begin(), sizes.end(), 0); - std::vector eff_pot_pw_index(specs.size()); + std::vector pot_uterm_pw_index(specs.size()); int offset = 0; for (size_t i = 0; i < specs.size(); i++) { - eff_pot_pw_index[i] = offset; + pot_uterm_pw_index[i] = offset; offset += sizes[i]; } - std::vector locale(specs.size()); + std::vector occ_mat(specs.size()); for (size_t i = 0; i < specs.size(); i++) { int dim = (2 * specs[i].l + 1) * npol; - locale[i] = Matrix2D(dim, dim); + occ_mat[i] = Matrix2D(dim, dim); for (int j = 0; j < sizes[i]; j++) - locale[i].data[j] = static_cast(i * 1000 + j + 1); + occ_mat[i].data[j] = static_cast(i * 1000 + j + 1); } std::vector uom_array(total, 0.0); - std::vector locale_dn(specs.size()); // unused for nspin=4 + std::vector occ_mat_dn(specs.size()); // unused for nspin=4 - copy_occ_mat_to_flat(locale, locale_dn, uom_array, eff_pot_pw_index, 4); - set_occ_mat_from_flat(uom_array, locale, locale_dn, eff_pot_pw_index, 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); for (size_t i = 0; i < specs.size(); i++) for (int j = 0; j < sizes[i]; j++) - EXPECT_DOUBLE_EQ(locale[i].data[j], static_cast(i * 1000 + j + 1)); + EXPECT_DOUBLE_EQ(occ_mat[i].data[j], static_cast(i * 1000 + j + 1)); } // ===================================================================== -// 3. VU effective potential formula (cal_type=3, FLL) +// 3. pot_onsite effective potential formula (cal_type=3, FLL) // -// VU[m0,m1] = U * (0.5*delta(m0,m1) - locale[m0,m1]) (diagonal) -// VU[m0,m1] = -U * locale[m0,m1] (off-diagonal) +// 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) // ===================================================================== -static double compute_vu(double U_val, int m0, int m1, double locale_val) +static double compute_pot_onsite(double U_val, int m0, int m1, double occ_mat_val) { if (m0 == m1) - return U_val * (0.5 - locale_val); + return U_val * (0.5 - occ_mat_val); else - return -U_val * locale_val; + return -U_val * occ_mat_val; } -class VUPotentialTest : public ::testing::Test +class PotOnsitePotentialTest : public ::testing::Test { protected: void SetUp() override {} }; -TEST_F(VUPotentialTest, Diagonal_HalfFilled) +TEST_F(PotOnsitePotentialTest, Diagonal_HalfFilled) { double U = 4.0; - double locale = 0.5; // half-filled - double vu = compute_vu(U, 0, 0, locale); - EXPECT_DOUBLE_EQ(vu, 0.0); // U * (0.5 - 0.5) = 0 + double occ_mat = 0.5; // half-filled + double pot_onsite = compute_pot_onsite(U, 0, 0, occ_mat); + EXPECT_DOUBLE_EQ(pot_onsite, 0.0); // U * (0.5 - 0.5) = 0 } -TEST_F(VUPotentialTest, Diagonal_FullyOccupied) +TEST_F(PotOnsitePotentialTest, Diagonal_FullyOccupied) { double U = 4.0; - double locale = 1.0; // fully occupied - double vu = compute_vu(U, 0, 0, locale); - EXPECT_DOUBLE_EQ(vu, -2.0); // U * (0.5 - 1.0) = -2.0 + double occ_mat = 1.0; // fully occupied + double pot_onsite = compute_pot_onsite(U, 0, 0, occ_mat); + EXPECT_DOUBLE_EQ(pot_onsite, -2.0); // U * (0.5 - 1.0) = -2.0 } -TEST_F(VUPotentialTest, OffDiagonal) +TEST_F(PotOnsitePotentialTest, OffDiagonal) { double U = 5.0; - double locale = 0.3; - double vu = compute_vu(U, 0, 1, locale); - EXPECT_DOUBLE_EQ(vu, -1.5); // -U * locale = -1.5 + double occ_mat = 0.3; + double pot_onsite = compute_pot_onsite(U, 0, 1, occ_mat); + EXPECT_DOUBLE_EQ(pot_onsite, -1.5); // -U * occ_mat = -1.5 } // ===================================================================== @@ -327,14 +327,14 @@ TEST_F(VUPotentialTest, OffDiagonal) class EnergyCorrectionTest : public ::testing::Test { protected: - static double compute_energy(const std::vector& locale_flat, int m_size, double U) + static double compute_energy(const std::vector& occ_mat_flat, int m_size, double U) { double nm_trace = 0.0, nm2_trace = 0.0; for (int m0 = 0; m0 < m_size; m0++) { - nm_trace += locale_flat[m0 * m_size + m0]; + nm_trace += occ_mat_flat[m0 * m_size + m0]; for (int m1 = 0; m1 < m_size; m1++) - nm2_trace += locale_flat[m0 * m_size + m1] * locale_flat[m1 * m_size + m0]; + nm2_trace += occ_mat_flat[m0 * m_size + m1] * occ_mat_flat[m1 * m_size + m0]; } return 0.5 * U * (nm_trace - nm2_trace); } @@ -343,11 +343,11 @@ class EnergyCorrectionTest : public ::testing::Test TEST_F(EnergyCorrectionTest, HalfFilled_DOrbital) { const int m_size = 5; - std::vector locale(m_size * m_size, 0.0); + std::vector occ_mat(m_size * m_size, 0.0); for (int m = 0; m < m_size; m++) - locale[m * m_size + m] = 0.5; + occ_mat[m * m_size + m] = 0.5; - double energy = compute_energy(locale, m_size, 4.0); + double energy = compute_energy(occ_mat, m_size, 4.0); // Tr(n) = 2.5, Tr(n^2) = 1.25, E = 0.5 * 4 * 1.25 = 2.5 EXPECT_DOUBLE_EQ(energy, 2.5); } @@ -355,12 +355,12 @@ TEST_F(EnergyCorrectionTest, HalfFilled_DOrbital) TEST_F(EnergyCorrectionTest, OffDiagonal_Contribution) { const int m_size = 2; - std::vector locale = { + std::vector occ_mat = { 0.3, 0.1, 0.1, 0.3 }; - double energy = compute_energy(locale, m_size, 4.0); + double energy = compute_energy(occ_mat, m_size, 4.0); // Tr(n) = 0.6, Tr(n^2) = 0.3^2 + 0.1^2 + 0.1^2 + 0.3^2 = 0.20 // E = 0.5 * 4 * (0.6 - 0.20) = 0.8 EXPECT_DOUBLE_EQ(energy, 0.8); @@ -368,10 +368,10 @@ TEST_F(EnergyCorrectionTest, OffDiagonal_Contribution) TEST_F(EnergyCorrectionTest, DoubleCounting_Energy) { - // E_dc = sum_{m1,m2,spin} VU[m1,m2] * n[m2,m1] + // E_dc = sum_{m1,m2,spin} pot_onsite[m1,m2] * n[m2,m1] const int m_size = 3; double U = 4.0; - std::vector locale = { + std::vector occ_mat = { 0.5, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2 @@ -381,9 +381,9 @@ TEST_F(EnergyCorrectionTest, DoubleCounting_Energy) for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - double vu = (m1 == m2) ? U * (0.5 - locale[m1 * m_size + m2]) - : -U * locale[m1 * m_size + m2]; - e_dc += vu * locale[m2 * m_size + m1]; + double pot_onsite = (m1 == m2) ? U * (0.5 - occ_mat[m1 * m_size + m2]) + : -U * occ_mat[m1 * m_size + m2]; + e_dc += pot_onsite * occ_mat[m2 * m_size + m1]; } // Only diagonal: m=0: 0*0.5=0, m=1: 0.8*0.3=0.24, m=2: 1.2*0.2=0.24 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 d782609039..f89a4351d7 100644 --- a/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_lcao_test.cpp @@ -111,6 +111,15 @@ class DFTUTest : public ::testing::Test delete[] ucell.atoms; } + // Helper for TEST_F bodies: gtest-derived classes do not inherit + // the friend declaration, so direct dftu.occ_mat[...] access from + // TestBody would fail to compile. This wrapper runs inside + // DFTUTest, which is a friend of Plus_U_Base. + double occ_mat_c(int iat, int spin, int icc) const + { + return dftu.occ_mat[iat][2][0][spin].c[icc]; + } + #ifdef __MPI void init_parav() { @@ -172,7 +181,7 @@ TEST_F(DFTUTest, constructHRd2d) { for (int icc = 0; icc < 25; icc++) { - EXPECT_NEAR(dftu.occ_mat[iat][2][0][0].c[icc], 0.5, 1e-10); + EXPECT_NEAR(occ_mat_c(iat, 0, icc), 0.5, 1e-10); } } // check the value of HR @@ -230,7 +239,7 @@ TEST_F(DFTUTest, constructHRd2cd) { for (int icc = 0; icc < 25; icc++) { - EXPECT_NEAR(dftu.occ_mat[iat][2][0][0].c[icc], 0.5, 1e-10); + EXPECT_NEAR(occ_mat_c(iat, 0, icc), 0.5, 1e-10); } } // check the value of HR @@ -263,7 +272,7 @@ TEST_F(DFTUTest, constructHRd2cd) { for (int icc = 0; icc < 25; icc++) { - EXPECT_NEAR(dftu.occ_mat[iat][2][0][1].c[icc], 0.5, 1e-10); + EXPECT_NEAR(occ_mat_c(iat, 1, icc), 0.5, 1e-10); } } } 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 2856017d41..89a6b39911 100644 --- a/source/source_lcao/module_dftu/test/dftu_operator_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_operator_test.cpp @@ -6,22 +6,22 @@ /*********************************************************************** * Unit tests for DFT+U and DeltaSpin operator math and force/stress. - * Tests cover: cal_v_of_u, transfer_vu, cal_coeff_lambda, + * Tests cover: cal_pot_onsite, transfer_pot_onsite, cal_coeff_lambda, * Force/IJR, Stress/IJR, Voigt->matrix, PW index setup ***********************************************************************/ // ===================================================================== -// 1. cal_v_of_u: Hubbard potential calculation -// nspin=1,2 (spin_fold < 4): VU[is] = U * (0.5*delta - occ^T) +// 1. cal_pot_onsite: Hubbard potential calculation +// nspin=1,2 (spin_fold < 4): pot_onsite[is] = U * (0.5*delta - occ^T) // E_U += U * 0.5 * occ * occ^T -// nspin=4 (spin_fold == 4): VU[0] = U * (1.0*delta - occ^T), VU[is>0] = -U * occ^T +// nspin=4 (spin_fold == 4): pot_onsite[0] = U * (1.0*delta - occ^T), pot_onsite[is>0] = -U * occ^T // E_U += U * 0.25 * occ * occ^T // ===================================================================== -static void cal_v_of_u(const std::vector& occ, int m_size, double u_value, - std::vector& vu, double& eu) +static void cal_pot_onsite(const std::vector& occ, int m_size, double u_value, + std::vector& pot_onsite, double& eu) { - vu.assign(occ.size(), 0.0); + pot_onsite.assign(occ.size(), 0.0); eu = 0.0; int spin_fold = occ.size() / m_size / m_size; if (spin_fold < 4) // nspin=1,2 @@ -32,7 +32,7 @@ static void cal_v_of_u(const std::vector& occ, int m_size, double u_valu for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - vu[start + m1 * m_size + m2] = u_value * (0.5 * (m1 == m2) - occ[start + m2 * m_size + m1]); + pot_onsite[start + m1 * m_size + m2] = u_value * (0.5 * (m1 == m2) - occ[start + m2 * m_size + m1]); eu += u_value * 0.5 * occ[start + m2 * m_size + m1] * occ[start + m1 * m_size + m2]; } } @@ -43,7 +43,7 @@ static void cal_v_of_u(const std::vector& occ, int m_size, double u_valu for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - vu[m1 * m_size + m2] = u_value * (1.0 * (m1 == m2) - occ[m2 * m_size + m1]); + pot_onsite[m1 * m_size + m2] = u_value * (1.0 * (m1 == m2) - occ[m2 * m_size + m1]); eu += u_value * 0.25 * occ[m2 * m_size + m1] * occ[m1 * m_size + m2]; } // is=1,2,3: Pauli off-diagonal blocks @@ -53,7 +53,7 @@ static void cal_v_of_u(const std::vector& occ, int m_size, double u_valu for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - vu[start + m1 * m_size + m2] = u_value * (0.0 - occ[start + m2 * m_size + m1]); + pot_onsite[start + m1 * m_size + m2] = u_value * (0.0 - occ[start + m2 * m_size + m1]); eu += u_value * 0.25 * occ[start + m2 * m_size + m1] * occ[start + m1 * m_size + m2]; } } @@ -65,10 +65,10 @@ class CalVOfUTest : public ::testing::Test { protected: void SetUp() override {} TEST_F(CalVOfUTest, Nspin1_SingleOrbital_HalfFilled) { std::vector occ = {0.5}; - std::vector vu; double eu = 0.0; - cal_v_of_u(occ, 1, 4.0, vu, eu); - // VU = 4*(0.5-0.5)=0, E_U = 4*0.5*0.5*0.5=0.5 - EXPECT_DOUBLE_EQ(vu[0], 0.0); + std::vector pot_onsite; double eu = 0.0; + cal_pot_onsite(occ, 1, 4.0, pot_onsite, eu); + // pot_onsite = 4*(0.5-0.5)=0, E_U = 4*0.5*0.5*0.5=0.5 + EXPECT_DOUBLE_EQ(pot_onsite[0], 0.0); EXPECT_DOUBLE_EQ(eu, 0.5); } @@ -78,11 +78,11 @@ TEST_F(CalVOfUTest, Nspin2_DOrbital_SpinPolarized) std::vector occ(m_size * m_size * 2, 0.0); for (int m = 0; m < m_size; m++) occ[m * m_size + m] = 0.8; // spin-up majority for (int m = 0; m < m_size; m++) occ[m_size*m_size + m*m_size + m] = 0.2; // spin-down minority - std::vector vu; double eu = 0.0; - cal_v_of_u(occ, m_size, 5.0, vu, eu); - // spin-up VU: 5*(0.5-0.8)=-1.5, spin-down VU: 5*(0.5-0.2)=1.5 - for (int m = 0; m < m_size; m++) EXPECT_NEAR(vu[m*m_size+m], -1.5, 1e-14); - for (int m = 0; m < m_size; m++) EXPECT_NEAR(vu[m_size*m_size+m*m_size+m], 1.5, 1e-14); + std::vector pot_onsite; double eu = 0.0; + cal_pot_onsite(occ, m_size, 5.0, pot_onsite, eu); + // spin-up pot_onsite: 5*(0.5-0.8)=-1.5, spin-down pot_onsite: 5*(0.5-0.2)=1.5 + for (int m = 0; m < m_size; m++) EXPECT_NEAR(pot_onsite[m*m_size+m], -1.5, 1e-14); + for (int m = 0; m < m_size; m++) EXPECT_NEAR(pot_onsite[m_size*m_size+m*m_size+m], 1.5, 1e-14); // E_U = 5*0.5*[5*(0.8^2)+5*(0.2^2)] = 8.5 EXPECT_NEAR(eu, 8.5, 1e-14); } @@ -92,72 +92,72 @@ TEST_F(CalVOfUTest, Nspin4_Porbital_PauliBlocks) const int m_size = 3; std::vector occ(m_size * m_size * 4, 0.0); for (int m = 0; m < m_size; m++) occ[m * m_size + m] = 0.5; // Pauli I block - std::vector vu; double eu = 0.0; - cal_v_of_u(occ, m_size, 4.0, vu, eu); - // is=0: VU=4*(1.0-0.5)=2.0, is=1,2,3: VU=0 - for (int m = 0; m < m_size; m++) EXPECT_NEAR(vu[m*m_size+m], 2.0, 1e-14); + std::vector pot_onsite; double eu = 0.0; + cal_pot_onsite(occ, m_size, 4.0, pot_onsite, eu); + // is=0: pot_onsite=4*(1.0-0.5)=2.0, is=1,2,3: pot_onsite=0 + for (int m = 0; m < m_size; m++) EXPECT_NEAR(pot_onsite[m*m_size+m], 2.0, 1e-14); for (int is = 1; is < 4; is++) - for (int i = 0; i < m_size*m_size; i++) EXPECT_NEAR(vu[is*m_size*m_size+i], 0.0, 1e-14); + for (int i = 0; i < m_size*m_size; i++) EXPECT_NEAR(pot_onsite[is*m_size*m_size+i], 0.0, 1e-14); // E_U = 4*0.25*3*(0.5*0.5) = 0.75 EXPECT_NEAR(eu, 0.75, 1e-14); } // ===================================================================== -// 2. transfer_vu: Pauli matrix transformation (nspin=4) -// vu[0] = 0.5*(vu_tmp[0]+vu_tmp[3]) // Pauli I -// vu[3] = 0.5*(vu_tmp[0]-vu_tmp[3]) // Pauli sigma_z -// vu[1] = 0.5*(vu_tmp[1]+i*vu_tmp[2]) // sigma_x+i*sigma_y -// vu[2] = 0.5*(vu_tmp[1]-i*vu_tmp[2]) // sigma_x-i*sigma_y +// 2. transfer_pot_onsite: Pauli matrix transformation (nspin=4) +// pot_onsite[0] = 0.5*(pot_onsite_tmp[0]+pot_onsite_tmp[3]) // Pauli I +// pot_onsite[3] = 0.5*(pot_onsite_tmp[0]-pot_onsite_tmp[3]) // Pauli sigma_z +// pot_onsite[1] = 0.5*(pot_onsite_tmp[1]+i*pot_onsite_tmp[2]) // sigma_x+i*sigma_y +// pot_onsite[2] = 0.5*(pot_onsite_tmp[1]-i*pot_onsite_tmp[2]) // sigma_x-i*sigma_y // ===================================================================== -static void transfer_vu(const std::vector& vu_tmp, - std::vector>& vu) +static void transfer_pot_onsite(const std::vector& pot_onsite_tmp, + std::vector>& pot_onsite) { - const int m_size = int(sqrt(vu_tmp.size()) / 2); + const int m_size = int(sqrt(pot_onsite_tmp.size()) / 2); const int m_size2 = m_size * m_size; - vu.resize(vu_tmp.size()); + pot_onsite.resize(pot_onsite_tmp.size()); for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { int idx[4] = {m1*m_size+m2, m1*m_size+m2+m_size2, m2*m_size+m1+2*m_size2, m2*m_size+m1+3*m_size2}; - vu[idx[0]] = 0.5 * (vu_tmp[idx[0]] + vu_tmp[idx[3]]); - vu[idx[3]] = 0.5 * (vu_tmp[idx[0]] - vu_tmp[idx[3]]); - vu[idx[1]] = 0.5 * (vu_tmp[idx[1]] + std::complex(0,1) * vu_tmp[idx[2]]); - vu[idx[2]] = 0.5 * (vu_tmp[idx[1]] - std::complex(0,1) * vu_tmp[idx[2]]); + pot_onsite[idx[0]] = 0.5 * (pot_onsite_tmp[idx[0]] + pot_onsite_tmp[idx[3]]); + pot_onsite[idx[3]] = 0.5 * (pot_onsite_tmp[idx[0]] - pot_onsite_tmp[idx[3]]); + pot_onsite[idx[1]] = 0.5 * (pot_onsite_tmp[idx[1]] + std::complex(0,1) * pot_onsite_tmp[idx[2]]); + pot_onsite[idx[2]] = 0.5 * (pot_onsite_tmp[idx[1]] - std::complex(0,1) * pot_onsite_tmp[idx[2]]); } } -class TransferVUTest : public ::testing::Test { protected: void SetUp() override {} }; +class Transferpot_onsiteTest : public ::testing::Test { protected: void SetUp() override {} }; -TEST_F(TransferVUTest, PauliI_IdentityInput) +TEST_F(Transferpot_onsiteTest, PauliI_IdentityInput) { - std::vector vu_tmp = {1.0, 0.0, 0.0, 1.0}; - std::vector> vu; - transfer_vu(vu_tmp, vu); - EXPECT_NEAR(vu[0].real(), 1.0, 1e-15); EXPECT_NEAR(vu[0].imag(), 0.0, 1e-15); - EXPECT_NEAR(vu[3].real(), 0.0, 1e-15); + std::vector pot_onsite_tmp = {1.0, 0.0, 0.0, 1.0}; + std::vector> pot_onsite; + transfer_pot_onsite(pot_onsite_tmp, pot_onsite); + EXPECT_NEAR(pot_onsite[0].real(), 1.0, 1e-15); EXPECT_NEAR(pot_onsite[0].imag(), 0.0, 1e-15); + EXPECT_NEAR(pot_onsite[3].real(), 0.0, 1e-15); } -TEST_F(TransferVUTest, PureSigmaZ) +TEST_F(Transferpot_onsiteTest, PureSigmaZ) { - std::vector vu_tmp = {1.0, 0.0, 0.0, -1.0}; - std::vector> vu; - transfer_vu(vu_tmp, vu); - EXPECT_NEAR(vu[0].real(), 0.0, 1e-15); EXPECT_NEAR(vu[3].real(), 1.0, 1e-15); + std::vector pot_onsite_tmp = {1.0, 0.0, 0.0, -1.0}; + std::vector> pot_onsite; + transfer_pot_onsite(pot_onsite_tmp, pot_onsite); + EXPECT_NEAR(pot_onsite[0].real(), 0.0, 1e-15); EXPECT_NEAR(pot_onsite[3].real(), 1.0, 1e-15); } -TEST_F(TransferVUTest, SigmaX_Y_Combined) +TEST_F(Transferpot_onsiteTest, SigmaX_Y_Combined) { - std::vector vu_tmp_x = {0.0, 1.0, 1.0, 0.0}; - std::vector> vu; - transfer_vu(vu_tmp_x, vu); - EXPECT_NEAR(vu[1].real(), 0.5, 1e-15); EXPECT_NEAR(vu[1].imag(), 0.5, 1e-15); - EXPECT_NEAR(vu[2].real(), 0.5, 1e-15); EXPECT_NEAR(vu[2].imag(), -0.5, 1e-15); - - std::vector vu_tmp_y = {0.0, 1.0, -1.0, 0.0}; - transfer_vu(vu_tmp_y, vu); - EXPECT_NEAR(vu[1].real(), 0.5, 1e-15); EXPECT_NEAR(vu[1].imag(), -0.5, 1e-15); - EXPECT_NEAR(vu[2].real(), 0.5, 1e-15); EXPECT_NEAR(vu[2].imag(), 0.5, 1e-15); + std::vector pot_onsite_tmp_x = {0.0, 1.0, 1.0, 0.0}; + std::vector> pot_onsite; + transfer_pot_onsite(pot_onsite_tmp_x, pot_onsite); + EXPECT_NEAR(pot_onsite[1].real(), 0.5, 1e-15); EXPECT_NEAR(pot_onsite[1].imag(), 0.5, 1e-15); + EXPECT_NEAR(pot_onsite[2].real(), 0.5, 1e-15); EXPECT_NEAR(pot_onsite[2].imag(), -0.5, 1e-15); + + std::vector pot_onsite_tmp_y = {0.0, 1.0, -1.0, 0.0}; + transfer_pot_onsite(pot_onsite_tmp_y, pot_onsite); + EXPECT_NEAR(pot_onsite[1].real(), 0.5, 1e-15); EXPECT_NEAR(pot_onsite[1].imag(), -0.5, 1e-15); + EXPECT_NEAR(pot_onsite[2].real(), 0.5, 1e-15); EXPECT_NEAR(pot_onsite[2].imag(), 0.5, 1e-15); } // ===================================================================== @@ -202,12 +202,12 @@ TEST_F(CalCoeffLambdaTest, NonCollinear_General) // ===================================================================== // 4. Force/IJR core loop -// force1 += VU * * * DM -// force2 -= VU * * * DM +// force1 += pot_onsite * * * DM +// force2 -= pot_onsite * * * DM // nlm arrays: [value, deri_x, deri_y, deri_z] // ===================================================================== -static void cal_force_IJR_core(const std::vector& vu_in, +static void cal_force_IJR_core(const std::vector& pot_onsite_in, const std::vector& nlm1, const std::vector& nlm2, const double dm_val, int m_size, int nspin, double force1[3], double force2[3]) { @@ -216,13 +216,13 @@ static void cal_force_IJR_core(const std::vector& vu_in, for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - double vu = vu_in[m1*m_size + m2 + is*m_size2], dm = dm_val; - force1[0] += vu * nlm1[m1+m_size] * nlm2[m2] * dm; - force1[1] += vu * nlm1[m1+2*m_size] * nlm2[m2] * dm; - force1[2] += vu * nlm1[m1+3*m_size] * nlm2[m2] * dm; - force2[0] -= vu * nlm1[m1+m_size] * nlm2[m2] * dm; - force2[1] -= vu * nlm1[m1+2*m_size] * nlm2[m2] * dm; - force2[2] -= vu * nlm1[m1+3*m_size] * nlm2[m2] * dm; + double pot_onsite = pot_onsite_in[m1*m_size + m2 + is*m_size2], dm = dm_val; + force1[0] += pot_onsite * nlm1[m1+m_size] * nlm2[m2] * dm; + force1[1] += pot_onsite * nlm1[m1+2*m_size] * nlm2[m2] * dm; + force1[2] += pot_onsite * nlm1[m1+3*m_size] * nlm2[m2] * dm; + force2[0] -= pot_onsite * nlm1[m1+m_size] * nlm2[m2] * dm; + force2[1] -= pot_onsite * nlm1[m1+2*m_size] * nlm2[m2] * dm; + force2[2] -= pot_onsite * nlm1[m1+3*m_size] * nlm2[m2] * dm; } } @@ -230,30 +230,30 @@ class ForceIJRTest : public ::testing::Test { protected: void SetUp() override { TEST_F(ForceIJRTest, SingleOrbital_SingleSpin) { - std::vector vu = {2.0}, nlm1 = {1.0, 0.1, 0.2, 0.3}, nlm2 = {1.0, 0.0, 0.0, 0.0}; + std::vector pot_onsite = {2.0}, nlm1 = {1.0, 0.1, 0.2, 0.3}, nlm2 = {1.0, 0.0, 0.0, 0.0}; double dm_val = 0.5, force1[3]={0}, force2[3]={0}; - cal_force_IJR_core(vu, nlm1, nlm2, dm_val, 1, 1, force1, force2); - // force = VU*deri(nlm1)*val(nlm2)*DM = 2.0*{0.1,0.2,0.3}*1.0*0.5 = {0.1,0.2,0.3} + cal_force_IJR_core(pot_onsite, nlm1, nlm2, dm_val, 1, 1, force1, force2); + // force = pot_onsite*deri(nlm1)*val(nlm2)*DM = 2.0*{0.1,0.2,0.3}*1.0*0.5 = {0.1,0.2,0.3} EXPECT_NEAR(force1[0], 0.1, 1e-15); EXPECT_NEAR(force1[1], 0.2, 1e-15); EXPECT_NEAR(force1[2], 0.3, 1e-15); EXPECT_NEAR(force2[0], -0.1, 1e-15); EXPECT_NEAR(force2[1], -0.2, 1e-15); EXPECT_NEAR(force2[2], -0.3, 1e-15); } TEST_F(ForceIJRTest, ActionReaction) { - std::vector vu = {1.5}, nlm1 = {1.0, 0.3, 0.4, 0.5}, nlm2 = {1.0, 0.0, 0.0, 0.0}; + std::vector pot_onsite = {1.5}, nlm1 = {1.0, 0.3, 0.4, 0.5}, nlm2 = {1.0, 0.0, 0.0, 0.0}; double dm_val = 1.0, force1[3]={0}, force2[3]={0}; - cal_force_IJR_core(vu, nlm1, nlm2, dm_val, 1, 1, force1, force2); + cal_force_IJR_core(pot_onsite, nlm1, nlm2, dm_val, 1, 1, force1, force2); for (int i = 0; i < 3; i++) EXPECT_NEAR(force1[i], -force2[i], 1e-15); } // ===================================================================== // 5. Stress/IJR core loop -// stress[0]+=VU*DM*(nlm1_dx*dis1.x*nlm2_val+nlm1_val*nlm2_dx*dis2.x) -// stress[3]+=VU*DM*(nlm1_dy*dis1.y*nlm2_val+nlm1_val*nlm2_dy*dis2.y) -// stress[5]+=VU*DM*(nlm1_dz*dis1.z*nlm2_val+nlm1_val*nlm2_dz*dis2.z) +// stress[0]+=pot_onsite*DM*(nlm1_dx*dis1.x*nlm2_val+nlm1_val*nlm2_dx*dis2.x) +// stress[3]+=pot_onsite*DM*(nlm1_dy*dis1.y*nlm2_val+nlm1_val*nlm2_dy*dis2.y) +// stress[5]+=pot_onsite*DM*(nlm1_dz*dis1.z*nlm2_val+nlm1_val*nlm2_dz*dis2.z) // ===================================================================== -static void cal_stress_IJR_core(const std::vector& vu_in, +static void cal_stress_IJR_core(const std::vector& pot_onsite_in, const std::vector& nlm1, const std::vector& nlm2, const double dm_val, int m_size, int nspin, double dis1[3], double dis2[3], double stress[6]) @@ -263,7 +263,7 @@ static void cal_stress_IJR_core(const std::vector& vu_in, for (int m1 = 0; m1 < m_size; m1++) for (int m2 = 0; m2 < m_size; m2++) { - double tmp = vu_in[m1*m_size+m2+is*m_size2] * dm_val; + double tmp = pot_onsite_in[m1*m_size+m2+is*m_size2] * dm_val; stress[0] += tmp*(nlm1[m1+m_size]*dis1[0]*nlm2[m2] + nlm1[m1]*nlm2[m2+m_size]*dis2[0]); stress[1] += tmp*(nlm1[m1+m_size]*dis1[1]*nlm2[m2] + nlm1[m1]*nlm2[m2+m_size]*dis2[1]); stress[2] += tmp*(nlm1[m1+m_size]*dis1[2]*nlm2[m2] + nlm1[m1]*nlm2[m2+m_size]*dis2[2]); @@ -277,9 +277,9 @@ class StressIJRTest : public ::testing::Test { protected: void SetUp() override TEST_F(StressIJRTest, SingleOrbital_XDisplacement) { - std::vector vu = {1.0}, nlm1 = {1.0, 0.1, 0.0, 0.0}, nlm2 = {1.0, 0.2, 0.0, 0.0}; + std::vector pot_onsite = {1.0}, nlm1 = {1.0, 0.1, 0.0, 0.0}, nlm2 = {1.0, 0.2, 0.0, 0.0}; double dm_val = 1.0, dis1[3] = {1.0, 0.0, 0.0}, dis2[3] = {-1.0, 0.0, 0.0}, stress[6] = {0.0}; - cal_stress_IJR_core(vu, nlm1, nlm2, dm_val, 1, 1, dis1, dis2, stress); + cal_stress_IJR_core(pot_onsite, nlm1, nlm2, dm_val, 1, 1, dis1, dis2, stress); // stress[0] = 1.0*(0.1*1.0*1.0 + 1.0*0.2*(-1.0)) = -0.1 EXPECT_NEAR(stress[0], -0.1, 1e-15); EXPECT_NEAR(stress[1], 0.0, 1e-15); EXPECT_NEAR(stress[2], 0.0, 1e-15); @@ -287,9 +287,9 @@ TEST_F(StressIJRTest, SingleOrbital_XDisplacement) TEST_F(StressIJRTest, SymmetricDisplacement) { - std::vector vu = {2.0}, nlm1 = {1.0, 0.1, 0.2, 0.3}, nlm2 = {1.0, 0.1, 0.2, 0.3}; + std::vector pot_onsite = {2.0}, nlm1 = {1.0, 0.1, 0.2, 0.3}, nlm2 = {1.0, 0.1, 0.2, 0.3}; double dm_val = 1.0, dis1[3] = {1.0, 2.0, 3.0}, dis2[3] = {1.0, 2.0, 3.0}, stress[6] = {0.0}; - cal_stress_IJR_core(vu, nlm1, nlm2, dm_val, 1, 1, dis1, dis2, stress); + cal_stress_IJR_core(pot_onsite, nlm1, nlm2, dm_val, 1, 1, dis1, dis2, stress); EXPECT_NEAR(stress[0], 2.0*(0.1*1.0 + 1.0*0.1*1.0), 1e-15); // xx EXPECT_NEAR(stress[4], 2.0*(0.2*3.0 + 1.0*0.2*3.0), 1e-15); // yz } @@ -325,9 +325,9 @@ TEST_F(VoigtToMatrixTest, FullMappingAndSymmetry) } // ===================================================================== -// 7. PW operator index setup (ip_iat, ip_m, vu_begin_iat) +// 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, vu_begin_iat[iat] = VU array offset +// ip_iat[ip] = atom index, pot_onsite_begin_iat[iat] = pot_onsite array offset // ===================================================================== class PWIndexSetupTest : public ::testing::Test @@ -337,10 +337,10 @@ class PWIndexSetupTest : public ::testing::Test void setup_indices(const std::vector& atoms, std::vector& ip_iat, std::vector& ip_m, - std::vector& vu_begin_iat, int& vu_total_size) + std::vector& pot_onsite_begin_iat, int& pot_onsite_total_size) { - int ip0 = 0, vu_begin = 0, npol = 1; - ip_iat.resize(0); ip_m.resize(0); vu_begin_iat.resize(atoms.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); @@ -349,13 +349,13 @@ class PWIndexSetupTest : public ::testing::Test { for (int ip = 0; ip < atom.nh; ip++) { ip_iat[ip0] = static_cast(&atom - &atoms[0]); ip_m[ip0++] = -1; } - vu_begin_iat[&atom - &atoms[0]] = 0; + pot_onsite_begin_iat[&atom - &atoms[0]] = 0; } else { int tlp1 = 2 * atom.target_l + 1; - vu_begin_iat[&atom - &atoms[0]] = vu_begin; - vu_begin += tlp1 * tlp1 * npol * npol; + 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++) @@ -365,28 +365,28 @@ class PWIndexSetupTest : public ::testing::Test } } } - vu_total_size = vu_begin; + 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, vu_begin_iat; int vu_total_size; - setup_indices(atoms, ip_iat, ip_m, vu_begin_iat, vu_total_size); + 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(vu_begin_iat[0], 0); - EXPECT_EQ(vu_total_size, 25); // 5*5 + 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, vu_begin_iat; int vu_total_size; - setup_indices(atoms, ip_iat, ip_m, vu_begin_iat, vu_total_size); + 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); @@ -395,5 +395,5 @@ TEST_F(PWIndexSetupTest, MixedCorrelatedUncorrelated) // 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(vu_total_size, 9); // 3*3 for p-orbital + EXPECT_EQ(pot_onsite_total_size, 9); // 3*3 for p-orbital } 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 5dc811b687..bea2662642 100644 --- a/source/source_lcao/module_dftu/test/dftu_pw_test.cpp +++ b/source/source_lcao/module_dftu/test/dftu_pw_test.cpp @@ -1,8 +1,11 @@ #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_tools_pw.h" /*********************************************************************** * Unit tests for DFT+U PW nspin=1/2/4 support (PR-2) @@ -10,11 +13,11 @@ * Test targets: * 1. Energy weight logic: weight_eu and diag_coeff for nspin=1/2/4 * 2. Becp index logic: different index formulas for nspin=1/2 vs nspin=4 - * 3. VU effective potential: cal_occ_pw VU calculation for all nspin modes + * 3. pot_onsite effective potential: cal_occ_pw pot_onsite calculation for all nspin modes * 4. Energy calculation: E_U accumulation with correct weights * 5. Occupation matrix accumulation from becp: the core loop of cal_occ_pw * 6. Multi-atom split layout: [all_up | all_dn] layout for nspin=2 - * 7. OnsitePsOp kernel: vu application to ps for npol=1 + * 7. OnsitePsOp kernel: pot_onsite application to ps for npol=1 * * Strategy: test energy weights and becp index logic as pure * arithmetic — no need to link against full ABACUS libraries. @@ -64,86 +67,82 @@ TEST_F(DftuPwTest, BecpIndexNspin12vs4) } // ===================================================================== -// VU effective potential tests (cal_occ_pw logic) +// pot_onsite effective potential tests (cal_occ_pw logic) // ===================================================================== -TEST_F(DftuPwTest, VUPotNspin1_DiagonalLocale) +TEST_F(DftuPwTest, PotOnsitePotNspin1_DiagonalLocale) { - // For nspin=1: VU[m1,m2] = U * (0.5*delta(m1,m2) - locale[m2*m_size+m1]) - // With diagonal locale: locale[m,m] = 0.3 + // For nspin=1: pot_onsite[m1,m2] = U * (0.5*delta(m1,m2) - occ_mat[m2*m_size+m1]) + // With diagonal occ_mat: occ_mat[m,m] = 0.3 const double U_val = 4.0; const int m_size = 5; // d-orbital: 2*2+1 const int size = m_size * m_size; - std::vector locale_c(size, 0.0); + std::vector occ_mat_c(size, 0.0); for (int m = 0; m < m_size; m++) - locale_c[m * m_size + m] = 0.3; // diagonal + occ_mat_c[m * m_size + m] = 0.3; // diagonal - std::vector> vu(size, {0.0, 0.0}); - for (int m1 = 0; m1 < m_size; m1++) - for (int m2 = 0; m2 < m_size; m2++) - vu[m1 * m_size + m2] = U_val * (0.5 * (m1 == m2) - locale_c[m2 * m_size + m1]); + std::vector> pot_onsite(size, {0.0, 0.0}); + dftu_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++) - EXPECT_DOUBLE_EQ(vu[m * m_size + m].real(), 0.8); + EXPECT_DOUBLE_EQ(pot_onsite[m * m_size + m].real(), 0.8); // off-diagonal: U*(0 - 0) = 0 - EXPECT_DOUBLE_EQ(vu[0 * m_size + 1].real(), 0.0); - EXPECT_DOUBLE_EQ(vu[1 * m_size + 0].real(), 0.0); + EXPECT_DOUBLE_EQ(pot_onsite[0 * m_size + 1].real(), 0.0); + EXPECT_DOUBLE_EQ(pot_onsite[1 * m_size + 0].real(), 0.0); } -TEST_F(DftuPwTest, VUPotNspin2_TwoSpinChannels) +TEST_F(DftuPwTest, PotOnsitePotNspin2_TwoSpinChannels) { - // nspin=2: two independent spin channels with same formula VU = U*(0.5*delta - locale) + // nspin=2: two independent spin channels with same formula pot_onsite = U*(0.5*delta - occ_mat) const double U_val = 5.0; const int m_size = 3; const int size = m_size * m_size; - std::vector locale_up(size, 0.0); - std::vector locale_dn(size, 0.0); - locale_up[0] = 0.4; // locale_up(0,0) = 0.4 - locale_dn[0] = 0.1; // locale_dn(0,0) = 0.1 + std::vector occ_mat_up(size, 0.0); + std::vector occ_mat_dn(size, 0.0); + occ_mat_up[0] = 0.4; // occ_mat_up(0,0) = 0.4 + occ_mat_dn[0] = 0.1; // occ_mat_dn(0,0) = 0.1 - // VU_up[0,0] = U*(0.5 - 0.4) = 0.5 - double vu_up_00 = U_val * (0.5 - locale_up[0 * m_size + 0]); - EXPECT_DOUBLE_EQ(vu_up_00, 0.5); + std::vector> pot_onsite_up(size, {0.0, 0.0}); + std::vector> pot_onsite_dn(size, {0.0, 0.0}); + dftu_pw::compute_pot_onsite_scalar(pot_onsite_up.data(), occ_mat_up.data(), U_val, 0.5, 0.5, m_size); + dftu_pw::compute_pot_onsite_scalar(pot_onsite_dn.data(), occ_mat_dn.data(), U_val, 0.5, 0.5, m_size); - // VU_dn[0,0] = U*(0.5 - 0.1) = 2.0 - double vu_dn_00 = U_val * (0.5 - locale_dn[0 * m_size + 0]); - EXPECT_DOUBLE_EQ(vu_dn_00, 2.0); + // pot_onsite_up[0,0] = U*(0.5 - 0.4) = 0.5 + EXPECT_DOUBLE_EQ(pot_onsite_up[0].real(), 0.5); + // pot_onsite_dn[0,0] = U*(0.5 - 0.1) = 2.0 + EXPECT_DOUBLE_EQ(pot_onsite_dn[0].real(), 2.0); } -TEST_F(DftuPwTest, VUPotNspin4_PauliTransform) +TEST_F(DftuPwTest, PotOnsitePotNspin4_PauliTransform) { - // nspin=4: after computing VU in Pauli basis, transform to spin basis - // vu_spin[0] = 0.5*(vu_pauli[0] + vu_pauli[3]) - // vu_spin[3] = 0.5*(vu_pauli[0] - vu_pauli[3]) - // vu_spin[1] = 0.5*(vu_pauli[1] + i*vu_pauli[2]) - // vu_spin[2] = 0.5*(vu_pauli[1] - i*vu_pauli[2]) - const int m_size = 3; + // nspin=4: after computing pot_onsite in Pauli basis, transform to spin basis + // pot_onsite_spin[0] = 0.5*(pot_onsite_pauli[0] + pot_onsite_pauli[3]) + // pot_onsite_spin[3] = 0.5*(pot_onsite_pauli[0] - pot_onsite_pauli[3]) + // pot_onsite_spin[1] = 0.5*(pot_onsite_pauli[1] + i*pot_onsite_pauli[2]) + // pot_onsite_spin[2] = 0.5*(pot_onsite_pauli[1] - i*pot_onsite_pauli[2]) + const int m_size = 1; const int size = m_size * m_size; - // For a single (m1,m2) pair, test the Pauli->spin transform - std::complex vu_pauli[4]; - vu_pauli[0] = {1.0, 0.0}; // charge channel - vu_pauli[1] = {0.5, 0.0}; // sigma_x - vu_pauli[2] = {0.3, 0.0}; // sigma_y - vu_pauli[3] = {0.2, 0.0}; // sigma_z - - std::complex vu_spin[4]; - vu_spin[0] = 0.5 * (vu_pauli[0] + vu_pauli[3]); - vu_spin[3] = 0.5 * (vu_pauli[0] - vu_pauli[3]); - vu_spin[1] = 0.5 * (vu_pauli[1] + std::complex(0.0, 1.0) * vu_pauli[2]); - vu_spin[2] = 0.5 * (vu_pauli[1] - std::complex(0.0, 1.0) * vu_pauli[2]); - - EXPECT_DOUBLE_EQ(vu_spin[0].real(), 0.6); // 0.5*(1.0+0.2) - EXPECT_DOUBLE_EQ(vu_spin[0].imag(), 0.0); - EXPECT_DOUBLE_EQ(vu_spin[3].real(), 0.4); // 0.5*(1.0-0.2) - EXPECT_DOUBLE_EQ(vu_spin[3].imag(), 0.0); - EXPECT_DOUBLE_EQ(vu_spin[1].real(), 0.25); // 0.5*0.5 - EXPECT_DOUBLE_EQ(vu_spin[1].imag(), 0.15); // 0.5*0.3 - EXPECT_DOUBLE_EQ(vu_spin[2].real(), 0.25); // 0.5*0.5 - EXPECT_DOUBLE_EQ(vu_spin[2].imag(), -0.15);// -0.5*0.3 + // For a single (m1,m2) pair, test the Pauli->spin transform (in-place) + std::complex pot_onsite[4]; + pot_onsite[0] = {1.0, 0.0}; // charge channel + pot_onsite[1] = {0.5, 0.0}; // sigma_x + pot_onsite[2] = {0.3, 0.0}; // sigma_y + pot_onsite[3] = {0.2, 0.0}; // sigma_z + + dftu_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); + EXPECT_DOUBLE_EQ(pot_onsite[3].real(), 0.4); // 0.5*(1.0-0.2) + EXPECT_DOUBLE_EQ(pot_onsite[3].imag(), 0.0); + EXPECT_DOUBLE_EQ(pot_onsite[1].real(), 0.25); // 0.5*0.5 + EXPECT_DOUBLE_EQ(pot_onsite[1].imag(), 0.15); // 0.5*0.3 + EXPECT_DOUBLE_EQ(pot_onsite[2].real(), 0.25); // 0.5*0.5 + EXPECT_DOUBLE_EQ(pot_onsite[2].imag(), -0.15);// -0.5*0.3 } // ===================================================================== @@ -152,31 +151,33 @@ TEST_F(DftuPwTest, VUPotNspin4_PauliTransform) TEST_F(DftuPwTest, EnergyNspin12_DiagonalLocale) { - // E_U = sum_{m1,m2} U * weight_eu * locale[m2,m1] * locale[m1,m2] + // E_U = sum_{m1,m2} U * weight_eu * occ_mat[m2,m1] * occ_mat[m1,m2] // nspin=1: weight_eu = 1.0, nspin=2: weight_eu = 0.5 const double U_val = 4.0; const int m_size = 3; const int size = m_size * m_size; - std::vector locale_c(size, 0.0); - locale_c[0 * m_size + 0] = 0.5; - locale_c[1 * m_size + 1] = 0.3; - locale_c[2 * m_size + 2] = 0.2; + std::vector occ_mat_c(size, 0.0); + occ_mat_c[0 * m_size + 0] = 0.5; + occ_mat_c[1 * m_size + 1] = 0.3; + occ_mat_c[2 * m_size + 2] = 0.2; // nspin=1: E = U * 1.0 * (0.5^2 + 0.3^2 + 0.2^2) = 4 * 0.38 = 1.52 - double energy_u = 0.0; - for (int m1 = 0; m1 < m_size; m1++) - for (int m2 = 0; m2 < m_size; m2++) - energy_u += U_val * 1.0 * locale_c[m2 * m_size + m1] * locale_c[m1 * m_size + m2]; + std::vector> pot_onsite_nspin1(size, {0.0, 0.0}); + double energy_u = dftu_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); // nspin=2: two spin channels, weight_eu = 0.5 + std::vector occ_mat_up(size, 0.0), occ_mat_dn(size, 0.0); + occ_mat_up[0] = 0.4; occ_mat_dn[0] = 0.6; + std::vector> pot_onsite_up(size, {0.0, 0.0}); + std::vector> pot_onsite_dn(size, {0.0, 0.0}); energy_u = 0.0; - std::vector locale_up(size, 0.0), locale_dn(size, 0.0); - locale_up[0] = 0.4; locale_dn[0] = 0.6; - // Only diagonal element (0,0) is non-zero, so only m1=0, m2=0 contributes - energy_u += U_val * 0.5 * locale_up[0] * locale_up[0]; - energy_u += U_val * 0.5 * locale_dn[0] * locale_dn[0]; + energy_u += dftu_pw::compute_pot_onsite_scalar( + pot_onsite_up.data(), occ_mat_up.data(), U_val, 0.5, 0.5, m_size); + energy_u += dftu_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); } @@ -190,23 +191,17 @@ TEST_F(DftuPwTest, EnergyNspin4_WithOffDiagonal) const double weight_eu = 0.25; // 4 Pauli components stored contiguously - std::vector locale_c(size * 4, 0.0); + std::vector occ_mat_c(size * 4, 0.0); // charge channel (is=0) - locale_c[0] = 0.5; locale_c[1] = 0.1; - locale_c[2] = 0.1; locale_c[3] = 0.5; + occ_mat_c[0] = 0.5; occ_mat_c[1] = 0.1; + occ_mat_c[2] = 0.1; occ_mat_c[3] = 0.5; // sigma_x (is=1) - locale_c[size + 0] = 0.2; locale_c[size + 1] = 0.0; - locale_c[size + 2] = 0.0; locale_c[size + 3] = 0.2; - - double energy_u = 0.0; - for (int is = 0; is < 4; is++) { - int start = is * size; - for (int m1 = 0; m1 < m_size; m1++) - for (int m2 = 0; m2 < m_size; m2++) - energy_u += U_val * weight_eu - * locale_c[start + m2 * m_size + m1] - * locale_c[start + m1 * m_size + m2]; - } + occ_mat_c[size + 0] = 0.2; occ_mat_c[size + 1] = 0.0; + 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_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 // is=1: 2*0.25*(0.2*0.2 + 0 + 0 + 0.2*0.2) = 0.04 @@ -220,33 +215,28 @@ TEST_F(DftuPwTest, EnergyNspin4_WithOffDiagonal) TEST_F(DftuPwTest, LocaleAccumNspin12) { - // nspin=1/2: locale[m1*m_size+m2] += weight * real(conj(becp[m1]) * becp[m2]) - const int m_size = 3, nkb = 5, begin_ih = 0, m_begin = 0, nbands = 2; - const double weights[2] = {1.0, 0.5}; + // nspin=1/2: occ_mat[m1*m_size+m2] += weight * real(conj(becp[m1]) * becp[m2]) + const int m_size = 3, nkb = 5, begin_ih = 0, m_begin = 0, nbands = 2, ik = 0; std::vector> becp(nbands * nkb, {0.0, 0.0}); becp[0 * nkb + 0] = {1.0, 0.0}; becp[0 * nkb + 1] = {0.0, 1.0}; becp[0 * nkb + 2] = {0.5, 0.5}; becp[1 * nkb + 0] = {0.5, 0.0}; becp[1 * nkb + 1] = {0.5, -0.5}; becp[1 * nkb + 2] = {0.0, 1.0}; - std::vector locale_c(m_size * m_size, 0.0); - for (int ib = 0; ib < nbands; ib++) { - int ind_m1m2 = 0; - for (int m1 = 0; m1 < m_size; m1++) { - const int index_m1 = ib * nkb + begin_ih + m_begin + m1; - for (int m2 = 0; m2 < m_size; m2++) { - const int index_m2 = ib * nkb + begin_ih + m_begin + m2; - locale_c[ind_m1m2] += weights[ib] * (std::conj(becp[index_m1]) * becp[index_m2]).real(); - ind_m1m2++; - } - } - } + ModuleBase::matrix wg(1, nbands); + wg(0, 0) = 1.0; + wg(0, 1) = 0.5; - // band0, w=1.0: locale[0,0] = 1.0*|1|^2 = 1.0 - // band1, w=0.5: locale[0,0] = 0.5*|0.5|^2 = 0.125 - EXPECT_DOUBLE_EQ(locale_c[0], 1.125); + std::vector occ_mat_c(m_size * m_size, 0.0); + dftu_pw::accumulate_occ_scalar( + occ_mat_c.data(), becp.data(), nbands, nkb, + begin_ih, m_begin, m_size, wg, ik); - // locale[1,1]: band0 = 1.0*|i|^2 = 1.0, band1 = 0.5*|(0.5,-0.5)|^2 = 0.25 - EXPECT_DOUBLE_EQ(locale_c[4], 1.25); + // band0, w=1.0: occ_mat[0,0] = 1.0*|1|^2 = 1.0 + // band1, w=0.5: occ_mat[0,0] = 0.5*|0.5|^2 = 0.125 + EXPECT_DOUBLE_EQ(occ_mat_c[0], 1.125); + + // occ_mat[1,1]: band0 = 1.0*|i|^2 = 1.0, band1 = 0.5*|(0.5,-0.5)|^2 = 0.25 + EXPECT_DOUBLE_EQ(occ_mat_c[4], 1.25); } TEST_F(DftuPwTest, LocaleAccumNspin4_PauliComponents) @@ -256,46 +246,31 @@ TEST_F(DftuPwTest, LocaleAccumNspin4_PauliComponents) // occ[1] = w * conj(becp_up[m1]) * becp_dn[m2] // occ[2] = w * conj(becp_dn[m1]) * becp_up[m2] // occ[3] = w * conj(becp_dn[m1]) * becp_dn[m2] - // locale[ind] += (occ[0]+occ[3]).real() -- charge - // locale[ind+size] += (occ[1]+occ[2]).real() -- sigma_x - // locale[ind+2*size] += (occ[1]-occ[2]).imag() -- sigma_y - // locale[ind+3*size] += (occ[0]-occ[3]).real() -- sigma_z - const int m_size = 1, nkb = 2, nbands = 1; - const double weight = 1.0; + // occ_mat[ind] += (occ[0]+occ[3]).real() -- charge + // occ_mat[ind+size] += (occ[1]+occ[2]).real() -- sigma_x + // occ_mat[ind+2*size] += (occ[1]-occ[2]).imag() -- sigma_y + // occ_mat[ind+3*size] += (occ[0]-occ[3]).real() -- sigma_z + const int m_size = 1, nkb = 2, nbands = 1, npol = 2, ik = 0; std::vector> becp(nbands * 2 * nkb, {0.0, 0.0}); becp[0] = {0.8, 0.0}; // becp_up[m=0] becp[nkb] = {0.0, 0.6}; // becp_dn[m=0] const int size = m_size * m_size; - std::vector locale_c(size * 4, 0.0); - - for (int ib = 0; ib < nbands; ib++) { - int ind_m1m2 = 0; - for (int m1 = 0; m1 < m_size; m1++) { - const int index_m1 = ib * 2 * nkb + 0 + m1; - for (int m2 = 0; m2 < m_size; m2++) { - const int index_m2 = ib * 2 * nkb + 0 + m2; - std::complex occ[4]; - occ[0] = weight * std::conj(becp[index_m1]) * becp[index_m2]; - occ[1] = weight * std::conj(becp[index_m1]) * becp[index_m2 + nkb]; - occ[2] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2]; - occ[3] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2 + nkb]; - locale_c[ind_m1m2] += (occ[0] + occ[3]).real(); - locale_c[ind_m1m2 + size] += (occ[1] + occ[2]).real(); - locale_c[ind_m1m2 + 2 * size] += (occ[1] - occ[2]).imag(); - locale_c[ind_m1m2 + 3 * size] += (occ[0] - occ[3]).real(); - ind_m1m2++; - } - } - } + std::vector occ_mat_c(size * 4, 0.0); + + ModuleBase::matrix wg(1, nbands); + wg(0, 0) = 1.0; + dftu_pw::accumulate_occ_spinor( + occ_mat_c.data(), becp.data(), nbands, npol, nkb, + 0, 0, m_size, wg, ik); // becp_up = (0.8, 0), becp_dn = (0, 0.6) // occ[0] = 0.64, occ[1] = (0, 0.48), occ[2] = (0, -0.48), occ[3] = 0.36 - EXPECT_DOUBLE_EQ(locale_c[0], 1.0); // charge: (0.64+0.36).real = 1.0 - EXPECT_DOUBLE_EQ(locale_c[1], 0.0); // sigma_x: (occ1+occ2).real = 0 - EXPECT_DOUBLE_EQ(locale_c[2], 0.96); // sigma_y: (occ1-occ2).imag = 0.96 - EXPECT_DOUBLE_EQ(locale_c[3], 0.28); // sigma_z: (occ0-occ3).real = 0.28 + EXPECT_DOUBLE_EQ(occ_mat_c[0], 1.0); // charge: (0.64+0.36).real = 1.0 + EXPECT_DOUBLE_EQ(occ_mat_c[1], 0.0); // sigma_x: (occ1+occ2).real = 0 + EXPECT_DOUBLE_EQ(occ_mat_c[2], 0.96); // sigma_y: (occ1-occ2).imag = 0.96 + EXPECT_DOUBLE_EQ(occ_mat_c[3], 0.28); // sigma_z: (occ0-occ3).real = 0.28 } // ===================================================================== @@ -310,10 +285,10 @@ 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; - // eff_pot_pw_index: split layout, each atom gets `size` entries - std::vector eff_pot_pw_index = {0, size}; + // pot_uterm_pw_index: split layout, each atom gets `size` entries + std::vector pot_uterm_pw_index = {0, size}; - // Simulate locale values for both atoms + // Simulate occ_mat values for both atoms std::vector loc_up[2], loc_dn[2]; for (int i = 0; i < 2; i++) { loc_up[i].assign(size, 0.0); loc_dn[i].assign(size, 0.0); @@ -327,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[eff_pot_pw_index[iat] + mm] = loc_up[iat][mm]; - uom_array[half_size + eff_pot_pw_index[iat] + mm] = loc_dn[iat][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]; } // Verify split layout: first half = all spin-up, second half = all spin-down @@ -339,32 +314,32 @@ TEST_F(DftuPwTest, MultiAtomSplitLayout_Nspin2) // --- Read back and verify round-trip --- for (int iat = 0; iat < nat; iat++) - EXPECT_DOUBLE_EQ(uom_array[eff_pot_pw_index[iat]], loc_up[iat][0]); + EXPECT_DOUBLE_EQ(uom_array[pot_uterm_pw_index[iat]], loc_up[iat][0]); - // --- VU values in split layout --- + // --- pot_onsite values in split layout --- const double U_val = 5.0; const double diag_coeff = 0.5; - std::vector> eff_pot_pw(total, {0.0, 0.0}); - - // atom 0 spin-up VU - std::complex* vu_up_0 = &eff_pot_pw[0]; - vu_up_0[0] = U_val * (diag_coeff - loc_up[0][0]); - // atom 0 spin-down VU (split layout: offset by half_size) - std::complex* vu_dn_0 = &eff_pot_pw[half_size]; - vu_dn_0[0] = U_val * (diag_coeff - loc_dn[0][0]); - - EXPECT_DOUBLE_EQ(vu_up_0[0].real(), -1.5); // 5*(0.5-0.8) - EXPECT_DOUBLE_EQ(vu_dn_0[0].real(), 1.5); // 5*(0.5-0.2) - - // Verify no overlap between atoms in VU arrays - std::complex* vu_up_1 = &eff_pot_pw[size]; - vu_up_1[0] = U_val * (diag_coeff - loc_up[1][0]); - EXPECT_NE(vu_up_0[0], vu_up_1[0]); + std::vector> pot_uterm_pw(total, {0.0, 0.0}); + + // atom 0 spin-up pot_onsite + std::complex* pot_onsite_up_0 = &pot_uterm_pw[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]; + 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]; + 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]); } // ===================================================================== // OnsitePsOp kernel test (simplified npol=1 branch) -// Tests the vu application to ps without full ABACUS integration +// Tests the pot_onsite application to ps without full ABACUS integration // ===================================================================== TEST_F(DftuPwTest, OnsitePsOpKernel_Nspin2_Npol1) @@ -372,15 +347,15 @@ TEST_F(DftuPwTest, OnsitePsOpKernel_Nspin2_Npol1) // Simulate the npol=1 branch of onsite_ps_op kernel const int npm = 4, tnp = 10, orb_l = 2, tlp1 = 2 * orb_l + 1, nat = 2; - // vu array: 2 atoms, each with tlp1*tlp1 = 25 elements - std::vector> vu(nat * tlp1 * tlp1); - for (size_t i = 0; i < vu.size(); i++) - vu[i] = {static_cast(i + 1), 0.0}; + // pot_onsite array: 2 atoms, each with tlp1*tlp1 = 25 elements + std::vector> pot_onsite(nat * tlp1 * tlp1); + for (size_t i = 0; i < pot_onsite.size(); i++) + pot_onsite[i] = {static_cast(i + 1), 0.0}; // ip_m: maps each projector to m index within its atom std::vector ip_m = {0, 1, 2, 3, 4, 0, 1, 2, 3, 4}; std::vector ip_iat = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; - std::vector vu_begin_iat = {0, tlp1 * tlp1}; + std::vector pot_onsite_begin_iat = {0, tlp1 * tlp1}; // becp: npm * tnp std::vector> becp(npm * tnp, {0.0, 0.0}); @@ -397,21 +372,21 @@ TEST_F(DftuPwTest, OnsitePsOpKernel_Nspin2_Npol1) int m1 = ip_m[ip]; if (m1 < 0) continue; int iat = ip_iat[ip]; - const std::complex* vu_iat = vu.data() + vu_begin_iat[iat]; + const std::complex* pot_onsite_iat = pot_onsite.data() + pot_onsite_begin_iat[iat]; int ip2_begin = ip - m1, ip2_end = ip - m1 + tlp1; const int psind = ip * npm + ib; for (int ip2 = ip2_begin; ip2 < ip2_end; ip2++) { int m2 = ip_m[ip2]; - ps[psind] += vu_iat[m1 * tlp1 + m2] * becp[ib * tnp + ip2]; + ps[psind] += pot_onsite_iat[m1 * tlp1 + m2] * becp[ib * tnp + ip2]; } } } // Verify ps[0] (ib=0, ip=0, m1=0, iat=0) - // ps[0] = sum_{ip2=0..4} vu[0*tlp1+ip_m[ip2]] * becp[0*tnp+ip2] + // ps[0] = sum_{ip2=0..4} pot_onsite[0*tlp1+ip_m[ip2]] * becp[0*tnp+ip2] std::complex expected = {0.0, 0.0}; for (int ip2 = 0; ip2 < tlp1; ip2++) - expected += vu[ip2] * becp[ip2]; + expected += pot_onsite[ip2] * becp[ip2]; EXPECT_DOUBLE_EQ(ps[0].real(), expected.real()); EXPECT_DOUBLE_EQ(ps[0].imag(), expected.imag()); } diff --git a/source/source_lcao/setup_dftu_lcao.cpp b/source/source_lcao/setup_dftu_lcao.cpp index 307fb21379..bd8d775fd7 100644 --- a/source/source_lcao/setup_dftu_lcao.cpp +++ b/source/source_lcao/setup_dftu_lcao.cpp @@ -1,5 +1,6 @@ #include "setup_dftu_lcao.h" #include "source_lcao/module_dftu/dftu_lcao.h" +#include "source_lcao/module_dftu/dftu_occup.h" #include "source_pw/module_pwdft/dftu_output.h" // mohan add 2025-11-08 #include "source_estate/module_dm/density_matrix.h" #include "source_lcao/hamilt_lcao.h" @@ -61,10 +62,10 @@ void finish_dftu_lcao(const int iter, /// new DFT+U method calculates energy in Hamiltonian if (dft_plus_u == 2) { - if (dftu_ptr->occ_mat_ctrl != 2) + if (dftu_ptr->get_occ_mat_ctrl() != 2) { - dftu_cal_occup_m(iter, ucell, dm_vec, kv, mixing_beta, - static_cast*>(hamilt_lcao_ptr), *dftu_ptr); + DFTU_LCAO::cal_occ_mat(iter, ucell, dm_vec, kv, mixing_beta, + static_cast*>(hamilt_lcao_ptr), *dftu_ptr); } dftu_ptr->cal_energy_correction(ucell, iter); } diff --git a/source/source_pw/module_pwdft/CMakeLists.txt b/source/source_pw/module_pwdft/CMakeLists.txt index 4a4b6d71f6..b4d1616260 100644 --- a/source/source_pw/module_pwdft/CMakeLists.txt +++ b/source/source_pw/module_pwdft/CMakeLists.txt @@ -14,7 +14,8 @@ list(APPEND objects op_pw_exx_pot.cpp dftu_base.cpp dftu_output.cpp - dftu_pw.cpp + dftu_tools_pw.cpp + dftu_cal_occ_pw.cpp setup_pot.cpp setup_pwrho.cpp setup_pwwfc.cpp diff --git a/source/source_pw/module_pwdft/dftu_base.cpp b/source/source_pw/module_pwdft/dftu_base.cpp index abc2d918e8..d54b8dc30e 100644 --- a/source/source_pw/module_pwdft/dftu_base.cpp +++ b/source/source_pw/module_pwdft/dftu_base.cpp @@ -6,11 +6,8 @@ #include "source_base/timer.h" #include "source_io/module_parameter/parameter.h" -#include -#include #include #include -#include #include #include @@ -54,7 +51,7 @@ void Plus_U_Base::init_base(UnitCell& cell, this->nspin = nspin; this->orbital_corr = orbital_corr; - this->use_yukawa = yukawa_potential; + this->use_yukawa_ = yukawa_potential; this->uramping = uramping; this->occ_mat_ctrl = occ_mat_ctrl; this->mixing_dftu = mixing_dftu; @@ -73,7 +70,7 @@ void Plus_U_Base::init_base(UnitCell& cell, this->occ_mat.resize(cell.nat); this->occ_mat_save.resize(cell.nat); - this->eff_pot_pw_index.resize(cell.nat); + this->pot_uterm_pw_index.resize(cell.nat); int pot_index = 0; this->iatlnmipol2iwt.resize(cell.nat); @@ -100,12 +97,12 @@ void Plus_U_Base::init_base(UnitCell& cell, const int elem_size = tlp1 * tlp1; if(nspin == 4) { - this->eff_pot_pw_index[iat] = pot_index; + this->pot_uterm_pw_index[iat] = pot_index; pot_index += tlp1_npol * tlp1_npol; } else { - this->eff_pot_pw_index[iat] = pot_index; + this->pot_uterm_pw_index[iat] = pot_index; pot_index += elem_size; } @@ -174,11 +171,11 @@ void Plus_U_Base::init_base(UnitCell& cell, if (nspin == 2) pot_index *= 2; - this->eff_pot_pw.resize(pot_index, 0.0); + this->pot_uterm_pw.resize(pot_index, 0.0); this->uom_array.resize(pot_index, 0.0); this->uom_save.resize(pot_index, 0.0); - if (use_yukawa) + if (use_yukawa_) { this->Fk.resize(cell.ntype); @@ -247,7 +244,7 @@ void Plus_U_Base::init_base(UnitCell& cell, void Plus_U_Base::uramping_update() { // Yukawa calculates U directly every iteration, no need for ramping - if (use_yukawa) { + if (use_yukawa_) { return; } // if uramping < 0.1, use the original U @@ -272,7 +269,7 @@ void Plus_U_Base::uramping_update() bool Plus_U_Base::u_converged() { // Yukawa calculates U directly every iteration, always considered converged - if (use_yukawa) { + if (use_yukawa_) { return true; } for (int i = 0; i < static_cast(this->u_target.size()); i++) @@ -310,7 +307,7 @@ void Plus_U_Base::copy_occ_mat(const UnitCell& ucell) const int size = occ_mat[iat][target_l][0][0].nr * occ_mat[iat][target_l][0][0].nc; for(int mm=0; mmuom_save[eff_pot_pw_index[iat]+mm] = occ_mat[iat][target_l][0][0].c[mm]; + this->uom_save[pot_uterm_pw_index[iat]+mm] = occ_mat[iat][target_l][0][0].c[mm]; } } } @@ -324,8 +321,8 @@ void Plus_U_Base::copy_occ_mat(const UnitCell& ucell) const int half_size = this->uom_save.size() / 2; for(int mm=0; mmuom_save[eff_pot_pw_index[iat]+mm] = occ_mat[iat][target_l][0][0].c[mm]; - this->uom_save[half_size + eff_pot_pw_index[iat]+mm] = occ_mat[iat][target_l][0][1].c[mm]; + this->uom_save[pot_uterm_pw_index[iat]+mm] = occ_mat[iat][target_l][0][0].c[mm]; + this->uom_save[half_size + pot_uterm_pw_index[iat]+mm] = occ_mat[iat][target_l][0][1].c[mm]; } } } @@ -403,7 +400,7 @@ void Plus_U_Base::mix_occ_mat(const UnitCell& ucell, { for (int mm = 0; mm < size; mm++) { - this->uom_save[eff_pot_pw_index[iat] + mm] = occ_mat[iat][target_l][0][0].c[mm]; + this->uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat[iat][target_l][0][0].c[mm]; } } } @@ -420,8 +417,8 @@ void Plus_U_Base::mix_occ_mat(const UnitCell& ucell, { for (int mm = 0; mm < size; mm++) { - this->uom_save[eff_pot_pw_index[iat] + mm] = occ_mat[iat][target_l][0][0].c[mm]; - this->uom_save[half_size + eff_pot_pw_index[iat] + mm] = occ_mat[iat][target_l][0][1].c[mm]; + this->uom_save[pot_uterm_pw_index[iat] + mm] = occ_mat[iat][target_l][0][0].c[mm]; + this->uom_save[half_size + pot_uterm_pw_index[iat] + mm] = occ_mat[iat][target_l][0][1].c[mm]; } } } @@ -446,17 +443,17 @@ void Plus_U_Base::set_occ_mat(const UnitCell& ucell) if (this->nspin == 4) { for(int mm = 0; mm < occ_mat[iat][l][0][0].nr * occ_mat[iat][l][0][0].nc; mm++) - occ_mat[iat][l][0][0].c[mm] = this->uom_array[eff_pot_pw_index[iat] + mm]; + occ_mat[iat][l][0][0].c[mm] = this->uom_array[pot_uterm_pw_index[iat] + mm]; } else if (this->nspin == 1 || this->nspin == 2) { const int half_size = this->uom_array.size() / 2; for(int mm = 0; mm < occ_mat[iat][l][0][0].nr * occ_mat[iat][l][0][0].nc; mm++) { - occ_mat[iat][l][0][0].c[mm] = this->uom_array[eff_pot_pw_index[iat] + mm]; + occ_mat[iat][l][0][0].c[mm] = this->uom_array[pot_uterm_pw_index[iat] + mm]; if (this->nspin == 2) { - occ_mat[iat][l][0][1].c[mm] = this->uom_array[half_size + eff_pot_pw_index[iat] + mm]; + occ_mat[iat][l][0][1].c[mm] = this->uom_array[half_size + pot_uterm_pw_index[iat] + mm]; } } } @@ -733,6 +730,6 @@ void Plus_U_Base::local_occup_bcast(const UnitCell& ucell, } -// cal_occ_pw() is implemented in source_lcao/module_dftu/dftu_pw.cpp -// as a Plus_U_Base method. It will be relocated to this directory -// in Phase 5 of the class-split refactor. +// cal_occ_pw() is implemented in source_pw/module_pwdft/dftu_cal_occ_pw.cpp +// as a Plus_U_Base method. Pure per-atom kernels live in dftu_tools_pw.{h,cpp} +// as free functions in namespace dftu_pw. diff --git a/source/source_pw/module_pwdft/dftu_base.h b/source/source_pw/module_pwdft/dftu_base.h index 7885f6f8fa..8aa9d455d9 100644 --- a/source/source_pw/module_pwdft/dftu_base.h +++ b/source/source_pw/module_pwdft/dftu_base.h @@ -1,7 +1,6 @@ #ifndef DFTU_BASE_H #define DFTU_BASE_H -#include "source_cell/klist.h" #include "source_cell/unitcell.h" #include "source_estate/module_charge/charge_mixing.h" @@ -9,13 +8,19 @@ #include +class DFTUTest; + class Plus_U_Base { + friend class DFTUTest; + + //============================================================= + // public section + //============================================================= public: Plus_U_Base(); ~Plus_U_Base(); - public: /// allocate relevant data structures (base part, no LCAO types) void init_base(UnitCell& cell, const int npol, @@ -35,16 +40,7 @@ class Plus_U_Base void uramping_update(); bool u_converged(); - std::vector u_current; - std::vector u_target; - std::vector orbital_corr; - double uramping = 0.0; - int occ_mat_ctrl = 0; - int mixing_dftu = 0; - int nspin = 0; - - // --- Accessors --- - + // --- Accessors for U values and orbital configuration --- double get_u_current(int it) const { return u_current[it]; } double get_u_target(int it) const { return u_target[it]; } int get_num_u_types() const { return static_cast(u_current.size()); } @@ -52,6 +48,18 @@ class Plus_U_Base bool has_correlated_orbital(int it) const { return orbital_corr[it] != -1; } const int* get_orbital_corr_data() const { return orbital_corr.data(); } + /// read-only access to the orbital_corr vector (length ntype) + const std::vector& get_orbital_corr_vec() const { return orbital_corr; } + + /// read-only access to the iat->(l,n,m,ipol)->iwt lookup table + const std::vector>>>>& + get_iatlnmipol2iwt() const { return iatlnmipol2iwt; } + + // --- Accessors for DFT+U configuration --- + double get_uramping() const { return uramping; } + int get_occ_mat_ctrl() const { return occ_mat_ctrl; } + bool use_yukawa() const { return use_yukawa_; } + double get_U_Yukawa(int it, int l, int n) const { return U_Yukawa[it][l][n]; } double get_J_Yukawa(int it, int l, int n) const { return J_Yukawa[it][l][n]; } @@ -59,22 +67,9 @@ class Plus_U_Base void set_energy(const double &e) { energy_u = e; } void set_double_energy() { energy_u *= 2.0; } - protected: - double energy_u = 0.0; - - int cal_type = 3; - std::string device; - int kpar = 1; - - // transform between iwt index and it, ia, L, N and m index - std::vector>>>> - iatlnmipol2iwt; - - public: - /// interface for PW base + /// interface for PW basis /// calculate the local occupation number matrix for PW based wave functions - void cal_occ_pw(const int iter, - const void* psi_in, + void cal_occ_pw(const void* psi_in, const ModuleBase::matrix& wg_in, const UnitCell& cell, Charge_Mixing* p_chgmix, @@ -82,17 +77,17 @@ class Plus_U_Base /// get effective potential pointer for the given spin channel (PW basis) /// - /// nspin=1: isk is ignored, returns &eff_pot_pw[0] + /// nspin=1: isk is ignored, returns &pot_uterm_pw[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 &eff_pot_pw[0] (all Pauli blocks) - const std::complex* get_eff_pot_pw_spin(const int isk) const + /// 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 { if (nspin == 2 && isk == 1) { - return eff_pot_pw.data() + eff_pot_pw.size() / 2; + return pot_uterm_pw.data() + pot_uterm_pw.size() / 2; } - return eff_pot_pw.data(); + return pot_uterm_pw.data(); } /// get size of effective potential for a single spin channel (PW basis) @@ -100,28 +95,26 @@ 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_eff_pot_pw_spin() const + int get_size_pot_uterm_pw_spin() const { - return (nspin == 2) ? static_cast(eff_pot_pw.size() / 2) - : static_cast(eff_pot_pw.size()); + return (nspin == 2) ? static_cast(pot_uterm_pw.size() / 2) + : static_cast(pot_uterm_pw.size()); } /// get effective potential matrix for PW base (per-atom, raw index) - /// @deprecated Use get_eff_pot_pw_spin() for nspin-aware access. - [[deprecated("Use get_eff_pot_pw_spin() for nspin-aware access")]] - const std::complex* get_eff_pot_pw(const int iat) const + /// @deprecated Use get_pot_uterm_pw_spin() for nspin-aware access. + [[deprecated("Use get_pot_uterm_pw_spin() for nspin-aware access")]] + const std::complex* get_pot_uterm_pw(const int iat) const { - return &(eff_pot_pw[eff_pot_pw_index[iat]]); + return &(pot_uterm_pw[pot_uterm_pw_index[iat]]); } - int get_size_eff_pot_pw() const + int get_size_pot_uterm_pw() const { - return eff_pot_pw.size(); + return pot_uterm_pw.size(); } // dftu can be calculated only after occ_mat has been initialized - bool occ_mat_initialized = false; - 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; } @@ -129,24 +122,6 @@ class Plus_U_Base bool is_mixing_enabled() const { return mixing_dftu != 0; } void enable_mixing() { mixing_dftu = 1; } - protected: - void copy_occ_mat(const UnitCell& ucell); - void zero_occ_mat(const UnitCell& ucell); - void mix_occ_mat(const UnitCell& ucell, const double& mixing_beta); - void set_occ_mat(const UnitCell& ucell); - - std::vector> eff_pot_pw; - std::vector eff_pot_pw_index; - std::vector uom_array; - std::vector uom_save; - - // Yukawa-related members (base part, no LCAO dependency) - double lambda = 0.0; - std::vector>>> Fk; - std::vector>> U_Yukawa; - std::vector>> J_Yukawa; - - public: /// get occupation matrix element occ_mat[iat][l][n][spin](m1,m2) double get_occ_mat(const int iat, const int l, const int n, const int spin, const int m1, const int m2) const @@ -171,17 +146,71 @@ class Plus_U_Base void set_occ_mat_flat(const int iat, const int l, const int spin, const std::vector& occ); - // local occupancy matrix of the correlated subspace + protected: + // --- U values and orbital configuration (set in init_base) --- + std::vector u_current; + std::vector u_target; + std::vector orbital_corr; + + // --- DFT+U configuration flags --- + double uramping = 0.0; + int occ_mat_ctrl = 0; + int mixing_dftu = 0; + int nspin = 0; + bool use_yukawa_ = false; + + // --- State flags --- + // dftu can be calculated only after occ_mat has been initialized + bool occ_mat_initialized = false; + + // --- Occupation matrices --- std::vector>>> occ_mat; std::vector>>> occ_mat_save; - //============================================================= - // output() and write_occup_m() have been extracted to free functions - // in source_pw/module_pwdft/dftu_output.cpp as dftu_io::output and - // dftu_io::write_occup_m. They access Plus_U_Base via public getters. - // mohan refactored 2025-11-08 - //============================================================= - protected: + // --- Internal state --- + double energy_u = 0.0; + + int cal_type = 3; + std::string device; + int kpar = 1; + + // transform between iwt index and it, ia, L, N and m index + std::vector>>>> + iatlnmipol2iwt; + + void copy_occ_mat(const UnitCell& ucell); + void zero_occ_mat(const UnitCell& ucell); + void mix_occ_mat(const UnitCell& ucell, const double& mixing_beta); + void set_occ_mat(const UnitCell& ucell); + + /// accumulate occ_mat from psi for all k-points (per-device template) + template + void accumulate_occ_one_k(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + const int* isk); + + /// reduce occ_mat across k-pools (per-atom, nspin-aware) + void reduce_occ_mat(const UnitCell& cell); + + /// copy occ_mat to uom_array for mixing (nspin-aware split layout) + void sync_occ_to_uom(const UnitCell& cell); + + /// compute effective potential pot_onsite and DFT+U energy from occ_mat + /// (assumes occ_mat has already been reduced across k-pools) + void compute_eff_pot_and_energy(const UnitCell& cell); + + std::vector> pot_uterm_pw; + std::vector pot_uterm_pw_index; + std::vector uom_array; + std::vector uom_save; + + // Yukawa-related members (base part, no LCAO dependency) + double lambda = 0.0; + std::vector>>> Fk; + std::vector>> U_Yukawa; + std::vector>> J_Yukawa; + void read_occup_m(const UnitCell& ucell, const std::string& fn, const std::string& init_chg, @@ -190,14 +219,6 @@ class Plus_U_Base void local_occup_bcast(const UnitCell& ucell, int nspin, int npol); - - //============================================================= - // In dftu_yukawa.cpp - // Relevant for calculating U using Yukawa potential - //============================================================= - - public: - bool use_yukawa = false; }; diff --git a/source/source_pw/module_pwdft/dftu_cal_occ_pw.cpp b/source/source_pw/module_pwdft/dftu_cal_occ_pw.cpp new file mode 100644 index 0000000000..54848f456c --- /dev/null +++ b/source/source_pw/module_pwdft/dftu_cal_occ_pw.cpp @@ -0,0 +1,269 @@ +#include "source_pw/module_pwdft/dftu_base.h" +#include "source_pw/module_pwdft/dftu_tools_pw.h" +#include "source_pw/module_pwdft/onsite_proj.h" +#include "source_base/parallel_reduce.h" +#include "source_base/global_variable.h" +#include "source_base/timer.h" +#include "source_base/parallel_global.h" + +/// 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. +/// +/// 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 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) +{ + ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); + this->copy_occ_mat(cell); + this->zero_occ_mat(cell); + + if(this->device == "cpu") + { + this->accumulate_occ_one_k(psi_in, wg_in, cell, isk); + } +#if defined(__CUDA) || defined(__ROCM) + else + { + this->accumulate_occ_one_k(psi_in, wg_in, cell, isk); + } +#endif + + // reduce occ_mat across k-pools, then copy to uom_array for mixing + this->reduce_occ_mat(cell); + this->sync_occ_to_uom(cell); + + // mixing + if(is_mixing_enabled() && p_chgmix != nullptr) + { + p_chgmix->mix_uom(this->uom_array, this->uom_save); + this->set_occ_mat(cell); + } + + this->compute_eff_pot_and_energy(cell); + + ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); +} + +/// reduce occ_mat across all k-pools. +/// +/// Each k-pool only accumulates occ_mat contributions from the k-points it +/// owns; this sums them across pools so occ_mat holds the full result. +/// nspin=1: single channel, size elements +/// nspin=2: two channels (spin-up/down) reduced separately +/// nspin=4: 4 Pauli blocks packed contiguously, reduced in one shot +void Plus_U_Base::reduce_occ_mat(const UnitCell& cell) +{ + for(int iat = 0; iat < cell.nat; iat++) + { + const int it = cell.iat2it[iat]; + const int target_l = get_orbital_corr(it); + if(!has_correlated_orbital(it)) + { + continue; + } + const int size = (2 * target_l + 1) * (2 * target_l + 1); + + if(this->nspin != 4) + { + Parallel_Reduce::reduce_double_allpool(this->kpar, + GlobalV::NPROC_IN_POOL, + this->occ_mat[iat][target_l][0][0].c, + size); + if(this->nspin == 2) + { + Parallel_Reduce::reduce_double_allpool(this->kpar, + GlobalV::NPROC_IN_POOL, + this->occ_mat[iat][target_l][0][1].c, + size); + } + } + else + { + Parallel_Reduce::reduce_double_allpool(this->kpar, + GlobalV::NPROC_IN_POOL, + this->occ_mat[iat][target_l][0][0].c, + size * 4); + } + } +} + +/// copy occ_mat to uom_array for mixing. +/// +/// Layout: +/// nspin=1: uom_array[pot_uterm_pw_index[iat] + mm] = occ_mat[...][0][0] +/// nspin=2: split layout [all_up | all_dn], each atom's spin-up in the +/// first half and spin-down in the second half, both indexed by +/// pot_uterm_pw_index[iat] +/// nspin=4: not used here (uom_array mixing only covers nspin=1/2 in the +/// current code path; the nspin=4 branch is a no-op) +void Plus_U_Base::sync_occ_to_uom(const UnitCell& cell) +{ + if(this->uom_array.size() == 0) + { + return; + } + for(int iat = 0; iat < cell.nat; iat++) + { + const int it = cell.iat2it[iat]; + const int target_l = get_orbital_corr(it); + if(!has_correlated_orbital(it)) + { + continue; + } + const int size = (2 * target_l + 1) * (2 * target_l + 1); + + for(int mm = 0; mm < size; mm++) + { + this->uom_array[pot_uterm_pw_index[iat] + mm] = + this->occ_mat[iat][target_l][0][0].c[mm]; + } + if(this->nspin == 2) + { + const int half_size = this->uom_array.size() / 2; + for(int mm = 0; mm < size; mm++) + { + this->uom_array[half_size + pot_uterm_pw_index[iat] + mm] = + this->occ_mat[iat][target_l][0][1].c[mm]; + } + } + } +} + +/// compute effective potential pot_onsite and DFT+U energy from occ_mat. +/// +/// Preconditions: +/// - occ_mat has been accumulated from psi and reduced across k-pools +/// (cal_occ_pw calls this after the reduce + mixing steps). +/// +/// Outputs: +/// - pot_uterm_pw: 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] +/// - energy_u: E_U = sum U * weight_eu * occ(m2,m1) * occ(m1,m2) +void Plus_U_Base::compute_eff_pot_and_energy(const UnitCell& cell) +{ + this->energy_u = 0.0; + const double weight_eu = (this->nspin == 1) ? 1.0 : (this->nspin == 2) ? 0.5 : 0.25; + const double diag_coeff = (this->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 = get_orbital_corr(it); + if(!has_correlated_orbital(it)) + { + continue; + } + const int size = (2 * target_l + 1) * (2 * target_l + 1); + + //update effective potential + const double u_value = this->u_current[it]; + std::complex* pot_onsite_iat = &(this->pot_uterm_pw[this->pot_uterm_pw_index[iat]]); + const int m_size = 2 * target_l + 1; + + if(this->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. + this->energy_u += dftu_pw::compute_pot_onsite_spinor( + pot_onsite_iat, + this->occ_mat[iat][target_l][0][0].c, + u_value, diag_coeff, weight_eu, m_size); + } + else // nspin=1 or nspin=2 + { + // spin-up channel + this->energy_u += dftu_pw::compute_pot_onsite_scalar( + pot_onsite_iat, + this->occ_mat[iat][target_l][0][0].c, + u_value, diag_coeff, weight_eu, m_size); + // spin-down channel for nspin=2 + if(this->nspin == 2) + { + std::complex* pot_onsite_iat1 = &(this->pot_uterm_pw[this->pot_uterm_pw.size()/2 + this->pot_uterm_pw_index[iat]]); + this->energy_u += dftu_pw::compute_pot_onsite_scalar( + pot_onsite_iat1, + this->occ_mat[iat][target_l][0][1].c, + u_value, diag_coeff, weight_eu, m_size); + } + } + } +} + +template +void Plus_U_Base::accumulate_occ_one_k(const void* psi_in, + const ModuleBase::matrix& wg_in, + const UnitCell& cell, + const int* isk) +{ + 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 = (this->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 = get_orbital_corr(it); + if(!has_correlated_orbital(it)) + { + begin_ih += nh; + continue; + } + const int m_begin = target_l * target_l; + const int tlp1 = 2 * target_l + 1; + if(this->nspin == 4) + { + dftu_pw::accumulate_occ_spinor( + this->occ_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 + { + dftu_pw::accumulate_occ_scalar( + this->occ_mat[iat][target_l][0][is].c, + becp, nbands, nkb, begin_ih, m_begin, tlp1, + wg_in, ik); + } + begin_ih += nh; + } + } +} + +// explicit instantiations +template void Plus_U_Base::accumulate_occ_one_k( + const void*, const ModuleBase::matrix&, const UnitCell&, const int*); +#if defined(__CUDA) || defined(__ROCM) +template void Plus_U_Base::accumulate_occ_one_k( + const void*, const ModuleBase::matrix&, const UnitCell&, const int*); +#endif diff --git a/source/source_pw/module_pwdft/dftu_output.cpp b/source/source_pw/module_pwdft/dftu_output.cpp index 0a01b3ec5a..0f2aee7615 100644 --- a/source/source_pw/module_pwdft/dftu_output.cpp +++ b/source/source_pw/module_pwdft/dftu_output.cpp @@ -3,14 +3,12 @@ #include "source_pw/module_pwdft/dftu_base.h" #include "source_base/constants.h" #include "source_base/global_function.h" +#include "source_base/global_variable.h" #include "source_base/timer.h" -#include "source_io/module_parameter/parameter.h" #include -#include #include #include -#include #include // local inline helpers for eigenvalue calculation @@ -113,7 +111,7 @@ void output(const Plus_U_Base& dftu, continue; } - if (!dftu.use_yukawa) + if (!dftu.use_yukawa()) { GlobalV::ofs_running << " Type=" << T+1 << " L=" << L << " ORBITAL=" << 0 << " U=" << dftu.get_u_current(T) * ModuleBase::Ry_to_eV << " eV" << std::endl; diff --git a/source/source_pw/module_pwdft/dftu_pw.cpp b/source/source_pw/module_pwdft/dftu_pw.cpp deleted file mode 100644 index 2a03d47169..0000000000 --- a/source/source_pw/module_pwdft/dftu_pw.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "source_pw/module_pwdft/dftu_base.h" -#include "source_pw/module_pwdft/onsite_proj.h" -#include "source_base/parallel_reduce.h" -#include "source_io/module_parameter/parameter.h" -#include "source_base/timer.h" -#include "source_base/parallel_global.h" - -/// calculate occupation matrix for DFT+U (PW basis) -/// -/// nspin=1 (npol=1): single spin channel; occ_mat[iat][l][n][0] only; -/// eff_pot_pw 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 Plus_U_Base::cal_occ_pw(const int iter, - const void* psi_in, - const ModuleBase::matrix& wg_in, - const UnitCell& cell, - Charge_Mixing* p_chgmix, - const int* isk) -{ - ModuleBase::timer::start("Plus_U_Base", "cal_occ_pw"); - this->copy_occ_mat(cell); - this->zero_occ_mat(cell); - - if(this->device == "cpu") - { - auto* onsite_p = projectors::OnsiteProjector::get_instance(); - const psi::Psi>* psi_p = (const psi::Psi>*)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 = (this->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 = get_orbital_corr(it); - if(!has_correlated_orbital(it)) - { - begin_ih += nh; - continue; - } - const int m_begin = target_l * target_l; - const int tlp1 = 2 * target_l + 1; - const int tlp1_2 = tlp1 * tlp1; - if(this->nspin == 4) - { - for(int ib = 0;ib occ[4]; - occ[0] = weight * conj(becp[index_m1]) * becp[index_m2]; - occ[1] = weight * conj(becp[index_m1]) * becp[index_m2 + nkb]; - occ[2] = weight * conj(becp[index_m1 + nkb]) * becp[index_m2]; - occ[3] = weight * conj(becp[index_m1 + nkb]) * becp[index_m2 + nkb]; - this->occ_mat[iat][target_l][0][0].c[ind_m1m2] += (occ[0] + occ[3]).real(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + tlp1_2] += (occ[1] + occ[2]).real(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + 2 * tlp1_2] += (occ[1] - occ[2]).imag(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + 3 * tlp1_2] += (occ[0] - occ[3]).real(); - ind_m1m2++; - } - } - }// ib - } - else // nspin=1 or nspin=2 - { - for(int ib = 0;ibocc_mat[iat][target_l][0][is].c[ind_m1m2] += weight * (conj(becp[index_m1]) * becp[index_m2]).real(); - ind_m1m2++; - } - } - }// ib - } - begin_ih += nh; - }// iat - - }// ik - } -#if defined(__CUDA) || defined(__ROCM) - else - { - auto* onsite_p = projectors::OnsiteProjector::get_instance(); - const psi::Psi, base_device::DEVICE_GPU>* psi_p = (const psi::Psi, base_device::DEVICE_GPU>*)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 = (this->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 = get_orbital_corr(it); - if(!has_correlated_orbital(it)) - { - begin_ih += nh; - continue; - } - const int m_begin = target_l * target_l; - const int tlp1 = 2 * target_l + 1; - const int tlp1_2 = tlp1 * tlp1; - if(this->nspin == 4) - { - for(int ib = 0;ib occ[4]; - occ[0] = weight * conj(becp[index_m1]) * becp[index_m2]; - occ[1] = weight * conj(becp[index_m1]) * becp[index_m2 + nkb]; - occ[2] = weight * conj(becp[index_m1 + nkb]) * becp[index_m2]; - occ[3] = weight * conj(becp[index_m1 + nkb]) * becp[index_m2 + nkb]; - this->occ_mat[iat][target_l][0][0].c[ind_m1m2] += (occ[0] + occ[3]).real(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + tlp1_2] += (occ[1] + occ[2]).real(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + 2 * tlp1_2] += (occ[1] - occ[2]).imag(); - this->occ_mat[iat][target_l][0][0].c[ind_m1m2 + 3 * tlp1_2] += (occ[0] - occ[3]).real(); - ind_m1m2++; - } - } - }// ib - } - else // nspin=1 or nspin=2 - { - for(int ib = 0;ibocc_mat[iat][target_l][0][is].c[ind_m1m2] += weight * (conj(becp[index_m1]) * becp[index_m2]).real(); - ind_m1m2++; - } - } - }// ib - } - begin_ih += nh; - }// iat - }// ik - } -#endif - - // reduce occ_mat from all k-pools - for(int iat = 0; iat < cell.nat; iat++) - { - const int it = cell.iat2it[iat]; - const int target_l = get_orbital_corr(it); - if(!has_correlated_orbital(it)) - { - continue; - } - const int size = (2 * target_l + 1) * (2 * target_l + 1); - - if(this->nspin != 4) - { - Parallel_Reduce::reduce_double_allpool(this->kpar, - GlobalV::NPROC_IN_POOL, - this->occ_mat[iat][target_l][0][0].c, - size); - if(this->nspin == 2) - { - Parallel_Reduce::reduce_double_allpool(this->kpar, - GlobalV::NPROC_IN_POOL, - this->occ_mat[iat][target_l][0][1].c, - size); - } - } - else - { - Parallel_Reduce::reduce_double_allpool(this->kpar, - GlobalV::NPROC_IN_POOL, - this->occ_mat[iat][target_l][0][0].c, - size * 4); - } - - // save occ_mat matrix for this iat to uom_array - if(this->uom_array.size() != 0) - { - for(int mm=0;mmuom_array[eff_pot_pw_index[iat]+mm] = this->occ_mat[iat][target_l][0][0].c[mm]; - } - if(this->nspin == 2) - { - const int half_size = this->uom_array.size() / 2; - for(int mm=0;mmuom_array[half_size + eff_pot_pw_index[iat]+mm] = this->occ_mat[iat][target_l][0][1].c[mm]; - } - } - } - } - - // mixing - if(is_mixing_enabled() && p_chgmix != nullptr) - { - p_chgmix->mix_uom(this->uom_array, this->uom_save); - this->set_occ_mat(cell); - } - - this->energy_u = 0.0; - const double weight_eu = (this->nspin == 1) ? 1.0 : (this->nspin == 2) ? 0.5 : 0.25; - const double diag_coeff = (this->nspin == 4) ? 1.0 : 0.5; - // calculate VU 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 = get_orbital_corr(it); - if(!has_correlated_orbital(it)) - { - continue; - } - const int size = (2 * target_l + 1) * (2 * target_l + 1); - - //update effective potential - const double u_value = this->u_current[it]; - std::complex* vu_iat = &(this->eff_pot_pw[this->eff_pot_pw_index[iat]]); - const int m_size = 2 * target_l + 1; - - if(this->nspin == 4) - { - for (int m1 = 0; m1 < m_size; m1++) - { - for (int m2 = 0; m2 < m_size; m2++) - { - vu_iat[m1 * m_size + m2] = u_value * - (diag_coeff * (m1 == m2) - this->occ_mat[iat][target_l][0][0].c[m2 * m_size + m1]); - this->energy_u += u_value * weight_eu * this->occ_mat[iat][target_l][0][0].c[m2 * m_size + m1] - * this->occ_mat[iat][target_l][0][0].c[m1 * m_size + m2]; - } - } - for (int is = 1; is < 4; ++is) - { - int start = is * m_size * m_size; - for (int m1 = 0; m1 < m_size; m1++) - { - for (int m2 = 0; m2 < m_size; m2++) - { - vu_iat[start + m1 * m_size + m2] = u_value * - (0 - this->occ_mat[iat][target_l][0][0].c[start + m2 * m_size + m1]); - this->energy_u += u_value * weight_eu - * this->occ_mat[iat][target_l][0][0].c[start + m2 * m_size + m1] - * this->occ_mat[iat][target_l][0][0].c[start + m1 * m_size + m2]; - } - } - } - // transfer from Pauli matrix representation to spin representation - for (int m1 = 0; m1 < m_size; m1++) - { - for (int m2 = 0; m2 < m_size; m2++) - { - int index[4]; - index[0] = m1 * m_size + m2; - index[1] = m1 * m_size + m2 + size; - index[2] = m1 * m_size + m2 + size * 2; - index[3] = m1 * m_size + m2 + size * 3; - std::complex vu_tmp[4]; - for (int i = 0; i < 4; i++) - { - vu_tmp[i] = vu_iat[index[i]]; - } - vu_iat[index[0]] = 0.5 * (vu_tmp[0] + vu_tmp[3]); - vu_iat[index[3]] = 0.5 * (vu_tmp[0] - vu_tmp[3]); - vu_iat[index[1]] = 0.5 * (vu_tmp[1] + std::complex(0.0, 1.0) * vu_tmp[2]); - vu_iat[index[2]] = 0.5 * (vu_tmp[1] - std::complex(0.0, 1.0) * vu_tmp[2]); - } - } - } - else // nspin=1 or nspin=2 - { - // spin-up channel - for (int m1 = 0; m1 < m_size; m1++) - { - for (int m2 = 0; m2 < m_size; m2++) - { - vu_iat[m1 * m_size + m2] = u_value * - (diag_coeff * (m1 == m2) - this->occ_mat[iat][target_l][0][0].c[m2 * m_size + m1]); - this->energy_u += u_value * weight_eu * this->occ_mat[iat][target_l][0][0].c[m2 * m_size + m1] - * this->occ_mat[iat][target_l][0][0].c[m1 * m_size + m2]; - } - } - // spin-down channel for nspin=2 - if(this->nspin == 2) - { - std::complex* vu_iat1 = &(this->eff_pot_pw[this->eff_pot_pw.size()/2 + this->eff_pot_pw_index[iat]]); - for (int m1 = 0; m1 < m_size; m1++) - { - for (int m2 = 0; m2 < m_size; m2++) - { - vu_iat1[m1 * m_size + m2] = u_value * - (diag_coeff * (m1 == m2) - this->occ_mat[iat][target_l][0][1].c[m2 * m_size + m1]); - this->energy_u += u_value * weight_eu * this->occ_mat[iat][target_l][0][1].c[m2 * m_size + m1] - * this->occ_mat[iat][target_l][0][1].c[m1 * m_size + m2]; - } - } - } - } - } - - ModuleBase::timer::end("Plus_U_Base", "cal_occ_pw"); -} diff --git a/source/source_pw/module_pwdft/dftu_tools_pw.cpp b/source/source_pw/module_pwdft/dftu_tools_pw.cpp new file mode 100644 index 0000000000..036d2d8625 --- /dev/null +++ b/source/source_pw/module_pwdft/dftu_tools_pw.cpp @@ -0,0 +1,149 @@ +#include "source_pw/module_pwdft/dftu_tools_pw.h" + +namespace dftu_pw { + +void pauli_to_spin_basis(std::complex* pot_onsite, int m_size) +{ + const int size = m_size * m_size; + for (int m1 = 0; m1 < m_size; m1++) + { + for (int m2 = 0; m2 < m_size; m2++) + { + int index[4]; + index[0] = m1 * m_size + m2; + index[1] = m1 * m_size + m2 + size; + index[2] = m1 * m_size + m2 + size * 2; + index[3] = m1 * m_size + m2 + size * 3; + std::complex pot_onsite_tmp[4]; + for (int i = 0; i < 4; i++) + { + pot_onsite_tmp[i] = pot_onsite[index[i]]; + } + pot_onsite[index[0]] = 0.5 * (pot_onsite_tmp[0] + pot_onsite_tmp[3]); + pot_onsite[index[3]] = 0.5 * (pot_onsite_tmp[0] - pot_onsite_tmp[3]); + pot_onsite[index[1]] = 0.5 * (pot_onsite_tmp[1] + std::complex(0.0, 1.0) * pot_onsite_tmp[2]); + pot_onsite[index[2]] = 0.5 * (pot_onsite_tmp[1] - std::complex(0.0, 1.0) * pot_onsite_tmp[2]); + } + } +} + +double compute_pot_onsite_spinor( + std::complex* pot_onsite, + const double* occ, + double u_value, + double diag_coeff, + double weight_eu, + int m_size) +{ + double energy_u = 0.0; + const int m_size2 = m_size * m_size; + for (int is = 0; is < 4; ++is) + { + int start = is * m_size2; + double diag = (is == 0) ? diag_coeff : 0.0; + for (int m1 = 0; m1 < m_size; m1++) + { + for (int m2 = 0; m2 < m_size; m2++) + { + pot_onsite[start + m1 * m_size + m2] = u_value * + (diag * (m1 == m2) - occ[start + m2 * m_size + m1]); + energy_u += u_value * weight_eu + * occ[start + m2 * m_size + m1] + * occ[start + m1 * m_size + m2]; + } + } + } + pauli_to_spin_basis(pot_onsite, m_size); + return energy_u; +} + +double compute_pot_onsite_scalar( + std::complex* pot_onsite, + const double* occ, + double u_value, + double diag_coeff, + double weight_eu, + int m_size) +{ + double energy_u = 0.0; + for (int m1 = 0; m1 < m_size; m1++) + { + for (int m2 = 0; m2 < m_size; m2++) + { + pot_onsite[m1 * m_size + m2] = u_value * + (diag_coeff * (m1 == m2) - occ[m2 * m_size + m1]); + energy_u += u_value * weight_eu + * occ[m2 * m_size + m1] + * occ[m1 * m_size + m2]; + } + } + return energy_u; +} + +void accumulate_occ_spinor( + double* occ_mat_out, + const std::complex* becp, + int nbands, + int npol, + int nkb, + int begin_ih, + int m_begin, + int tlp1, + const ModuleBase::matrix& wg, + int ik) +{ + const int tlp1_2 = tlp1 * tlp1; + for (int ib = 0; ib < nbands; ib++) + { + const double weight = wg(ik, ib); + int ind_m1m2 = 0; + for (int m1 = 0; m1 < tlp1; m1++) + { + const int index_m1 = ib * npol * nkb + begin_ih + m_begin + m1; + for (int m2 = 0; m2 < tlp1; m2++) + { + const int index_m2 = ib * npol * nkb + begin_ih + m_begin + m2; + std::complex occ[4]; + occ[0] = weight * std::conj(becp[index_m1]) * becp[index_m2]; + occ[1] = weight * std::conj(becp[index_m1]) * becp[index_m2 + nkb]; + occ[2] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2]; + occ[3] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2 + nkb]; + occ_mat_out[ind_m1m2] += (occ[0] + occ[3]).real(); + occ_mat_out[ind_m1m2 + tlp1_2] += (occ[1] + occ[2]).real(); + occ_mat_out[ind_m1m2 + 2 * tlp1_2] += (occ[1] - occ[2]).imag(); + occ_mat_out[ind_m1m2 + 3 * tlp1_2] += (occ[0] - occ[3]).real(); + ind_m1m2++; + } + } + } +} + +void accumulate_occ_scalar( + double* occ_mat_out, + const std::complex* becp, + int nbands, + int nkb, + int begin_ih, + int m_begin, + int tlp1, + const ModuleBase::matrix& wg, + int ik) +{ + for (int ib = 0; ib < nbands; ib++) + { + const double weight = wg(ik, ib); + int ind_m1m2 = 0; + for (int m1 = 0; m1 < tlp1; m1++) + { + const int index_m1 = ib * nkb + begin_ih + m_begin + m1; + for (int m2 = 0; m2 < tlp1; m2++) + { + const int index_m2 = ib * nkb + begin_ih + m_begin + m2; + occ_mat_out[ind_m1m2] += weight * (std::conj(becp[index_m1]) * becp[index_m2]).real(); + ind_m1m2++; + } + } + } +} + +} // namespace dftu_pw diff --git a/source/source_pw/module_pwdft/dftu_tools_pw.h b/source/source_pw/module_pwdft/dftu_tools_pw.h new file mode 100644 index 0000000000..188a5127ce --- /dev/null +++ b/source/source_pw/module_pwdft/dftu_tools_pw.h @@ -0,0 +1,101 @@ +#ifndef DFTU_TOOLS_PW_H +#define DFTU_TOOLS_PW_H + +#include +#include "source_base/matrix.h" + +/// 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_pw.cpp call them after computing per-atom offsets and fetching the +/// relevant member state (occ_mat, pot_uterm_pw, u_current, etc.). +namespace dftu_pw { + +/// transform pot_onsite from Pauli basis to spin basis (in-place, nspin==4 only). +/// +/// pot_onsite points to the per-atom pot_onsite block of size 4 * m_size * m_size, storing +/// 4 contiguous Pauli blocks (is=0 charge, is=1 sigma_x, is=2 sigma_y, +/// is=3 sigma_z). After the transform, the same memory holds the spin +/// representation: +/// pot_onsite[0] <- 0.5 * (pot_onsite_pauli[0] + pot_onsite_pauli[3]) +/// pot_onsite[3*size] <- 0.5 * (pot_onsite_pauli[0] - pot_onsite_pauli[3]) +/// pot_onsite[size] <- 0.5 * (pot_onsite_pauli[1] + i * pot_onsite_pauli[2]) +/// pot_onsite[2*size] <- 0.5 * (pot_onsite_pauli[1] - i * pot_onsite_pauli[2]) +void pauli_to_spin_basis(std::complex* pot_onsite, int m_size); + +/// compute pot_onsite and energy contribution for one atom (nspin==4, spinor). +/// +/// Writes 4 Pauli blocks of pot_onsite into pot_onsite (size 4 * m_size * m_size) and +/// 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]] +/// occ: pointer to occ_mat[iat][target_l][0][0].c (4 Pauli blocks packed) +double compute_pot_onsite_spinor( + std::complex* pot_onsite, + const double* occ, + double u_value, + double diag_coeff, + double weight_eu, + int m_size); + +/// compute pot_onsite and energy contribution for one atom, one spin channel +/// (nspin==1 or nspin==2). Returns the energy_u increment. +/// +/// pot_onsite: pointer to the spin channel's pot_onsite block (size m_size * m_size) +/// occ: pointer to occ_mat[iat][target_l][0][is].c for this channel +double compute_pot_onsite_scalar( + std::complex* pot_onsite, + const double* occ, + double u_value, + double diag_coeff, + double weight_eu, + int m_size); + +/// accumulate occ_mat from becp for one atom, one k-point (nspin==4, spinor). +/// +/// occ_mat_out points to occ_mat[iat][target_l][0][0].c, which packs 4 +/// Pauli blocks contiguously (each of size tlp1*tlp1). The function adds +/// the contributions from all nbands bands for the given k-point. +/// +/// becp: projector-bra overlap for this k-point +/// npol: 2 for spinor (nspin==4) +/// nkb: number of projectors per band per spin +/// begin_ih: offset of this atom's projectors in becp +/// m_begin: offset of the correlated l's first m within the atom's projectors +/// tlp1: 2*target_l + 1 +void accumulate_occ_spinor( + double* occ_mat_out, + const std::complex* becp, + int nbands, + int npol, + int nkb, + int begin_ih, + int m_begin, + int tlp1, + const ModuleBase::matrix& wg, + int ik); + +/// accumulate occ_mat from becp for one atom, one k-point (nspin==1 or 2). +/// +/// occ_mat_out points to occ_mat[iat][target_l][0][is].c, a single channel +/// of size tlp1*tlp1. The caller selects the spin channel by passing the +/// corresponding occ_mat pointer; this function does not need is. +/// Adds contributions from all nbands bands. +/// +/// becp, nbands, nkb, begin_ih, m_begin, tlp1: same as accumulate_occ_spinor +void accumulate_occ_scalar( + double* occ_mat_out, + const std::complex* becp, + int nbands, + int nkb, + int begin_ih, + int m_begin, + int tlp1, + const ModuleBase::matrix& wg, + int ik); + +} // namespace dftu_pw + +#endif 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 cdcd477e82..eb633ec5a1 100644 --- a/source/source_pw/module_pwdft/kernels/cuda/force_op.cu +++ b/source/source_pw/module_pwdft/kernels/cuda/force_op.cu @@ -328,7 +328,7 @@ __global__ void cal_force_onsite(int wg_nc, const int* atom_na, int tpiba, const FPTYPE* d_wg, - const thrust::complex* vu, + const thrust::complex* pot_onsite, const int* orbital_corr, const thrust::complex* becp, const thrust::complex* dbecp, @@ -349,7 +349,7 @@ __global__ void cal_force_onsite(int wg_nc, { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; - vu += npol * npol * tlp1_2 * atom_na[ii]; + pot_onsite += npol * npol * tlp1_2 * atom_na[ii]; } const int ib2 = ib * npol; @@ -371,7 +371,7 @@ __global__ void cal_force_onsite(int wg_nc, FPTYPE tmp = 0; if (npol == 2) { - thrust::complex ps[4] = {vu[mm], vu[mm + tlp1_2], vu[mm + 2 * tlp1_2], vu[mm + 3 * tlp1_2]}; + thrust::complex ps[4] = {pot_onsite[mm], pot_onsite[mm + tlp1_2], pot_onsite[mm + 2 * tlp1_2], pot_onsite[mm + 3 * tlp1_2]}; const thrust::complex dbb0 = conj(dbecp[inkb0]) * becp[inkb2]; const thrust::complex dbb1 = conj(dbecp[inkb0]) * becp[inkb2 + nkb]; const thrust::complex dbb2 = conj(dbecp[inkb0 + nkb]) * becp[inkb2]; @@ -380,14 +380,14 @@ __global__ void cal_force_onsite(int wg_nc, } else { - tmp = -fac * (vu[mm] * conj(dbecp[inkb0]) * becp[inkb2]).real(); + tmp = -fac * (pot_onsite[mm] * conj(dbecp[inkb0]) * becp[inkb2]).real(); } atomicAdd(force + iat * forcenl_nc + ipol, tmp); } } ++iat; sum += nprojs; - vu += npol * npol * tlp1_2; + pot_onsite += npol * npol * tlp1_2; } } @@ -482,7 +482,7 @@ void cal_force_nl_op::operator()(const base_dev const int* atom_na, const FPTYPE& tpiba, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -501,7 +501,7 @@ void cal_force_nl_op::operator()(const base_dev atom_na, tpiba, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), @@ -520,7 +520,7 @@ void cal_force_nl_op::operator()(const base_dev atom_na, tpiba, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), diff --git a/source/source_pw/module_pwdft/kernels/cuda/onsite_op.cu b/source/source_pw/module_pwdft/kernels/cuda/onsite_op.cu index 0c3f0a181a..51aa8f2216 100644 --- a/source/source_pw/module_pwdft/kernels/cuda/onsite_op.cu +++ b/source/source_pw/module_pwdft/kernels/cuda/onsite_op.cu @@ -50,9 +50,9 @@ __global__ void onsite_op(const int npm, const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int tnp, - const thrust::complex* vu, + const thrust::complex* pot_onsite, thrust::complex* ps, const thrust::complex* becp) { @@ -62,7 +62,7 @@ __global__ void onsite_op(const int npm, { const int nbands = npm / npol; int iat = ip_iat[ip]; - const thrust::complex* vu_iat = vu + vu_begin_iat[iat]; + const thrust::complex* pot_onsite_iat = pot_onsite + pot_onsite_begin_iat[iat]; int orb_l = orb_l_iat[iat]; int tlp1 = 2 * orb_l + 1; int tlp1_2 = tlp1 * tlp1; @@ -80,9 +80,9 @@ __global__ void onsite_op(const int npm, const int becpind = ib2 * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind] + vu_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; - ps[psind + 1] += vu_iat[index_mm + tlp1_2 * 1] * becp[becpind] - + vu_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind] + pot_onsite_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; + ps[psind + 1] += pot_onsite_iat[index_mm + tlp1_2 * 1] * becp[becpind] + + pot_onsite_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; } } } @@ -96,7 +96,7 @@ __global__ void onsite_op(const int npm, const int becpind = ib * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind]; } } } @@ -134,9 +134,9 @@ void hamilt::onsite_ps_op::operator()(const bas const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int& tnp, - const std::complex* vu, + const std::complex* pot_onsite, std::complex* ps, const std::complex* becp) { @@ -148,9 +148,9 @@ void hamilt::onsite_ps_op::operator()(const bas orb_l_iat, ip_iat, ip_m, - vu_begin_iat, + pot_onsite_begin_iat, tnp, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), reinterpret_cast*>(ps), // array of data reinterpret_cast*>(becp)); // array of data 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 fcb6190e7c..ea73f8eb28 100644 --- a/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu +++ b/source/source_pw/module_pwdft/kernels/cuda/stress_op.cu @@ -936,7 +936,7 @@ __global__ void cal_stress_onsite( const int *atom_nh, const int *atom_na, const FPTYPE *d_wg, - const thrust::complex *vu, + const thrust::complex *pot_onsite, const int* orbital_corr, const thrust::complex *becp, const thrust::complex *dbecp, @@ -955,7 +955,7 @@ __global__ void cal_stress_onsite( for (int ii = 0; ii < it; ii++) { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; - vu += npol * npol * tlp1_2 * atom_na[ii]; + pot_onsite += npol * npol * tlp1_2 * atom_na[ii]; } FPTYPE stress_var = 0; @@ -973,7 +973,7 @@ __global__ void cal_stress_onsite( const int inkb2 = sum + ip2 + ib2 * nkb; if (npol == 2) { - thrust::complex ps[4] = {vu[mm], vu[mm + tlp1_2], vu[mm + 2 * tlp1_2], vu[mm + 3 * tlp1_2]}; + thrust::complex ps[4] = {pot_onsite[mm], pot_onsite[mm + tlp1_2], pot_onsite[mm + 2 * tlp1_2], pot_onsite[mm + 3 * tlp1_2]}; const thrust::complex dbb0 = conj(dbecp[inkb1]) * becp[inkb2]; const thrust::complex dbb1 = conj(dbecp[inkb1]) * becp[inkb2 + nkb]; const thrust::complex dbb2 = conj(dbecp[inkb1 + nkb]) * becp[inkb2]; @@ -982,12 +982,12 @@ __global__ void cal_stress_onsite( } else { - stress_var -= fac * (vu[mm] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); + stress_var -= fac * (pot_onsite[mm] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); } } ++iat; sum+=nprojs; - vu += npol * npol * tlp1_2; + pot_onsite += npol * npol * tlp1_2; }//ia __syncwarp(); warp_reduce(stress_var); @@ -1073,7 +1073,7 @@ void cal_stress_nl_op::operator()(const base_de const int* atom_nh, const int* atom_na, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -1089,7 +1089,7 @@ void cal_stress_nl_op::operator()(const base_de atom_nh, atom_na, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), @@ -1105,7 +1105,7 @@ void cal_stress_nl_op::operator()(const base_de atom_nh, atom_na, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), diff --git a/source/source_pw/module_pwdft/kernels/force_op.cpp b/source/source_pw/module_pwdft/kernels/force_op.cpp index 35483375c9..e132fdb1cb 100644 --- a/source/source_pw/module_pwdft/kernels/force_op.cpp +++ b/source/source_pw/module_pwdft/kernels/force_op.cpp @@ -297,7 +297,7 @@ struct cal_force_nl_op const int* atom_na, const FPTYPE& tpiba, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -340,7 +340,7 @@ struct cal_force_nl_op std::complex ps[4]; for(int i = 0; i < 4; i++) { - ps[i] = vu[(i * tlp1_2 + m * tlp1 + m2)]; + ps[i] = pot_onsite[(i * tlp1_2 + m * tlp1 + m2)]; } for (int iforce = 0; iforce < 3; iforce++) @@ -361,7 +361,7 @@ struct cal_force_nl_op { const int index0 = iforce * nbands * npol * nkb + ib2 * nkb + inkb; const int index1 = ib2 * nkb + jnkb; - local_force[iforce] -= fac * (vu[(m * tlp1 + m2)] * conj(dbecp[index0]) * becp[index1]).real(); + local_force[iforce] -= fac * (pot_onsite[(m * tlp1 + m2)] * conj(dbecp[index0]) * becp[index1]).real(); } } } @@ -371,7 +371,7 @@ struct cal_force_nl_op force[iat * forcenl_nc + iforce] += local_force[iforce]; } } - vu += npol * npol * tlp1_2;// step for vu + pot_onsite += npol * npol * tlp1_2;// step for pot_onsite } // end ia iat0 += atom_na[it]; sum0 += atom_na[it] * nproj; diff --git a/source/source_pw/module_pwdft/kernels/force_op.h b/source/source_pw/module_pwdft/kernels/force_op.h index b97c6688a6..5ce771fedc 100644 --- a/source/source_pw/module_pwdft/kernels/force_op.h +++ b/source/source_pw/module_pwdft/kernels/force_op.h @@ -125,7 +125,7 @@ struct cal_force_nl_op const int* atom_na, const FPTYPE& tpiba, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -257,7 +257,7 @@ struct cal_force_nl_op const int* atom_na, const FPTYPE& tpiba, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, diff --git a/source/source_pw/module_pwdft/kernels/onsite_op.cpp b/source/source_pw/module_pwdft/kernels/onsite_op.cpp index 8ac4e8fb84..875f3dc9cd 100644 --- a/source/source_pw/module_pwdft/kernels/onsite_op.cpp +++ b/source/source_pw/module_pwdft/kernels/onsite_op.cpp @@ -61,9 +61,9 @@ struct onsite_ps_op const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int& tnp, - const std::complex* vu, + const std::complex* pot_onsite, std::complex* ps, const std::complex* becp) { @@ -80,7 +80,7 @@ struct onsite_ps_op if(m1 < 0) continue; int ib2 = ib * npol; int iat = ip_iat[ip]; - const std::complex* vu_iat = vu + vu_begin_iat[iat]; + const std::complex* pot_onsite_iat = pot_onsite + pot_onsite_begin_iat[iat]; int orb_l = orb_l_iat[iat]; int tlp1 = 2 * orb_l + 1; int tlp1_2 = tlp1 * tlp1; @@ -92,10 +92,10 @@ struct onsite_ps_op const int becpind = ib2 * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind] - + vu_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; - ps[psind + 1] += vu_iat[index_mm + tlp1_2 * 1] * becp[becpind] - + vu_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind] + + pot_onsite_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; + ps[psind + 1] += pot_onsite_iat[index_mm + tlp1_2 * 1] * becp[becpind] + + pot_onsite_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; } } // end ip } // end ib @@ -112,7 +112,7 @@ struct onsite_ps_op int m1 = ip_m[ip]; if(m1 < 0) continue; int iat = ip_iat[ip]; - const std::complex* vu_iat = vu + vu_begin_iat[iat]; + const std::complex* pot_onsite_iat = pot_onsite + pot_onsite_begin_iat[iat]; int orb_l = orb_l_iat[iat]; int tlp1 = 2 * orb_l + 1; int ip2_begin = ip - m1; @@ -123,7 +123,7 @@ struct onsite_ps_op const int becpind = ib * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind]; } } // end ip } // end ib diff --git a/source/source_pw/module_pwdft/kernels/onsite_op.h b/source/source_pw/module_pwdft/kernels/onsite_op.h index 83f3790d6b..5ad221ba3f 100644 --- a/source/source_pw/module_pwdft/kernels/onsite_op.h +++ b/source/source_pw/module_pwdft/kernels/onsite_op.h @@ -24,9 +24,9 @@ struct onsite_ps_op { const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int& tnp, - const std::complex* vu, + const std::complex* pot_onsite, std::complex* ps, const std::complex* becp); }; @@ -52,9 +52,9 @@ struct onsite_ps_op { const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int& tnp, - const std::complex* vu, + const std::complex* pot_onsite, std::complex* ps, const std::complex* becp); }; 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 cd4edf33ec..64c2a68269 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 @@ -314,7 +314,7 @@ __global__ void cal_force_onsite(int wg_nc, const int* atom_na, int tpiba, const FPTYPE* d_wg, - const thrust::complex* vu, + const thrust::complex* pot_onsite, const int* orbital_corr, const thrust::complex* becp, const thrust::complex* dbecp, @@ -335,7 +335,7 @@ __global__ void cal_force_onsite(int wg_nc, { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; - vu += npol * npol * tlp1_2 * atom_na[ii]; + pot_onsite += npol * npol * tlp1_2 * atom_na[ii]; } const int ib2 = ib * npol; @@ -357,7 +357,7 @@ __global__ void cal_force_onsite(int wg_nc, FPTYPE tmp = 0; if (npol == 2) { - thrust::complex ps[4] = {vu[mm], vu[mm + tlp1_2], vu[mm + 2 * tlp1_2], vu[mm + 3 * tlp1_2]}; + thrust::complex ps[4] = {pot_onsite[mm], pot_onsite[mm + tlp1_2], pot_onsite[mm + 2 * tlp1_2], pot_onsite[mm + 3 * tlp1_2]}; const thrust::complex dbb0 = conj(dbecp[inkb0]) * becp[inkb2]; const thrust::complex dbb1 = conj(dbecp[inkb0]) * becp[inkb2 + nkb]; const thrust::complex dbb2 = conj(dbecp[inkb0 + nkb]) * becp[inkb2]; @@ -366,14 +366,14 @@ __global__ void cal_force_onsite(int wg_nc, } else { - tmp = -fac * (vu[mm] * conj(dbecp[inkb0]) * becp[inkb2]).real(); + tmp = -fac * (pot_onsite[mm] * conj(dbecp[inkb0]) * becp[inkb2]).real(); } atomicAdd(force + iat * forcenl_nc + ipol, tmp); } } ++iat; sum += nprojs; - vu += npol * npol * tlp1_2; + pot_onsite += npol * npol * tlp1_2; } } @@ -468,7 +468,7 @@ void cal_force_nl_op::operator()(const base_dev const int* atom_na, const FPTYPE& tpiba, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -491,7 +491,7 @@ void cal_force_nl_op::operator()(const base_dev atom_na, tpiba, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), @@ -514,7 +514,7 @@ void cal_force_nl_op::operator()(const base_dev atom_na, tpiba, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), diff --git a/source/source_pw/module_pwdft/kernels/rocm/onsite_op.hip.cu b/source/source_pw/module_pwdft/kernels/rocm/onsite_op.hip.cu index 71fdf82c50..3c1e9e6922 100644 --- a/source/source_pw/module_pwdft/kernels/rocm/onsite_op.hip.cu +++ b/source/source_pw/module_pwdft/kernels/rocm/onsite_op.hip.cu @@ -50,9 +50,9 @@ __global__ void onsite_op(const int npm, const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int tnp, - const thrust::complex* vu, + const thrust::complex* pot_onsite, thrust::complex* ps, const thrust::complex* becp) { @@ -62,7 +62,7 @@ __global__ void onsite_op(const int npm, { const int nbands = npm / npol; int iat = ip_iat[ip]; - const thrust::complex* vu_iat = vu + vu_begin_iat[iat]; + const thrust::complex* pot_onsite_iat = pot_onsite + pot_onsite_begin_iat[iat]; int orb_l = orb_l_iat[iat]; int tlp1 = 2 * orb_l + 1; int tlp1_2 = tlp1 * tlp1; @@ -80,9 +80,9 @@ __global__ void onsite_op(const int npm, const int becpind = ib2 * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind] + vu_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; - ps[psind + 1] += vu_iat[index_mm + tlp1_2 * 1] * becp[becpind] - + vu_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind] + pot_onsite_iat[index_mm + tlp1_2 * 2] * becp[becpind + tnp]; + ps[psind + 1] += pot_onsite_iat[index_mm + tlp1_2 * 1] * becp[becpind] + + pot_onsite_iat[index_mm + tlp1_2 * 3] * becp[becpind + tnp]; } } } @@ -96,7 +96,7 @@ __global__ void onsite_op(const int npm, const int becpind = ib * tnp + ip2; int m2 = ip_m[ip2]; const int index_mm = m1 * tlp1 + m2; - ps[psind] += vu_iat[index_mm] * becp[becpind]; + ps[psind] += pot_onsite_iat[index_mm] * becp[becpind]; } } } @@ -134,9 +134,9 @@ void hamilt::onsite_ps_op::operator()(const bas const int* orb_l_iat, const int* ip_iat, const int* ip_m, - const int* vu_begin_iat, + const int* pot_onsite_begin_iat, const int& tnp, - const std::complex* vu, + const std::complex* pot_onsite, std::complex* ps, const std::complex* becp) { @@ -148,9 +148,9 @@ void hamilt::onsite_ps_op::operator()(const bas orb_l_iat, ip_iat, ip_m, - vu_begin_iat, + pot_onsite_begin_iat, tnp, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), reinterpret_cast*>(ps), // array of data reinterpret_cast*>(becp)); // array of data 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 45db4048d8..d5c093cb51 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 @@ -925,7 +925,7 @@ __global__ void cal_stress_onsite( const int *atom_nh, const int *atom_na, const FPTYPE *d_wg, - const thrust::complex *vu, + const thrust::complex *pot_onsite, const int* orbital_corr, const thrust::complex *becp, const thrust::complex *dbecp, @@ -944,7 +944,7 @@ __global__ void cal_stress_onsite( for (int ii = 0; ii < it; ii++) { iat += atom_na[ii]; sum += atom_na[ii] * atom_nh[ii]; - vu += npol * npol * tlp1_2 * atom_na[ii]; + pot_onsite += npol * npol * tlp1_2 * atom_na[ii]; } FPTYPE stress_var = 0; @@ -962,7 +962,7 @@ __global__ void cal_stress_onsite( const int inkb2 = sum + ip2 + ib2 * nkb; if (npol == 2) { - thrust::complex ps[4] = {vu[mm], vu[mm + tlp1_2], vu[mm + 2 * tlp1_2], vu[mm + 3 * tlp1_2]}; + thrust::complex ps[4] = {pot_onsite[mm], pot_onsite[mm + tlp1_2], pot_onsite[mm + 2 * tlp1_2], pot_onsite[mm + 3 * tlp1_2]}; const thrust::complex dbb0 = conj(dbecp[inkb1]) * becp[inkb2]; const thrust::complex dbb1 = conj(dbecp[inkb1]) * becp[inkb2 + nkb]; const thrust::complex dbb2 = conj(dbecp[inkb1 + nkb]) * becp[inkb2]; @@ -971,12 +971,12 @@ __global__ void cal_stress_onsite( } else { - stress_var -= fac * (vu[mm] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); + stress_var -= fac * (pot_onsite[mm] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); } } ++iat; sum+=nprojs; - vu += npol * npol * tlp1_2; + pot_onsite += npol * npol * tlp1_2; }//ia __syncwarp(); warp_reduce(stress_var); @@ -1062,7 +1062,7 @@ void cal_stress_nl_op::operator()(const base_de const int* atom_nh, const int* atom_na, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -1078,7 +1078,7 @@ void cal_stress_nl_op::operator()(const base_de atom_nh, atom_na, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), @@ -1094,7 +1094,7 @@ void cal_stress_nl_op::operator()(const base_de atom_nh, atom_na, d_wg, - reinterpret_cast*>(vu), + reinterpret_cast*>(pot_onsite), orbital_corr, reinterpret_cast*>(becp), reinterpret_cast*>(dbecp), diff --git a/source/source_pw/module_pwdft/kernels/stress_op.cpp b/source/source_pw/module_pwdft/kernels/stress_op.cpp index 09e04f8eac..a6d0612b65 100644 --- a/source/source_pw/module_pwdft/kernels/stress_op.cpp +++ b/source/source_pw/module_pwdft/kernels/stress_op.cpp @@ -255,7 +255,7 @@ struct cal_stress_nl_op const int* atom_nh, const int* atom_na, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -294,7 +294,7 @@ struct cal_stress_nl_op { const int m2 = ip2 - ip_begin; const int inkb2 = ib2 * nkb + sum + ia * nproj + ip2; - local_stress -= fac * (vu[m1 * tlp1 + m2] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); + local_stress -= fac * (pot_onsite[m1 * tlp1 + m2] * (conj(dbecp[inkb1]) * becp[inkb2])).real(); } } // end ip break; @@ -309,7 +309,7 @@ struct cal_stress_nl_op std::complex ps[4]; for(int i = 0; i < 4; i++) { - ps[i] = vu[(i * tlp1_2 + m1 * tlp1 + m2)]; + ps[i] = pot_onsite[(i * tlp1_2 + m1 * tlp1 + m2)]; } const int inkb2 = ib2 * nkb + sum + ia * nproj + ip2; @@ -325,7 +325,7 @@ struct cal_stress_nl_op break; } }// ib - vu += npol * npol * tlp1_2;// step for vu + pot_onsite += npol * npol * tlp1_2;// step for pot_onsite }// ia sum += atom_na[it] * nproj; } // end it diff --git a/source/source_pw/module_pwdft/kernels/stress_op.h b/source/source_pw/module_pwdft/kernels/stress_op.h index d107431e3d..260053dba6 100644 --- a/source/source_pw/module_pwdft/kernels/stress_op.h +++ b/source/source_pw/module_pwdft/kernels/stress_op.h @@ -132,7 +132,7 @@ struct cal_stress_nl_op const int* atom_nh, const int* atom_na, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, @@ -340,7 +340,7 @@ struct cal_stress_nl_op const int* atom_nh, const int* atom_na, const FPTYPE* d_wg, - const std::complex* vu, + const std::complex* pot_onsite, const int* orbital_corr, const std::complex* becp, const std::complex* dbecp, diff --git a/source/source_pw/module_pwdft/kernels/test/onsite_op_test.cpp b/source/source_pw/module_pwdft/kernels/test/onsite_op_test.cpp index 41d301f8c4..9d42c509ff 100644 --- a/source/source_pw/module_pwdft/kernels/test/onsite_op_test.cpp +++ b/source/source_pw/module_pwdft/kernels/test/onsite_op_test.cpp @@ -173,11 +173,11 @@ TEST_F(OnsitePsDeltaSpinNpol2Test, MultiBand) // For npol=1: // for each ip: // m1 = ip_m[ip], if m1 < 0 continue -// iat = ip_iat[ip], vu_iat = vu + vu_begin_iat[iat] +// iat = ip_iat[ip], pot_onsite_iat = pot_onsite + pot_onsite_begin_iat[iat] // tlp1 = 2*orb_l + 1 // for ip2 in [ip-m1, ip-m1+tlp1): // m2 = ip_m[ip2] -// ps[ip * npm + ib] += vu_iat[m1*tlp1 + m2] * becp[ib * tnp + ip2] +// ps[ip * npm + ib] += pot_onsite_iat[m1*tlp1 + m2] * becp[ib * tnp + ip2] // ===================================================================== class OnsitePsDftuNpol1Test : public ::testing::Test @@ -196,26 +196,26 @@ TEST_F(OnsitePsDftuNpol1Test, SingleBandSingleAtom_DOrbital) std::vector orb_l_iat = {2}; // d-orbital (l=2) std::vector ip_iat = {0, 0, 0, 0, 0}; // all belong to atom 0 std::vector ip_m = {0, 1, 2, 3, 4}; // m indices - std::vector vu_begin_iat = {0}; // VU starts at index 0 + std::vector pot_onsite_begin_iat = {0}; // pot_onsite starts at index 0 - // VU matrix for d-orbital (5x5), row-major - std::vector vu(25, 0.0); - vu[0] = 1.0; // VU[0,0] - vu[6] = 2.0; // VU[1,1] - vu[12] = 3.0; // VU[2,2] + // pot_onsite matrix for d-orbital (5x5), row-major + std::vector pot_onsite(25, 0.0); + pot_onsite[0] = 1.0; // pot_onsite[0,0] + pot_onsite[6] = 2.0; // pot_onsite[1,1] + pot_onsite[12] = 3.0; // pot_onsite[2,2] std::vector becp = {1.0, 0.5, 0.3, 0.2, 0.1}; // 5 projectors std::vector ps(5, 0.0); // tnp * npm = 5 kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // For ip=0 (m1=0): ip2 ranges from 0 to 5 - // ps[0] += VU[0,0]*becp[0] + VU[0,1]*becp[1] + ... + // ps[0] += pot_onsite[0,0]*becp[0] + pot_onsite[0,1]*becp[1] + ... // = 1.0*1.0 + 0 + 0 + 0 + 0 = 1.0 // For ip=1 (m1=1): ip2 ranges from 0 to 5 - // ps[1] += VU[1,0]*becp[0] + VU[1,1]*becp[1] + ... + // ps[1] += pot_onsite[1,0]*becp[0] + pot_onsite[1,1]*becp[1] + ... // = 0 + 2.0*0.5 + 0 + 0 + 0 = 1.0 // For ip=2 (m1=2): ps[2] += 3.0*0.3 = 0.9 EXPECT_NEAR(ps[0].real(), 1.0, 1e-15); @@ -225,33 +225,33 @@ TEST_F(OnsitePsDftuNpol1Test, SingleBandSingleAtom_DOrbital) EXPECT_NEAR(ps[4].real(), 0.0, 1e-15); } -TEST_F(OnsitePsDftuNpol1Test, OffDiagonalVU) +TEST_F(OnsitePsDftuNpol1Test, OffDiagonalPotOnsite) { - // Test off-diagonal VU elements + // Test off-diagonal pot_onsite elements const int npm = 1, npol = 1, tnp = 3; // p-orbital std::vector orb_l_iat = {1}; // p-orbital std::vector ip_iat = {0, 0, 0}; std::vector ip_m = {0, 1, 2}; - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - // VU with off-diagonal: VU[0,1] = 0.5, VU[1,0] = 0.5 - std::vector vu(9, 0.0); - vu[1] = 0.5; // VU[0,1] - vu[3] = 0.5; // VU[1,0] + // pot_onsite with off-diagonal: pot_onsite[0,1] = 0.5, pot_onsite[1,0] = 0.5 + std::vector pot_onsite(9, 0.0); + pot_onsite[1] = 0.5; // pot_onsite[0,1] + pot_onsite[3] = 0.5; // pot_onsite[1,0] std::vector becp = {1.0, 2.0, 3.0}; std::vector ps(3, 0.0); kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // ip=0 (m1=0): ip2 from 0 to 3 - // ps[0] += VU[0,0]*becp[0] + VU[0,1]*becp[1] + VU[0,2]*becp[2] + // ps[0] += pot_onsite[0,0]*becp[0] + pot_onsite[0,1]*becp[1] + pot_onsite[0,2]*becp[2] // = 0*1.0 + 0.5*2.0 + 0*3.0 = 1.0 // ip=1 (m1=1): - // ps[1] += VU[1,0]*becp[0] + VU[1,1]*becp[1] + VU[1,2]*becp[2] + // ps[1] += pot_onsite[1,0]*becp[0] + pot_onsite[1,1]*becp[1] + pot_onsite[1,2]*becp[2] // = 0.5*1.0 + 0*2.0 + 0*3.0 = 0.5 EXPECT_NEAR(ps[0].real(), 1.0, 1e-15); EXPECT_NEAR(ps[1].real(), 0.5, 1e-15); @@ -266,20 +266,20 @@ TEST_F(OnsitePsDftuNpol1Test, NonCorrelatedProjector_MMinus1) std::vector ip_iat = {0, 0, 0, 0}; // First projector is not correlated (m=-1), rest are p-type (m=0,1,2) std::vector ip_m = {-1, 0, 1, 2}; - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - std::vector vu(9, 1.0); // all VU = 1.0 + std::vector pot_onsite(9, 1.0); // all pot_onsite = 1.0 std::vector becp = {1.0, 1.0, 1.0, 1.0}; std::vector ps(4, 0.0); kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // ip=0: m1=-1, skipped // ip=1,2,3: should have contributions EXPECT_NEAR(ps[0].real(), 0.0, 1e-15); // skipped - EXPECT_NEAR(ps[1].real(), 3.0, 1e-15); // sum of VU[1,*]*becp + EXPECT_NEAR(ps[1].real(), 3.0, 1e-15); // sum of pot_onsite[1,*]*becp EXPECT_NEAR(ps[2].real(), 3.0, 1e-15); EXPECT_NEAR(ps[3].real(), 3.0, 1e-15); } @@ -291,10 +291,10 @@ TEST_F(OnsitePsDftuNpol1Test, MultiBand_DOrbital) std::vector orb_l_iat = {2}; std::vector ip_iat = {0, 0, 0, 0, 0}; std::vector ip_m = {0, 1, 2, 3, 4}; - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - std::vector vu(25, 0.0); - vu[0] = 2.0; // VU[0,0] + std::vector pot_onsite(25, 0.0); + pot_onsite[0] = 2.0; // pot_onsite[0,0] // Band 0: becp[0..4], Band 1: becp[5..9] std::vector becp = { @@ -304,11 +304,11 @@ TEST_F(OnsitePsDftuNpol1Test, MultiBand_DOrbital) std::vector ps(10, 0.0); // tnp * npm = 10 kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); - // Band 0: ps[0] += VU[0,0] * becp[0] = 2.0 * 1.0 = 2.0 - // Band 1: ps[5] += VU[0,0] * becp[5] = 2.0 * 0.0 = 0.0 + // Band 0: ps[0] += pot_onsite[0,0] * becp[0] = 2.0 * 1.0 = 2.0 + // Band 1: ps[5] += pot_onsite[0,0] * becp[5] = 2.0 * 0.0 = 0.0 // Wait, becp indexing: becp[ib * tnp + ip2] // For band 1, ib=1: becp[1*5 + 0] = becp[5] = 0.0 EXPECT_NEAR(ps[0].real(), 2.0, 1e-15); @@ -319,10 +319,10 @@ TEST_F(OnsitePsDftuNpol1Test, MultiBand_DOrbital) // 4. DFT+U kernel (npol=2 branch) // // For npol=2: -// ps[ip * npm + ib2] += vu_iat[index_mm] * becp[ib2*tnp + ip2] -// + vu_iat[index_mm + 2*tlp1^2] * becp[ib2*tnp + ip2 + tnp] -// ps[ip * npm + ib2+1] += vu_iat[index_mm + tlp1^2] * becp[ib2*tnp + ip2] -// + vu_iat[index_mm + 3*tlp1^2] * becp[ib2*tnp + ip2 + tnp] +// ps[ip * npm + ib2] += pot_onsite_iat[index_mm] * becp[ib2*tnp + ip2] +// + pot_onsite_iat[index_mm + 2*tlp1^2] * becp[ib2*tnp + ip2 + tnp] +// ps[ip * npm + ib2+1] += pot_onsite_iat[index_mm + tlp1^2] * becp[ib2*tnp + ip2] +// + pot_onsite_iat[index_mm + 3*tlp1^2] * becp[ib2*tnp + ip2 + tnp] // // where index_mm = m1 * tlp1 + m2 // ===================================================================== @@ -343,14 +343,14 @@ TEST_F(OnsitePsDftuNpol2Test, SingleBandSingleAtom_Porbital) std::vector orb_l_iat = {1}; // p-orbital std::vector ip_iat = {0, 0, 0}; std::vector ip_m = {0, 1, 2}; - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - // VU: 4 blocks of 3x3 = 36 elements - std::vector vu(36, 0.0); - // Block 0 (Pauli I): VU[0,0] = 2.0 - vu[0] = 2.0; - // Block 1 (Pauli X): VU[0,0] = 1.0 - vu[9] = 1.0; // tlp1^2 = 9 + // pot_onsite: 4 blocks of 3x3 = 36 elements + std::vector pot_onsite(36, 0.0); + // Block 0 (Pauli I): pot_onsite[0,0] = 2.0 + pot_onsite[0] = 2.0; + // Block 1 (Pauli X): pot_onsite[0,0] = 1.0 + pot_onsite[9] = 1.0; // tlp1^2 = 9 // becp: 2 rows (spin up/down) x 3 projectors std::vector becp = { @@ -360,12 +360,12 @@ TEST_F(OnsitePsDftuNpol2Test, SingleBandSingleAtom_Porbital) std::vector ps = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // tnp * npm = 6 kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // For ip=0 (m1=0): ip2 from 0 to 3 - // ps[0] += vu[0]*becp[0] + vu[18]*becp[3] = 2.0*1.0 + 0*0.0 = 2.0 - // ps[1] += vu[9]*becp[0] + vu[27]*becp[3] = 1.0*1.0 + 0*0.0 = 1.0 + // ps[0] += pot_onsite[0]*becp[0] + pot_onsite[18]*becp[3] = 2.0*1.0 + 0*0.0 = 2.0 + // ps[1] += pot_onsite[9]*becp[0] + pot_onsite[27]*becp[3] = 1.0*1.0 + 0*0.0 = 1.0 EXPECT_NEAR(ps[0].real(), 2.0, 1e-15); EXPECT_NEAR(ps[1].real(), 1.0, 1e-15); } @@ -377,10 +377,10 @@ TEST_F(OnsitePsDftuNpol2Test, MultiBand) std::vector orb_l_iat = {1}; std::vector ip_iat = {0, 0, 0}; std::vector ip_m = {0, 1, 2}; - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - std::vector vu(36, 0.0); - vu[0] = 2.0; // Block 0, VU[0,0] + std::vector pot_onsite(36, 0.0); + pot_onsite[0] = 2.0; // Block 0, pot_onsite[0,0] // becp: 2 spin x 3 proj x 2 bands = 12 elements // Layout: [band0_up, band0_dn, band1_up, band1_dn] @@ -393,13 +393,13 @@ TEST_F(OnsitePsDftuNpol2Test, MultiBand) std::vector ps(12, 0.0); kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // Band pair 0 (ib=0, ib2=0): - // ps[0] += vu[0]*becp[0] + vu[18]*becp[3] = 2.0*1.0 + 0 = 2.0 + // ps[0] += pot_onsite[0]*becp[0] + pot_onsite[18]*becp[3] = 2.0*1.0 + 0 = 2.0 // Band pair 1 (ib=1, ib2=2): - // ps[2] += vu[0]*becp[6] + vu[18]*becp[9] = 2.0*0.2 + 0 = 0.4 + // ps[2] += pot_onsite[0]*becp[6] + pot_onsite[18]*becp[9] = 2.0*0.2 + 0 = 0.4 EXPECT_NEAR(ps[0].real(), 2.0, 1e-15); EXPECT_NEAR(ps[2].real(), 0.4, 1e-15); } @@ -447,23 +447,23 @@ TEST_F(OnsitePsEdgeCasesTest, ZeroLambda) EXPECT_NEAR(ps[1].real(), 20.0, 1e-15); } -TEST_F(OnsitePsEdgeCasesTest, ComplexVU) +TEST_F(OnsitePsEdgeCasesTest, Complexpot_onsite) { - // DFT+U with complex VU elements + // DFT+U with complex pot_onsite elements const int npm = 1, npol = 1, tnp = 2; std::vector orb_l_iat = {0}; // s-orbital, but 2 projectors std::vector ip_iat = {0, 0}; std::vector ip_m = {0, -1}; // first correlated, second not - std::vector vu_begin_iat = {0}; + std::vector pot_onsite_begin_iat = {0}; - std::vector vu = {complexd(1.0, 2.0)}; // 1x1 VU matrix + std::vector pot_onsite = {complexd(1.0, 2.0)}; // 1x1 pot_onsite matrix std::vector becp = {complexd(0.5, 0.5), 1.0}; std::vector ps = {0.0, 0.0}; kernel(nullptr, npm, npol, - orb_l_iat.data(), ip_iat.data(), ip_m.data(), vu_begin_iat.data(), - tnp, vu.data(), ps.data(), becp.data()); + orb_l_iat.data(), ip_iat.data(), ip_m.data(), pot_onsite_begin_iat.data(), + tnp, pot_onsite.data(), ps.data(), becp.data()); // ps[0] += (1+complexd(0.0, 2.0)) * (0.5+0.5i) = 0.5+0.5i + complexd(0.0, 1.0)-1 = -0.5+1.5i EXPECT_NEAR(ps[0].real(), -0.5, 1e-15); diff --git a/source/source_pw/module_pwdft/onsite_proj.cpp b/source/source_pw/module_pwdft/onsite_proj.cpp index 331d3331bd..40b0747cd7 100644 --- a/source/source_pw/module_pwdft/onsite_proj.cpp +++ b/source/source_pw/module_pwdft/onsite_proj.cpp @@ -594,10 +594,10 @@ 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* vu_ptr = dftu.get_eff_pot_pw_spin(isk_val); - const int vu_size = dftu.get_size_eff_pot_pw_spin(); + 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_data(), vu_ptr, vu_size, wg_ik); + dftu.get_orbital_corr_data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } template @@ -606,10 +606,10 @@ 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* vu_ptr = dftu.get_eff_pot_pw_spin(isk_val); - const int vu_size = dftu.get_size_eff_pot_pw_spin(); + 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_data(), vu_ptr, vu_size, wg_ik); + dftu.get_orbital_corr_data(), pot_onsite_ptr, pot_onsite_size, wg_ik); } template diff --git a/source/source_pw/module_pwdft/onsite_proj_tools.cpp b/source/source_pw/module_pwdft/onsite_proj_tools.cpp index 4239d8fa9e..593804ca11 100644 --- a/source/source_pw/module_pwdft/onsite_proj_tools.cpp +++ b/source/source_pw/module_pwdft/onsite_proj_tools.cpp @@ -809,26 +809,26 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, int npm, FPTYPE* force, const int* orbital_corr, - const std::complex* vu, - const int size_vu, + const std::complex* pot_onsite, + const int size_pot_onsite, const FPTYPE* h_wg) { int* orbital_corr_tmp = nullptr; - std::complex* vu_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_complex_op()(vu_tmp, size_vu); - syncmem_complex_h2d_op()(vu_tmp, vu, size_vu); + 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)); } else #endif { orbital_corr_tmp = const_cast(orbital_corr); - vu_tmp = const_cast*>(vu); + pot_onsite_tmp = const_cast*>(pot_onsite); d_wg = const_cast(h_wg); } const int force_nc = 3; @@ -846,7 +846,7 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, atom_na, this->ucell_->tpiba, d_wg, - vu_tmp, + pot_onsite_tmp, orbital_corr_tmp, becp, dbecp, @@ -854,7 +854,7 @@ void Onsite_Proj_tools::cal_force_dftu(int ik, #if defined(__CUDA) || defined(__ROCM) if (this->device == base_device::GpuDevice) { - delmem_complex_op()(vu_tmp); + delmem_complex_op()(pot_onsite_tmp); delmem_int_op()(orbital_corr_tmp); } #endif @@ -921,15 +921,15 @@ template double Onsite_Proj_tools::cal_stress_dftu(int ik, int npm, const int* orb_corr, - const std::complex* vu, - const int size_vu, + const std::complex* pot_onsite, + const int size_pot_onsite, const FPTYPE* h_wg) { double stress_out = 0.0; const int npol = this->ucell_->get_npol(); int* orb_corr_tmp = nullptr; - std::complex* vu_tmp = nullptr; + std::complex* pot_onsite_tmp = nullptr; #if defined(__CUDA) || defined(__ROCM) if (this->device == base_device::GpuDevice) { @@ -937,9 +937,9 @@ double Onsite_Proj_tools::cal_stress_dftu(int ik, resmem_int_op()(orb_corr_tmp, this->ucell_->ntype); syncmem_int_h2d_op()(orb_corr_tmp, orb_corr, this->ucell_->ntype); - // vu_tmp - resmem_complex_op()(vu_tmp, size_vu); - syncmem_complex_h2d_op()(vu_tmp, vu, size_vu); + // pot_onsite_tmp + resmem_complex_op()(pot_onsite_tmp, size_pot_onsite); + syncmem_complex_h2d_op()(pot_onsite_tmp, pot_onsite, size_pot_onsite); // transfer data from from host to device syncmem_var_h2d_op()(d_wg, h_wg, this->nbands * (ik+1)); @@ -959,7 +959,7 @@ double Onsite_Proj_tools::cal_stress_dftu(int ik, atom_nh, atom_na, d_wg, - vu_tmp, + pot_onsite_tmp, orb_corr_tmp, becp, dbecp, @@ -968,14 +968,14 @@ double Onsite_Proj_tools::cal_stress_dftu(int ik, // Transfer stress from device to host syncmem_var_d2h_op()(&stress_out, stress_device, 1); delmem_var_op()(stress_device); - delmem_complex_op()(vu_tmp); + delmem_complex_op()(pot_onsite_tmp); delmem_int_op()(orb_corr_tmp); } else #endif { orb_corr_tmp = const_cast(orb_corr); - vu_tmp = const_cast*>(vu); + pot_onsite_tmp = const_cast*>(pot_onsite); d_wg = const_cast(h_wg); cal_stress_nl_op()(this->ctx, @@ -988,7 +988,7 @@ double Onsite_Proj_tools::cal_stress_dftu(int ik, atom_nh, atom_na, d_wg, - vu_tmp, + pot_onsite_tmp, orb_corr_tmp, becp, dbecp, diff --git a/source/source_pw/module_pwdft/onsite_proj_tools.h b/source/source_pw/module_pwdft/onsite_proj_tools.h index 0b7ef73b83..6c3ecc0a37 100644 --- a/source/source_pw/module_pwdft/onsite_proj_tools.h +++ b/source/source_pw/module_pwdft/onsite_proj_tools.h @@ -78,8 +78,8 @@ class Onsite_Proj_tools int npm, FPTYPE* force, const int* orbital_corr, - const std::complex* vu, - const int size_vu, + const std::complex* pot_onsite, + const int size_pot_onsite, const FPTYPE* h_wg ); @@ -96,8 +96,8 @@ class Onsite_Proj_tools int ik, int npm, const int* orbital_corr, - const std::complex* vu, - const int size_vu, + const std::complex* pot_onsite, + const int size_pot_onsite, const FPTYPE* h_wg ); diff --git a/source/source_pw/module_pwdft/op_pw_proj.cpp b/source/source_pw/module_pwdft/op_pw_proj.cpp index 7244b315f7..9321138cc9 100644 --- a/source/source_pw/module_pwdft/op_pw_proj.cpp +++ b/source/source_pw/module_pwdft/op_pw_proj.cpp @@ -43,8 +43,8 @@ OnsiteProj>::~OnsiteProj() { } delmem_int_op()(this->orb_l_iat); delmem_int_op()(this->ip_m); - delmem_int_op()(this->vu_begin_iat); - delmem_complex_op()(this->vu_device); + delmem_int_op()(this->pot_onsite_begin_iat); + delmem_complex_op()(this->pot_onsite_device); } } @@ -181,21 +181,21 @@ void OnsiteProj>::cal_ps_delta_spin(const int npol, const this->ps, becp); } -// cal_ps_dftu — compute ps = VU * becp for DFT+U Hamiltonian contribution +// cal_ps_dftu — compute ps = pot_onsite * becp for DFT+U Hamiltonian contribution // -// eff_pot_pw layout by nspin: +// pot_uterm_pw 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 | ...] // split layout — first half is spin-up, second half spin-down. // For isk==1 (spin-down k-point), only the second half is -// uploaded to vu_device so that vu_begin_iat[iat] indexes +// uploaded to pot_onsite_device so that pot_onsite_begin_iat[iat] indexes // correctly into the spin-down block. // nspin=4: [iat0_Pauli_4blocks | iat1_Pauli_4blocks | ...] // 4*(2l+1)^2 entries per atom; kernel uses npol=2 spinor // structure with 2x2 Pauli matrix coefficients. // -// vu_begin_iat is computed as tlp1^2 * npol^2 per atom at init time, +// pot_onsite_begin_iat is computed as tlp1^2 * npol^2 per atom at init time, // which gives the correct offset for each nspin case: // nspin=1: tlp1^2 * 1 = tlp1^2 // nspin=2: tlp1^2 * 1 = tlp1^2 (per spin channel, selected by isk) @@ -209,15 +209,15 @@ void OnsiteProj>::setup_pw_dftu_indices() const resmem_int_op()(this->orb_l_iat, this->ucell->nat); resmem_int_op()(this->ip_m, onsite_p->get_tot_nproj()); - resmem_int_op()(this->vu_begin_iat, this->ucell->nat); + resmem_int_op()(this->pot_onsite_begin_iat, this->ucell->nat); resmem_int_op()(this->ip_iat, onsite_p->get_tot_nproj()); std::vector ip_iat0(onsite_p->get_tot_nproj()); std::vector ip_m0(onsite_p->get_tot_nproj()); - std::vector vu_begin_iat0(this->ucell->nat); + std::vector pot_onsite_begin_iat0(this->ucell->nat); std::vector orb_l_iat0(this->ucell->nat); int ip0 = 0; - int vu_begin = 0; + int pot_onsite_begin = 0; for(int iat=0;iatucell->nat;iat++) { const int it = this->ucell->iat2it[iat]; @@ -231,14 +231,14 @@ void OnsiteProj>::setup_pw_dftu_indices() const ip_iat0[ip0] = iat; ip_m0[ip0++] = -1; } - vu_begin_iat0[iat] = 0; + pot_onsite_begin_iat0[iat] = 0; continue; } else { const int tlp1 = 2 * target_l + 1; - vu_begin_iat0[iat] = vu_begin; - vu_begin += tlp1 * tlp1 * npol * npol; + pot_onsite_begin_iat0[iat] = pot_onsite_begin; + pot_onsite_begin += tlp1 * tlp1 * npol * npol; const int m_begin = target_l * target_l; const int m_end = (target_l + 1) * (target_l + 1); for(int ip=0;ip>::setup_pw_dftu_indices() const syncmem_int_h2d_op()(this->orb_l_iat, orb_l_iat0.data(), this->ucell->nat); syncmem_int_h2d_op()(this->ip_iat, ip_iat0.data(), onsite_p->get_tot_nproj()); syncmem_int_h2d_op()(this->ip_m, ip_m0.data(), onsite_p->get_tot_nproj()); - syncmem_int_h2d_op()(this->vu_begin_iat, vu_begin_iat0.data(), this->ucell->nat); + syncmem_int_h2d_op()(this->pot_onsite_begin_iat, pot_onsite_begin_iat0.data(), this->ucell->nat); - resmem_complex_op()(this->vu_device, dftu->get_size_eff_pot_pw()); + resmem_complex_op()(this->pot_onsite_device, dftu->get_size_pot_uterm_pw()); } template @@ -291,9 +291,9 @@ void OnsiteProj>::cal_ps_dftu( } const int isk_val = (PARAM.inp.nspin == 2) ? this->isk[this->ik] : 0; - const std::complex* vu_host = dftu->get_eff_pot_pw_spin(isk_val); - const int vu_size = dftu->get_size_eff_pot_pw_spin(); - syncmem_complex_h2d_op()(this->vu_device, vu_host, vu_size); + 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(); + syncmem_complex_h2d_op()(this->pot_onsite_device, pot_onsite_host, pot_onsite_size); hamilt::onsite_ps_op()( this->ctx, m, @@ -301,9 +301,9 @@ void OnsiteProj>::cal_ps_dftu( this->orb_l_iat, this->ip_iat, this->ip_m, - this->vu_begin_iat, + this->pot_onsite_begin_iat, tnp, - this->vu_device, + this->pot_onsite_device, this->ps, becp); } @@ -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): eff_pot_pw uses split layout [all_up | all_dn]; +// nspin=2 (npol=1): pot_uterm_pw 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/op_pw_proj.h b/source/source_pw/module_pwdft/op_pw_proj.h index 298cd8749c..4cece48299 100644 --- a/source/source_pw/module_pwdft/op_pw_proj.h +++ b/source/source_pw/module_pwdft/op_pw_proj.h @@ -54,7 +54,7 @@ class OnsiteProj> : public OperatorPW void cal_ps_dftu(const int npol, const int m) const; - /// one-time setup of DFT+U PW index arrays (orb_l_iat, ip_iat, ip_m, vu_begin_iat) + /// one-time setup of DFT+U PW index arrays (orb_l_iat, ip_iat, ip_m, pot_onsite_begin_iat) void setup_pw_dftu_indices() const; void update_becp(const T* psi_in, const int npol, const int m, const int npwx) const; @@ -71,8 +71,8 @@ class OnsiteProj> : public OperatorPW mutable T* lambda_coeff = nullptr; mutable int* orb_l_iat = nullptr; mutable int* ip_m = nullptr; - mutable int* vu_begin_iat = nullptr; - mutable T* vu_device = nullptr; + mutable int* pot_onsite_begin_iat = nullptr; + mutable T* pot_onsite_device = nullptr; mutable int nkb_m = 0; diff --git a/source/source_pw/module_pwdft/setup_dftu_pw.cpp b/source/source_pw/module_pwdft/setup_dftu_pw.cpp index fbab39d9db..a49a99f4d6 100644 --- a/source/source_pw/module_pwdft/setup_dftu_pw.cpp +++ b/source/source_pw/module_pwdft/setup_dftu_pw.cpp @@ -25,9 +25,9 @@ void iter_init_dftu_pw(const int iter, return; } - if (dftu.occ_mat_ctrl != 2) + if (dftu.get_occ_mat_ctrl() != 2) { - dftu.cal_occ_pw(iter, psi, wg, ucell, p_chgmix, isk); + dftu.cal_occ_pw(psi, wg, ucell, p_chgmix, isk); } dftu_io::output(dftu, ucell, PARAM.inp.out_chg[0], PARAM.globalv.global_out_dir, PARAM.inp.nspin, PARAM.globalv.npol); }