diff --git a/.clang-format b/.clang-format index 8970df99c2..5ea3e06441 100644 --- a/.clang-format +++ b/.clang-format @@ -1,49 +1,63 @@ --- Language: Cpp -BasedOnStyle: Microsoft +BasedOnStyle: LLVM -AlwaysBreakTemplateDeclarations: Yes +ColumnLimit: 120 -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false +#AlwaysBreakTemplateDeclarations: Yes +# +#AllowAllArgumentsOnNextLine: false +#AllowAllParametersOfDeclarationOnNextLine: false BinPackArguments: false BinPackParameters: false - -BreakBeforeBinaryOperators: All -BreakBeforeTernaryOperators: true - -Cpp11BracedListStyle: true -FixNamespaceComments: true - -# InsertBraces: true # only for clang-format version15.0.0 or later - -# About include -IncludeBlocks: Regroup -IncludeIsMainRegex: '([-_](test|unittest))?$' -IncludeIsMainSourceRegex: '' - +PackArguments: + BinPack: UseBreakAfter + BreakAfter: 3 +PackParameters: + BinPack: UseBreakAfter + BreakAfter: 3 +# +#BreakBeforeBinaryOperators: None +#BreakBeforeTernaryOperators: true +BreakBeforeBraces: Allman +BreakAfterOpenBracketFunction: true +AlignAfterOpenBracket: DontAlign +# +#Cpp11BracedListStyle: true +#FixNamespaceComments: true +# +InsertBraces: true # only for clang-format version15.0.0 or later +# +## About include +#IncludeBlocks: Regroup +#IncludeIsMainRegex: '([-_](test|unittest))?$' +#IncludeIsMainSourceRegex: '' +# IndentWidth: 4 -IndentWrappedFunctionNames: true - -# About Point -DerivePointerAlignment: false -PointerAlignment: Left - -ReflowComments: true -SortIncludes: true -SortUsingDeclarations: true - -# About space -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceBeforeRangeBasedForLoopColon: false -SpaceInEmptyParentheses: false -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: false -SpacesInParentheses: false -SpacesInSquareBrackets: false +#IndentWrappedFunctionNames: true +# +## About Point +#DerivePointerAlignment: false +#PointerAlignment: Left +PenaltyBreakBeforeMemberAccess: 1000 +PenaltyBreakScopeResolution: 1000 +# +#ReflowComments: true +#SortIncludes: true +#SortUsingDeclarations: true +# +## About space +#SpaceAfterCStyleCast: false +#SpaceAfterLogicalNot: false +#SpaceBeforeRangeBasedForLoopColon: false +#SpaceInEmptyParentheses: false +#SpacesInAngles: false +#SpacesInCStyleCastParentheses: false +#SpacesInContainerLiterals: false +#SpacesInParentheses: false +#SpacesInSquareBrackets: false +# Standard: c++11 TabWidth: 4 UseTab: Never diff --git a/source/source_esolver/esolver.h b/source/source_esolver/esolver.h index f302584cbb..c1d69987d9 100644 --- a/source/source_esolver/esolver.h +++ b/source/source_esolver/esolver.h @@ -12,10 +12,7 @@ namespace ModuleESolver class ESolver { public: - ESolver() - { - classname = "ESolver"; - } + ESolver() { classname = "ESolver"; } virtual ~ESolver() { @@ -25,26 +22,26 @@ class ESolver } //! initialize the energy solver by using input parameters and cell modules - virtual void before_all_runners(BaseCell& cell, const Input_para& inp) = 0; + virtual void before_all_runners(BaseCell &cell, const Input_para &inp) = 0; //! run energy solver - virtual void runner(BaseCell& cell, const int istep) = 0; + virtual void runner(BaseCell &cell, const int istep) = 0; //! perform post processing calculations - virtual void after_all_runners(BaseCell& cell) = 0; + virtual void after_all_runners(BaseCell &cell) = 0; //! deal with exx and other calculation than scf/md/relax/cell-relax: //! such as nscf, get_wf and get_pchg - virtual void others(BaseCell&, const int) {} + virtual void others(BaseCell &, const int) {} //! calculate total energy of a given system virtual double cal_energy() = 0; //! calcualte forces for the atoms in the given cell - virtual void cal_force(BaseCell& cell, ModuleBase::matrix& force) = 0; + virtual void cal_force(BaseCell &cell, ModuleBase::matrix &force) = 0; //! calcualte stress of given cell - virtual void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) = 0; + virtual void cal_stress(BaseCell &cell, ModuleBase::matrix &stress) = 0; bool conv_esolver = true; // whether esolver is converged @@ -52,7 +49,7 @@ class ESolver protected: /// Bound in before_all_runners; members use inp_->xxx instead of PARAM.inp.xxx - const Input_para* inp_ = nullptr; + const Input_para *inp_ = nullptr; }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_dfpt_pw.cpp b/source/source_esolver/esolver_dfpt_pw.cpp index c22017f783..27c94a3561 100644 --- a/source/source_esolver/esolver_dfpt_pw.cpp +++ b/source/source_esolver/esolver_dfpt_pw.cpp @@ -8,11 +8,11 @@ #include "esolver_dfpt_pw.h" -#include "source_estate/module_charge/charge.h" -#include "source_estate/module_pot/pot_xc_fdm.h" #include "source_base/macros.h" #include "source_base/math_polyint.h" #include "source_base/tool_quit.h" +#include "source_estate/module_charge/charge.h" +#include "source_estate/module_pot/pot_xc_fdm.h" #include "source_hamilt/module_xc/libxc_abacus.h" #include "source_hamilt/module_xc/xc_functional.h" #include "source_io/module_parameter/parameter.h" @@ -30,7 +30,8 @@ #include #include -namespace { +namespace +{ /** * @brief Re/Im-split finite-difference adapter over elecstate::PotXC_FDM. @@ -43,21 +44,35 @@ namespace { class XC_First_Order_FDM : public ModuleDFPT::XC_First_Order { public: - XC_First_Order_FDM(const int nspin, - const bool domag, - const bool domag_z, - const int gga_grad, - const bool out_elf, - const int test_charge, - ModulePW::PW_Basis* rho_basis, - const Charge* chg0, - const UnitCell* ucell) + XC_First_Order_FDM( + const int nspin, + const bool domag, + const bool domag_z, + const int gga_grad, + const bool out_elf, + const int test_charge, + ModulePW::PW_Basis *rho_basis, + const Charge *chg0, + const UnitCell *ucell) : ucell_(ucell) { - fdm_ = new elecstate::PotXC_FDM(nspin, domag, domag_z, gga_grad, out_elf, test_charge, rho_basis, chg0, ucell); + fdm_ = new elecstate::PotXC_FDM( + nspin, + domag, + domag_z, + gga_grad, + out_elf, + test_charge, + rho_basis, + chg0, + ucell); chg1_ = new Charge(); chg1_->set_rhopw(rho_basis); - chg1_->allocate(chg0->nspin, false, false, test_charge); + chg1_->allocate( + chg0->nspin, + false, + false, + test_charge); veff_1_.create(chg0->nspin, chg0->nrxx); } @@ -67,8 +82,8 @@ class XC_First_Order_FDM : public ModuleDFPT::XC_First_Order delete chg1_; } - void apply(const std::vector>& drho_r, - std::vector>& dvxc_r) const override + void apply( + const std::vector> &drho_r, std::vector> &dvxc_r) const override { const int nrxx = veff_1_.nc; if (static_cast(drho_r.size()) != nrxx) @@ -130,12 +145,10 @@ class XC_First_Order_FDM : public ModuleDFPT::XC_First_Order imax = ir; } } - std::cout << "XCDBG call=" << call - << " /|drho|^2=" << (dp_dv / dp_dp) + std::cout << "XCDBG call=" << call << " /|drho|^2=" << (dp_dv / dp_dp) << " |dvxc|/|drho|=" << (std::sqrt(dv_dv) / std::sqrt(dp_dp)) << " ratio@max=" << (dvxc_r[imax].real() / drho_r[imax].real()) - << " drho@max=" << drho_r[imax].real() - << std::endl; + << " drho@max=" << drho_r[imax].real() << std::endl; } ++call; } @@ -158,16 +171,15 @@ class XC_First_Order_FDM : public ModuleDFPT::XC_First_Order fdm_->cal_v_eff(chg1_, ucell_, veff_1_); for (int ir = 0; ir < nrxx; ++ir) { - dvxc_r[ir] += std::complex(0.0, 1.0) - * (v_plus[ir] - veff_1_(0, ir)) / (2.0 * eta); + dvxc_r[ir] += std::complex(0.0, 1.0) * (v_plus[ir] - veff_1_(0, ir)) / (2.0 * eta); } } private: - elecstate::PotXC_FDM* fdm_ = nullptr; - Charge* chg1_ = nullptr; + elecstate::PotXC_FDM *fdm_ = nullptr; + Charge *chg1_ = nullptr; mutable ModuleBase::matrix veff_1_; - const UnitCell* ucell_ = nullptr; + const UnitCell *ucell_ = nullptr; }; } // namespace @@ -199,10 +211,10 @@ ESolver_DFPT_PW::~ESolver_DFPT_PW() } } -void ESolver_DFPT_PW::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_DFPT_PW::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DFPT_PW", "before_all_runners"); @@ -232,10 +244,10 @@ void ESolver_DFPT_PW::before_all_runners(BaseCell& basecell, const Input_para& i dfpt_->set_loto(inp.dfpt_loto); } -void ESolver_DFPT_PW::runner(BaseCell& basecell, const int istep) +void ESolver_DFPT_PW::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DFPT_PW", "runner"); @@ -258,24 +270,24 @@ void ESolver_DFPT_PW::runner(BaseCell& basecell, const int istep) run_post_process(ucell); } -void ESolver_DFPT_PW::after_all_runners(BaseCell& basecell) +void ESolver_DFPT_PW::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DFPT_PW", "after_all_runners"); ESolver_KS_PW, base_device::DEVICE_CPU>::after_all_runners(ucell); } -void ESolver_DFPT_PW::run_gs(UnitCell& ucell) +void ESolver_DFPT_PW::run_gs(UnitCell &ucell) { ModuleBase::TITLE("ESolver_DFPT_PW", "run_gs"); ESolver_KS_PW, base_device::DEVICE_CPU>::runner(ucell, 0); } -void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) +void ESolver_DFPT_PW::init_dfpt(UnitCell &ucell) { ModuleBase::TITLE("ESolver_DFPT_PW", "init_dfpt"); @@ -283,19 +295,18 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) { ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", "DFPT currently supports nspin = 1 only"); } - if (this->pelec == nullptr || this->pelec->charge == nullptr || this->pelec->pot == nullptr - || this->stp.psi_cpu == nullptr || this->pw_rho == nullptr || this->pw_wfc == nullptr) + if (this->pelec == nullptr || this->pelec->charge == nullptr || this->pelec->pot == nullptr || + this->stp.psi_cpu == nullptr || this->pw_rho == nullptr || this->pw_wfc == nullptr) { ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", "ground state is not ready"); } if (this->pelec->charge->nrxx != this->pw_rho->nrxx) { - ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", - "charge is not on the rho grid (DFPT supports NCPP)"); + ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", "charge is not on the rho grid (DFPT supports NCPP)"); } // converged effective potential on the shared rho grid (row 0: nspin = 1) - const ModuleBase::matrix& veff_smooth = this->pelec->pot->get_veff_smooth(); + const ModuleBase::matrix &veff_smooth = this->pelec->pot->get_veff_smooth(); if (veff_smooth.nc != this->pw_rho->nrxx) { ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", "veff_smooth is not on the rho grid"); @@ -315,9 +326,8 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) if (xc_func_type != 1 && xc_func_type != 2) { std::stringstream msg; - msg << "DFPT supports LDA/GGA functionals only; the ground-state functional '" - << ucell.atoms[0].ncpp.xc_func << "' (func_type " << xc_func_type - << ") needs response channels that are not implemented"; + msg << "DFPT supports LDA/GGA functionals only; the ground-state functional '" << ucell.atoms[0].ncpp.xc_func + << "' (func_type " << xc_func_type << ") needs response channels that are not implemented"; ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", msg.str()); } @@ -333,7 +343,7 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) // plus the nonlinear core correction density when the pseudopotentials // carry one (PotXC_FDM adds chg->rho_core the same way); the first-order // density itself stays valence-only (a frozen core does not respond) - const Charge* chg0 = this->pelec->charge; + const Charge *chg0 = this->pelec->charge; const bool has_core = chg0->rho_core != nullptr; std::vector rho0_r(this->pw_rho->nrxx, 0.0); for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) @@ -345,26 +355,35 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) // LDA, tuned fractions) and the signed per-component combination // factors (e.g. BLYP_LR subtracts its short-range components) const std::vector xc_func_id = XC_Functional::get_func_id(); - const std::vector> xc_ext_params - = XC_Functional_Libxc::ext_params_for(xc_func_id, XC_Functional::get_hybrid_alpha(), XC_Functional::get_hse_omega()); + const std::vector> xc_ext_params = XC_Functional_Libxc::ext_params_for( + xc_func_id, XC_Functional::get_hybrid_alpha(), XC_Functional::get_hse_omega()); std::vector xc_weights(xc_func_id.size(), 1.0); for (size_t i = 0; i < xc_func_id.size(); ++i) { xc_weights[i] = XC_Functional::get_weight(xc_func_id[i]); } - xc_adapter_ = new ModuleDFPT::XC_First_Order_Analytic(xc_func_id, - XC_Functional::get_func_type(), - rho0_r, - this->pw_rho, - xc_ext_params, - xc_weights); + xc_adapter_ = new ModuleDFPT::XC_First_Order_Analytic( + xc_func_id, + XC_Functional::get_func_type(), + rho0_r, + this->pw_rho, + xc_ext_params, + xc_weights); #else - ModuleBase::WARNING("ESolver_DFPT_PW::init_dfpt", - "built without libxc: the DFPT XC kernel falls back to the finite-difference " - "amplitude path (LDA-only support; the GGA response at q != 0 lacks the " - "i(q.f_grad)A carrier term)"); - xc_adapter_ = new XC_First_Order_FDM(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad, - this->inp_->out_elf[0] > 0, this->inp_->test_charge, this->pw_rho, this->pelec->charge, &ucell); + ModuleBase::WARNING( + "ESolver_DFPT_PW::init_dfpt", "built without libxc: the DFPT XC kernel falls back to the finite-difference " + "amplitude path (LDA-only support; the GGA response at q != 0 lacks the " + "i(q.f_grad)A carrier term)"); + xc_adapter_ = new XC_First_Order_FDM( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + this->inp_->out_elf[0] > 0, + this->inp_->test_charge, + this->pw_rho, + this->pelec->charge, + &ucell); #endif if (getenv("DFPT_VKB") != nullptr) @@ -379,15 +398,26 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) gk[ig] = this->pw_wfc->getgpluskcar(ik, ig); } ModuleDFPT::DFPT_Pert pert; - pert.init(ucell, this->pw_rho, this->pw_wfc, this->sf); + pert.init( + ucell, + this->pw_rho, + this->pw_wfc, + this->sf); std::vector>> vkb; - pert.build_vkb(0, 0, gk, vkb); + pert.build_vkb( + 0, + 0, + gk, + vkb); std::vector>> vkb1; - pert.build_vkb(0, 1, gk, vkb1); + pert.build_vkb( + 0, + 1, + gk, + vkb1); const int nh = ucell.atoms[0].ncpp.nh; - const std::complex* gsvkb = this->ppcell.get_vkb_data(); - std::cout << "VKBCHK npw=" << npw << " nh=" << nh - << " nkb=" << this->ppcell.nkb << std::endl; + const std::complex *gsvkb = this->ppcell.get_vkb_data(); + std::cout << "VKBCHK npw=" << npw << " nh=" << nh << " nkb=" << this->ppcell.nkb << std::endl; for (int mu = 0; mu < nh; ++mu) { std::complex dot(0.0, 0.0); @@ -400,8 +430,8 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) nrm_mine += std::norm(vkb[mu][ig]); nrm_gs += std::norm(gs); } - std::cout << "VKBCHK mu=" << mu << " =" << dot - << " |mine|^2=" << nrm_mine << " |gs|^2=" << nrm_gs << std::endl; + std::cout << "VKBCHK mu=" << mu << " =" << dot << " |mine|^2=" << nrm_mine << " |gs|^2=" << nrm_gs + << std::endl; } for (int mu = 0; mu < nh; ++mu) { @@ -415,24 +445,34 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) nrm_mine += std::norm(vkb1[mu][ig]); nrm_gs += std::norm(gs); } - std::cout << "VKBCHK a1 mu=" << mu << " =" << dot - << " |mine|^2=" << nrm_mine << " |gs|^2=" << nrm_gs << std::endl; + std::cout << "VKBCHK a1 mu=" << mu << " =" << dot << " |mine|^2=" << nrm_mine + << " |gs|^2=" << nrm_gs << std::endl; } for (int ig = 0; ig < 6; ++ig) { std::cout << "VKBEL a1 mu=0 ig=" << ig << " mine=" << vkb1[0][ig] - << " gs=" << gsvkb[4 * this->pw_wfc->npwk_max + ig] - << " gcar=" << gk[ig].x << "," << gk[ig].y << "," << gk[ig].z << std::endl; + << " gs=" << gsvkb[4 * this->pw_wfc->npwk_max + ig] << " gcar=" << gk[ig].x << "," << gk[ig].y + << "," << gk[ig].z << std::endl; } } this->stp.sync_cpu(); - dfpt_->init(ucell, *this->stp.psi_cpu, this->pw_rho, this->pw_wfc, &this->sf, veff_r, - this->pelec->wg, this->pelec->ekb, xc_adapter_, nelec_, ecutwfc_, - dft_plus_u_ ? this->dftu_.get() : nullptr); + dfpt_->init( + ucell, + *this->stp.psi_cpu, + this->pw_rho, + this->pw_wfc, + &this->sf, + veff_r, + this->pelec->wg, + this->pelec->ekb, + xc_adapter_, + nelec_, + ecutwfc_, + dft_plus_u_ ? this->dftu_.get() : nullptr); } -void ESolver_DFPT_PW::run_post_process(UnitCell& ucell) +void ESolver_DFPT_PW::run_post_process(UnitCell &ucell) { ModuleBase::TITLE("ESolver_DFPT_PW", "run_post_process"); @@ -453,7 +493,7 @@ void ESolver_DFPT_PW::run_post_process(UnitCell& ucell) std::cout << dfpt_->format_loto_report(); } } - const ModuleBase::matrix& eps = dfpt_->get_dielectric_tensor(); + const ModuleBase::matrix &eps = dfpt_->get_dielectric_tensor(); if (eps.nr == 3 && eps.nc == 3) { std::cout << " DFPT dielectric tensor (epsilon_inf):" << std::endl; @@ -469,7 +509,7 @@ void ESolver_DFPT_PW::run_post_process(UnitCell& ucell) } for (int iat = 0; iat < ucell.nat; ++iat) { - const ModuleBase::matrix& zstar = dfpt_->get_born_charges(iat); + const ModuleBase::matrix &zstar = dfpt_->get_born_charges(iat); if (zstar.nr != 3 || zstar.nc != 3) { continue; diff --git a/source/source_esolver/esolver_dfpt_pw.h b/source/source_esolver/esolver_dfpt_pw.h index 8a2688dfad..817c6d1373 100644 --- a/source/source_esolver/esolver_dfpt_pw.h +++ b/source/source_esolver/esolver_dfpt_pw.h @@ -12,7 +12,8 @@ #include "esolver_ks_pw.h" #include "source_pw/module_dfpt/dfpt_pw.h" -namespace ModuleDFPT { +namespace ModuleDFPT +{ class XC_First_Order; } @@ -25,16 +26,16 @@ class ESolver_DFPT_PW : public ESolver_KS_PW, base_device:: ESolver_DFPT_PW(); ~ESolver_DFPT_PW(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; - void runner(BaseCell& basecell, const int istep) override; - void after_all_runners(BaseCell& basecell) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; + void runner(BaseCell &basecell, const int istep) override; + void after_all_runners(BaseCell &basecell) override; protected: - ModuleDFPT::DFPT_PW* dfpt_ = nullptr; + ModuleDFPT::DFPT_PW *dfpt_ = nullptr; ///< first-order XC kernel adapter over elecstate::PotXC_FDM (C7), ///< owned here so module_dfpt stays free of pot_xc_fdm.h dependencies - ModuleDFPT::XC_First_Order* xc_adapter_ = nullptr; + ModuleDFPT::XC_First_Order *xc_adapter_ = nullptr; bool gs_done_ = false; @@ -51,14 +52,14 @@ class ESolver_DFPT_PW : public ESolver_KS_PW, base_device:: bool dft_plus_u_ = false; - void run_gs(UnitCell& ucell); + void run_gs(UnitCell &ucell); /// wires DFPT_PW with the converged ground state; called after run_gs /// (the injected veff/XC reference data only exist once the GS SCF is /// done) - void init_dfpt(UnitCell& ucell); + void init_dfpt(UnitCell &ucell); - void run_post_process(UnitCell& ucell); + void run_post_process(UnitCell &ucell); }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_dm2rho.cpp b/source/source_esolver/esolver_dm2rho.cpp index 77b7825cc3..3ff8973429 100644 --- a/source/source_esolver/esolver_dm2rho.cpp +++ b/source/source_esolver/esolver_dm2rho.cpp @@ -6,31 +6,27 @@ #include "source_estate/elecstate_lcao.h" #include "source_io/module_ml/io_npz.h" #include "source_io/module_output/cube_io.h" -#include "source_lcao/lcao_domain.h" #include "source_lcao/hamilt_lcao.h" +#include "source_lcao/lcao_domain.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" #include "source_lcao/rho_tau_lcao.h" // mohan add 2025-10-24 namespace ModuleESolver { -template -ESolver_DM2rho::ESolver_DM2rho() +template ESolver_DM2rho::ESolver_DM2rho() { this->classname = "ESolver_DM2rho"; this->basisname = "LCAO"; } -template -ESolver_DM2rho::~ESolver_DM2rho() -{ -} +template ESolver_DM2rho::~ESolver_DM2rho() {} template -void ESolver_DM2rho::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_DM2rho::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DM2rho", "before_all_runners"); ModuleBase::timer::start("ESolver_DM2rho", "before_all_runners"); @@ -40,11 +36,10 @@ void ESolver_DM2rho::before_all_runners(BaseCell& basecell, const Input_ ModuleBase::timer::end("ESolver_DM2rho", "before_all_runners"); } -template -void ESolver_DM2rho::runner(BaseCell& basecell, const int istep) +template void ESolver_DM2rho::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DM2rho", "runner"); ModuleBase::timer::start("ESolver_DM2rho", "runner"); @@ -55,18 +50,32 @@ void ESolver_DM2rho::runner(BaseCell& basecell, const int istep) std::string zipname = "output_DM0.npz"; // read DM from file - ModuleIO::read_mat_npz(&(this->pv), ucell, zipname, *(this->dmat.dm->get_dmr_ptr(1))); + ModuleIO::read_mat_npz( + &(this->pv), + ucell, + zipname, + *(this->dmat.dm->get_dmr_ptr(1))); // if nspin=2, need extra reading if (this->inp_->nspin == 2) { zipname = "output_DM1.npz"; - ModuleIO::read_mat_npz(&(this->pv), ucell, zipname, *(this->dmat.dm->get_dmr_ptr(2))); + ModuleIO::read_mat_npz( + &(this->pv), + ucell, + zipname, + *(this->dmat.dm->get_dmr_ptr(2))); } // it's dangerous to design psiToRho function like this, mohan note 20251024 // this->pelec->psiToRho(*this->psi); - LCAO_domain::dm2rho(this->dmat.dm->get_dmr_vec(), this->inp_->nspin, &this->chr, this->inp_->nelec, ucell.omega, false); + LCAO_domain::dm2rho( + this->dmat.dm->get_dmr_vec(), + this->inp_->nspin, + &this->chr, + this->inp_->nelec, + ucell.omega, + false); // Write every density channel (rho[0..3] for nspin=4) so the file set // matches ctrl_output_fp: the init_chg=file reader reads chgs1..chgs @@ -85,32 +94,36 @@ void ESolver_DM2rho::runner(BaseCell& basecell, const int istep) fn += ".cube"; // write electron density - const std::string desc_chg = ModuleIO::make_data_desc("charge density", "magnetization density m", is, nspin); - - ModuleIO::write_vdata_palgrid(this->Pgrid, - this->chr.rho[is], - is, - nspin, - istep, - fn, - this->pelec->eferm.get_efval(is), - &(ucell), - 3, - 1, - PARAM.globalv.two_fermi, - false, - GlobalV::ofs_running, - desc_chg); + const std::string desc_chg = ModuleIO::make_data_desc( + "charge density", + "magnetization density m", + is, + nspin); + + ModuleIO::write_vdata_palgrid( + this->Pgrid, + this->chr.rho[is], + is, + nspin, + istep, + fn, + this->pelec->eferm.get_efval(is), + &(ucell), + 3, + 1, + PARAM.globalv.two_fermi, + false, + GlobalV::ofs_running, + desc_chg); } ModuleBase::timer::end("ESolver_DM2rho", "runner"); } -template -void ESolver_DM2rho::after_all_runners(BaseCell& basecell) +template void ESolver_DM2rho::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DM2rho", "after_all_runners"); ModuleBase::timer::start("ESolver_DM2rho", "after_all_runners"); diff --git a/source/source_esolver/esolver_dm2rho.h b/source/source_esolver/esolver_dm2rho.h index 66bd959f85..79e05bfe8b 100644 --- a/source/source_esolver/esolver_dm2rho.h +++ b/source/source_esolver/esolver_dm2rho.h @@ -8,18 +8,17 @@ namespace ModuleESolver { -template -class ESolver_DM2rho : public ESolver_KS_LCAO +template class ESolver_DM2rho : public ESolver_KS_LCAO { public: ESolver_DM2rho(); ~ESolver_DM2rho(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; - void runner(BaseCell& basecell, const int istep) override; + void runner(BaseCell &basecell, const int istep) override; }; } // namespace ModuleESolver #endif diff --git a/source/source_esolver/esolver_double_xc.cpp b/source/source_esolver/esolver_double_xc.cpp index 5afe888d97..820d494d50 100644 --- a/source/source_esolver/esolver_double_xc.cpp +++ b/source/source_esolver/esolver_double_xc.cpp @@ -23,15 +23,13 @@ namespace ModuleESolver { -template -ESolver_DoubleXC::ESolver_DoubleXC() +template ESolver_DoubleXC::ESolver_DoubleXC() { this->classname = "ESolver_DoubleXC"; this->basisname = "LCAO"; } -template -ESolver_DoubleXC::~ESolver_DoubleXC() +template ESolver_DoubleXC::~ESolver_DoubleXC() { delete this->psi_base; delete this->p_hamilt_base; @@ -39,10 +37,10 @@ ESolver_DoubleXC::~ESolver_DoubleXC() } template -void ESolver_DoubleXC::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_DoubleXC::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DoubleXC", "before_all_runners"); ModuleBase::timer::start("ESolver_DoubleXC", "before_all_runners"); @@ -54,10 +52,11 @@ void ESolver_DoubleXC::before_all_runners(BaseCell& basecell, const Inpu // 2) init ElecState if (this->pelec_base == nullptr) { - this->pelec_base = new elecstate::ElecStateLCAO(&(this->chr_base), // use which parameter? - &(this->kv), - this->kv.get_nks(), - this->pw_big); + this->pelec_base = new elecstate::ElecStateLCAO( + &(this->chr_base), // use which parameter? + &(this->kv), + this->kv.get_nks(), + this->pw_big); } // 4) initialize electronic wave function psi @@ -69,9 +68,9 @@ void ESolver_DoubleXC::before_all_runners(BaseCell& basecell, const Inpu { nsk = this->inp_->nspin; ncol = this->pv.ncol_bands; - if (this->inp_->ks_solver == "genelpa" || this->inp_->ks_solver == "elpa" || this->inp_->ks_solver == "lapack" - || this->inp_->ks_solver == "pexsi" || this->inp_->ks_solver == "cusolver" - || this->inp_->ks_solver == "cusolvermp") + if (this->inp_->ks_solver == "genelpa" || this->inp_->ks_solver == "elpa" || + this->inp_->ks_solver == "lapack" || this->inp_->ks_solver == "pexsi" || + this->inp_->ks_solver == "cusolver" || this->inp_->ks_solver == "cusolvermp") { ncol = this->pv.ncol; } @@ -85,11 +84,20 @@ void ESolver_DoubleXC::before_all_runners(BaseCell& basecell, const Inpu ncol = this->inp_->nbands; #endif } - this->psi_base = new psi::Psi(nsk, ncol, this->pv.nrow, this->kv.ngk, true); + this->psi_base = new psi::Psi( + nsk, + ncol, + this->pv.nrow, + this->kv.ngk, + true); } // 6) initialize the density matrix - LCAO_domain::allocate_dm(this->dmat_base, &this->kv, &this->pv, this->inp_->nspin); + LCAO_domain::allocate_dm( + this->dmat_base, + &this->kv, + &this->pv, + this->inp_->nspin); // 10) inititlize the charge density module_charge::InitRhoCfg init_rho_cfg; @@ -104,33 +112,47 @@ void ESolver_DoubleXC::before_all_runners(BaseCell& basecell, const Inpu init_rho_cfg.domag_z = PARAM.globalv.domag_z; init_rho_cfg.npol = PARAM.globalv.npol; init_rho_cfg.meta_gga = XC_Functional::get_ked_flag(); - this->chr_base.set_rhopw(this->pw_rhod); // mohan add 20251130 + this->chr_base.set_rhopw(this->pw_rhod); // mohan add 20251130 const bool kin_den = XC_Functional::get_ked_flag() || (this->inp_->out_elf[0] > 0); // mohan add 20251202 - this->chr_base.allocate(this->inp_->nspin, kin_den, XC_Functional::get_ked_flag(), - this->inp_->test_charge); - this->chr_base.init_rho(ucell, this->Pgrid, this->sf.strucFac, ucell.symm, &this->kv, nullptr, init_rho_cfg); - module_charge::check_rho(this->chr_base.rho, this->chr_base.nspin, - this->chr_base.rhopw->nrxx, ucell.omega, - this->chr_base.rhopw->nxyz, this->inp_->nelec); + this->chr_base.allocate( + this->inp_->nspin, + kin_den, + XC_Functional::get_ked_flag(), + this->inp_->test_charge); + this->chr_base.init_rho( + ucell, + this->Pgrid, + this->sf.strucFac, + ucell.symm, + &this->kv, + nullptr, + init_rho_cfg); + module_charge::check_rho( + this->chr_base.rho, + this->chr_base.nspin, + this->chr_base.rhopw->nrxx, + ucell.omega, + this->chr_base.rhopw->nxyz, + this->inp_->nelec); // 11) initialize the potential if (this->pelec_base->pot == nullptr) { - this->pelec_base->pot = new elecstate::Potential(this->pw_rhod, - this->pw_rho, - &ucell, - &(this->locpp.vloc), - &(this->sf), - &(this->solvent), - &(this->pelec_base->f_en.etxc), - &(this->pelec_base->f_en.vtxc)); + this->pelec_base->pot = new elecstate::Potential( + this->pw_rhod, + this->pw_rho, + &ucell, + &(this->locpp.vloc), + &(this->sf), + &(this->solvent), + &(this->pelec_base->f_en.etxc), + &(this->pelec_base->f_en.vtxc)); } ModuleBase::timer::end("ESolver_DoubleXC", "before_all_runners"); } -template -void ESolver_DoubleXC::before_scf(UnitCell& ucell, const int istep) +template void ESolver_DoubleXC::before_scf(UnitCell &ucell, const int istep) { ModuleBase::TITLE("ESolver_DoubleXC", "before_scf"); ModuleBase::timer::start("ESolver_DoubleXC", "before_scf"); @@ -158,39 +180,40 @@ void ESolver_DoubleXC::before_scf(UnitCell& ucell, const int istep) } if (this->p_hamilt_base == nullptr) { - const bool load_exx_flag = !GlobalC::restart.info_load.restart_exx - && GlobalC::restart.info_load.load_H; - this->p_hamilt_base = new hamilt::HamiltLCAO(ucell, - this->gd, - &this->pv, - this->pelec_base->pot, - this->kv, - this->two_center_bundle_, - this->orb_, - this->dmat_base.dm, - this->dftu_.get(), - this->deepks, - istep, - this->exx_nao, - this->exx_info_, - *this->inp_, - load_exx_flag, - nullptr); + const bool load_exx_flag = !GlobalC::restart.info_load.restart_exx && GlobalC::restart.info_load.load_H; + this->p_hamilt_base = new hamilt::HamiltLCAO( + ucell, + this->gd, + &this->pv, + this->pelec_base->pot, + this->kv, + this->two_center_bundle_, + this->orb_, + this->dmat_base.dm, + this->dftu_.get(), + this->deepks, + istep, + this->exx_nao, + this->exx_info_, + *this->inp_, + load_exx_flag, + nullptr); } XC_Functional::set_xc_type(this->inp_->deepks_out_base); - elecstate::init_scf(ucell, - this->Pgrid, - this->sf.strucFac, - this->locpp.numeric, - istep, - PARAM.globalv.global_out_dir, - *this->inp_, - this->pelec_base); + elecstate::init_scf( + ucell, + this->Pgrid, + this->sf.strucFac, + this->locpp.numeric, + istep, + PARAM.globalv.global_out_dir, + *this->inp_, + this->pelec_base); XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); // DMR should be same size with Hamiltonian(R) - this->dmat_base.dm->init_dmr(*(dynamic_cast*>(this->p_hamilt_base)->getHR())); + this->dmat_base.dm->init_dmr(*(dynamic_cast *>(this->p_hamilt_base)->getHR())); if (istep > 0) { @@ -202,13 +225,17 @@ void ESolver_DoubleXC::before_scf(UnitCell& ucell, const int istep) } template -void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) +void ESolver_DoubleXC::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { ModuleBase::TITLE("ESolver_DoubleXC", "iter_finish"); ModuleBase::timer::start("ESolver_DoubleXC", "iter_finish"); - bool output_iter = this->inp_->deepks_out_labels > 0 && this->inp_->deepks_out_freq_elec - && (iter % this->inp_->deepks_out_freq_elec == 0); + bool output_iter = this->inp_->deepks_out_labels > 0 && this->inp_->deepks_out_freq_elec && + (iter % this->inp_->deepks_out_freq_elec == 0); if (output_iter) { @@ -223,7 +250,11 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int } } - ESolver_KS_LCAO::iter_finish(ucell, istep, iter, conv_esolver); + ESolver_KS_LCAO::iter_finish( + ucell, + istep, + iter, + conv_esolver); // for deepks, output labels during electronic steps (after conv_esolver is renewed) if (output_iter) @@ -232,11 +263,12 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int // get etot of output charge density, now the etot is of density after charge mixing this->pelec->pot->update_from_charge(&this->chr_base, &ucell); this->pelec->f_en.descf = 0.0; - this->pelec->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + this->pelec->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); // std::cout<<"in deepks etot------"<pelec->f_en.print_all(); // std::cout<<"in deepks etot------"<::iter_finish(UnitCell& ucell, const int istep, int #ifdef __MLALGO // ---------- output tot and precalc ---------- - hamilt::HamiltLCAO* p_ham_deepks = dynamic_cast*>(this->p_hamilt); + hamilt::HamiltLCAO *p_ham_deepks = dynamic_cast *>(this->p_hamilt); LCAO_Deepks_Interface deepks_interface(&this->deepks.ld); - deepks_interface.out_deepks_labels(this->pelec->f_en.etot, - this->kv.get_nks(), - ucell.nat, - PARAM.globalv.nlocal, - this->pelec->ekb, - this->kv.kvec_d, - ucell, - this->orb_, - this->gd, - &(this->pv), - *(this->psi), - this->dmat.dm, - p_ham_deepks, - iter, - conv_esolver, - GlobalV::MY_RANK, - GlobalV::ofs_running); + deepks_interface.out_deepks_labels( + this->pelec->f_en.etot, + this->kv.get_nks(), + ucell.nat, + PARAM.globalv.nlocal, + this->pelec->ekb, + this->kv.kvec_d, + ucell, + this->orb_, + this->gd, + &(this->pv), + *(this->psi), + this->dmat.dm, + p_ham_deepks, + iter, + conv_esolver, + GlobalV::MY_RANK, + GlobalV::ofs_running); #endif // restore to density after charge mixing @@ -301,14 +334,15 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int this->pelec_base->f_en.deband = this->pelec->f_en.deband; this->pelec_base->f_en.demet = this->pelec->f_en.demet; this->pelec_base->f_en.descf = 0.0; // set descf to 0 - this->pelec_base->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); // 2 means Kohn-Sham functional - // std::cout<<"in double_xc------"<pelec_base->f_en.print_all(); - // std::cout<<"in double_xc------"<pelec_base->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); // 2 means Kohn-Sham functional + // std::cout<<"in double_xc------"<pelec_base->f_en.print_all(); + // std::cout<<"in double_xc------"<f_en.etot << // std::endl; @@ -331,16 +365,27 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int // which will change the hsolver::DiagoElpa::DecomposedState, influencing the following SCF steps #ifdef __MLALGO - using TH - = std::conditional_t::value, ModuleBase::matrix, ModuleBase::ComplexMatrix>; - hamilt::HamiltLCAO* p_ham_deepks_base - = dynamic_cast*>(this->p_hamilt_base); + using TH = + std::conditional_t::value, ModuleBase::matrix, ModuleBase::ComplexMatrix>; + hamilt::HamiltLCAO *p_ham_deepks_base = + dynamic_cast *>(this->p_hamilt_base); int nks = this->kv.get_nks(); std::vector h_tot(nks); - DeePKS_domain::get_h_tot(this->pv, p_ham_deepks_base, h_tot, PARAM.globalv.nlocal, nks, 'H'); + DeePKS_domain::get_h_tot( + this->pv, + p_ham_deepks_base, + h_tot, + PARAM.globalv.nlocal, + nks, + 'H'); const std::string file_htot = deepks_interface.get_filename("hbase", this->inp_->deepks_out_labels, iter); - LCAO_deepks_io::save_npy_h(h_tot, file_htot, PARAM.globalv.nlocal, nks, GlobalV::MY_RANK); + LCAO_deepks_io::save_npy_h( + h_tot, + file_htot, + PARAM.globalv.nlocal, + nks, + GlobalV::MY_RANK); #endif } @@ -387,8 +432,8 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int // copy dm int nks = this->kv.get_nks(); - auto _pes_lcao_base = dynamic_cast*>(this->pelec_base); - auto _pes_lcao = dynamic_cast*>(this->pelec); + auto _pes_lcao_base = dynamic_cast *>(this->pelec_base); + auto _pes_lcao = dynamic_cast *>(this->pelec); for (int ik = 0; ik < nks; ik++) { // mohan update 2025-11-03 @@ -406,10 +451,10 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int } template -void ESolver_DoubleXC::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_DoubleXC::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_DoubleXC", "cal_force"); ModuleBase::timer::start("ESolver_DoubleXC", "cal_force"); @@ -424,37 +469,46 @@ void ESolver_DoubleXC::cal_force(BaseCell& basecell, ModuleBase::matrix& this->deepks.dpks_out_type = "base"; // for deepks method - const FSCalcConfig fs_cfg{this->inp_->nspin, this->inp_->nbands, this->inp_->t_in_h, - this->inp_->sc_mag_switch, this->inp_->device, - PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad, - PARAM.globalv.gamma_only_pw, this->inp_->imp_sol}; - - fsl.getForceStress(ucell, - this->get_vdw_result(), - this->inp_->cal_force, - this->inp_->cal_stress, - this->inp_->test_force, - this->inp_->test_stress, - this->gd, - this->pv, - this->pelec_base, - this->dmat_base, // mohan add 2025-11-03 - this->psi, - this->two_center_bundle_, - this->orb_, - force_base, - stress_base, - this->locpp, - this->sf, - this->kv, - this->pw_rho, - this->solvent, - *this->dftu_, - this->deepks, - this->exx_nao, - &ucell.symm, - this->exx_info_, - fs_cfg, nullptr, nullptr); + const FSCalcConfig fs_cfg{this->inp_->nspin, + this->inp_->nbands, + this->inp_->t_in_h, + this->inp_->sc_mag_switch, + this->inp_->device, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + PARAM.globalv.gamma_only_pw, + this->inp_->imp_sol}; + + fsl.getForceStress( + ucell, + this->get_vdw_result(), + this->inp_->cal_force, + this->inp_->cal_stress, + this->inp_->test_force, + this->inp_->test_stress, + this->gd, + this->pv, + this->pelec_base, + this->dmat_base, // mohan add 2025-11-03 + this->psi, + this->two_center_bundle_, + this->orb_, + force_base, + stress_base, + this->locpp, + this->sf, + this->kv, + this->pw_rho, + this->solvent, + *this->dftu_, + this->deepks, + this->exx_nao, + &ucell.symm, + this->exx_info_, + fs_cfg, + nullptr, + nullptr); // restore to original xc XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); diff --git a/source/source_esolver/esolver_double_xc.h b/source/source_esolver/esolver_double_xc.h index d2aca66184..f82edc09bf 100644 --- a/source/source_esolver/esolver_double_xc.h +++ b/source/source_esolver/esolver_double_xc.h @@ -6,30 +6,33 @@ namespace ModuleESolver { // used in deepks, run target and base xc functional simultaneously -template -class ESolver_DoubleXC : public ESolver_KS_LCAO +template class ESolver_DoubleXC : public ESolver_KS_LCAO { public: ESolver_DoubleXC(); ~ESolver_DoubleXC(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; protected: - void before_scf(UnitCell& ucell, const int istep) override; + void before_scf(UnitCell &ucell, const int istep) override; - void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; //! Hamiltonian - hamilt::Hamilt* p_hamilt_base = nullptr; + hamilt::Hamilt *p_hamilt_base = nullptr; //! Electronic wavefunctions - psi::Psi* psi_base = nullptr; + psi::Psi *psi_base = nullptr; //! Electronic states - elecstate::ElecState* pelec_base = nullptr; + elecstate::ElecState *pelec_base = nullptr; //! Density Matrix, mohan add 2025-11-03 module_dm::Setup_DM dmat_base; diff --git a/source/source_esolver/esolver_dp.cpp b/source/source_esolver/esolver_dp.cpp index 98708ee051..abee4a2661 100644 --- a/source/source_esolver/esolver_dp.cpp +++ b/source/source_esolver/esolver_dp.cpp @@ -18,17 +18,18 @@ * @date 2023-05-15 */ #include "esolver_dp.h" + #include "source_base/parallel_common.h" #include "source_base/timer.h" +#include "source_cell/cif_io.h" #include "source_cell/ghost_exchange_plan.h" #include "source_cell/mdcell.h" #include "source_cell/module_neighlist/neighbor_search.h" -#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" -#include #include +#include #include #include @@ -42,7 +43,7 @@ using DPInputNlist = deepmd::InputNlist; #endif #endif -void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_DP::before_all_runners(BaseCell &basecell, const Input_para &inp) { this->inp_ = &inp; dp_potential = 0; @@ -53,7 +54,7 @@ void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) if (basecell.kind() == BaseCell::Kind::mdcell) { - MDCell& mdcell = static_cast(basecell); + MDCell &mdcell = static_cast(basecell); #ifdef __DPMD mdcell.set_neighbor_cutoff(dp.cutoff() * ModuleBase::ANGSTROM_AU); initialize_type_map_(mdcell.type_labels()); @@ -63,19 +64,20 @@ void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) return; } - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); dp_force.create(ucell.nat, 3); - ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", - ucell, - "# Generated by ABACUS ModuleIO::CifParser", - "data_?"); + ModuleIO::CifParser::write( + PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); atype.resize(ucell.nat); #ifdef __DPMD type_map(ucell); #endif } -void ESolver_DP::runner(BaseCell& basecell, const int istep) +void ESolver_DP::runner(BaseCell &basecell, const int istep) { ModuleBase::TITLE("ESolver_DP", "runner"); ModuleBase::timer::start("ESolver_DP", "runner"); @@ -86,7 +88,7 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) ModuleBase::WARNING_QUIT("ESolver_DP", "Please recompile with -D__DPMD"); #else static_cast(istep); - MDCell& mdcell = static_cast(basecell); + MDCell &mdcell = static_cast(basecell); if (!mdcell.has_neighbor_search()) { ModuleBase::WARNING_QUIT("ESolver", "MDCell neighbors must be prepared by the caller before runner()."); @@ -110,14 +112,14 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) cell[7] = mdcell.latvec().e32 * mdcell.lat0() * ModuleBase::BOHR_TO_A; cell[8] = mdcell.latvec().e33 * mdcell.lat0() * ModuleBase::BOHR_TO_A; - const std::vector& owned_atoms = mdcell.owned_atoms(); - const std::vector& ghost_atoms = mdcell.ghost_atoms(); + const std::vector &owned_atoms = mdcell.owned_atoms(); + const std::vector &ghost_atoms = mdcell.ghost_atoms(); std::vector coord(static_cast(3 * natom), 0.0); std::vector local_atype(static_cast(natom), 0); for (int iat = 0; iat < natom; ++iat) { - const LocalAtom& atom = iat < nowned_atoms ? owned_atoms[static_cast(iat)] - : ghost_atoms[static_cast(iat - nowned_atoms)]; + const LocalAtom &atom = iat < nowned_atoms ? owned_atoms[static_cast(iat)] + : ghost_atoms[static_cast(iat - nowned_atoms)]; coord[3 * iat] = atom.cart.x * mdcell.lat0() * ModuleBase::BOHR_TO_A; coord[3 * iat + 1] = atom.cart.y * mdcell.lat0() * ModuleBase::BOHR_TO_A; coord[3 * iat + 2] = atom.cart.z * mdcell.lat0() * ModuleBase::BOHR_TO_A; @@ -131,54 +133,79 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) const int dim_aparam = dp.dim_aparam(); if (dim_aparam > 0) { - ModuleBase::WARNING_QUIT("ESolver_DP", - "MDCell support does not yet support DeePMD atomic parameters (dim_aparam > 0)."); + ModuleBase::WARNING_QUIT( + "ESolver_DP", "MDCell support does not yet support DeePMD atomic parameters (dim_aparam > 0)."); } - const NeighborList& neighbor_list = mdcell.neighbor_search().get_neighbor_list(); + const NeighborList &neighbor_list = mdcell.neighbor_search().get_neighbor_list(); std::vector ilist(static_cast(nowned_atoms), 0); std::vector numneigh(static_cast(nowned_atoms), 0); - std::vector firstneigh(static_cast(nowned_atoms), NULL); - std::vector > sorted_neighbors(static_cast(nowned_atoms)); + std::vector firstneigh(static_cast(nowned_atoms), NULL); + std::vector> sorted_neighbors(static_cast(nowned_atoms)); for (int iat = 0; iat < nowned_atoms; ++iat) { ilist[static_cast(iat)] = iat; - sorted_neighbors[static_cast(iat)] - = neighbor_list.get_neighbors_sorted_by_distance(iat, coord); - numneigh[static_cast(iat)] - = static_cast(sorted_neighbors[static_cast(iat)].size()); - firstneigh[static_cast(iat)] - = sorted_neighbors[static_cast(iat)].empty() - ? NULL - : sorted_neighbors[static_cast(iat)].data(); + sorted_neighbors[static_cast(iat)] = + neighbor_list.get_neighbors_sorted_by_distance(iat, coord); + numneigh[static_cast(iat)] = + static_cast(sorted_neighbors[static_cast(iat)].size()); + firstneigh[static_cast(iat)] = sorted_neighbors[static_cast(iat)].empty() + ? NULL + : sorted_neighbors[static_cast(iat)].data(); } - GhostExchangePlan& ghost_plan = mdcell.get_ghost_exchange_plan(); + GhostExchangePlan &ghost_plan = mdcell.get_ghost_exchange_plan(); const bool use_mapping = ghost_plan.nprocs == 1; if (!ghost_plan.is_valid(static_cast(natom))) { ModuleBase::WARNING_QUIT("ESolver_DP", "Invalid MDCell ghost exchange plan."); } GhostExchangePlanView view = ghost_plan.make_view(); - int** sendlist_data = view.sendlist_storage.empty() ? NULL : view.sendlist_storage.data(); - int* ilist_data = nowned_atoms > 0 ? &ilist[0] : NULL; - int* numneigh_data = nowned_atoms > 0 ? &numneigh[0] : NULL; - int** firstneigh_data = nowned_atoms > 0 ? &firstneigh[0] : NULL; - int* mapping_data = use_mapping ? view.mapping : NULL; - void* dp_world = NULL; + int **sendlist_data = view.sendlist_storage.empty() ? NULL : view.sendlist_storage.data(); + int *ilist_data = nowned_atoms > 0 ? &ilist[0] : NULL; + int *numneigh_data = nowned_atoms > 0 ? &numneigh[0] : NULL; + int **firstneigh_data = nowned_atoms > 0 ? &firstneigh[0] : NULL; + int *mapping_data = use_mapping ? view.mapping : NULL; + void *dp_world = NULL; #ifdef __MPI MPI_Comm dp_world_comm = mdcell.communicator(); dp_world = &dp_world_comm; #endif #if defined(__DPMD_COMM_NLIST_ARGS) && __DPMD_COMM_NLIST_ARGS == 13 - DPInputNlist nlist(nowned_atoms, ilist_data, numneigh_data, firstneigh_data, view.nswap, view.sendnum, view.recvnum, view.firstrecv, sendlist_data, view.sendproc, view.recvproc, dp_world, ghost_plan.nprocs); + DPInputNlist nlist( + nowned_atoms, + ilist_data, + numneigh_data, + firstneigh_data, + view.nswap, + view.sendnum, + view.recvnum, + view.firstrecv, + sendlist_data, + view.sendproc, + view.recvproc, + dp_world, + ghost_plan.nprocs); #elif defined(__DPMD_COMM_NLIST_ARGS) && __DPMD_COMM_NLIST_ARGS == 12 - DPInputNlist nlist(nowned_atoms, ilist_data, numneigh_data, firstneigh_data, view.nswap, view.sendnum, view.recvnum, view.firstrecv, sendlist_data, view.sendproc, view.recvproc, dp_world); + DPInputNlist nlist( + nowned_atoms, + ilist_data, + numneigh_data, + firstneigh_data, + view.nswap, + view.sendnum, + view.recvnum, + view.firstrecv, + sendlist_data, + view.sendproc, + view.recvproc, + dp_world); #else - DPInputNlist nlist(nowned_atoms, - ilist_data, - numneigh_data, - firstneigh_data); + DPInputNlist nlist( + nowned_atoms, + ilist_data, + numneigh_data, + firstneigh_data); #endif #ifdef __DPMD_HAS_NLIST_MAPPING if (use_mapping) @@ -189,24 +216,35 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) double local_energy = 0.0; std::vector force, virial; ModuleBase::timer::start("ESolver_DP", "compute"); - dp.compute(local_energy, force, virial, coord, local_atype, cell, nghost, nlist, 0, fparam); + dp.compute( + local_energy, + force, + virial, + coord, + local_atype, + cell, + nghost, + nlist, + 0, + fparam); ModuleBase::timer::end("ESolver_DP", "compute"); if (force.size() != static_cast(3 * natom)) { ModuleBase::WARNING_QUIT("ESolver_DP", "DeePMD returned an invalid force array for MDCell."); } - std::vector& mutable_owned_atoms = mdcell.owned_atoms(); - std::vector& mutable_ghost_atoms = mdcell.ghost_atoms(); + std::vector &mutable_owned_atoms = mdcell.owned_atoms(); + std::vector &mutable_ghost_atoms = mdcell.ghost_atoms(); for (int iat = 0; iat < nowned_atoms; ++iat) { - mutable_owned_atoms[static_cast(iat)].force.set(force[3 * iat], force[3 * iat + 1], force[3 * iat + 2]); + mutable_owned_atoms[static_cast(iat)].force.set( + force[3 * iat], force[3 * iat + 1], force[3 * iat + 2]); } for (int iat = 0; iat < nghost; ++iat) { - mutable_ghost_atoms[static_cast(iat)].force.set(force[3 * (nowned_atoms + iat)], - force[3 * (nowned_atoms + iat) + 1], - force[3 * (nowned_atoms + iat) + 2]); + mutable_ghost_atoms[static_cast(iat)].force.set( + force[3 * (nowned_atoms + iat)], force[3 * (nowned_atoms + iat) + 1], + force[3 * (nowned_atoms + iat) + 2]); } if (virial.size() != 9) @@ -217,8 +255,20 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) std::array local_virial; std::copy(virial.begin(), virial.end(), local_virial.begin()); #ifdef __MPI - MPI_Allreduce(MPI_IN_PLACE, &local_energy, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); - MPI_Allreduce(MPI_IN_PLACE, local_virial.data(), 9, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + &local_energy, + 1, + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + local_virial.data(), + 9, + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); #endif const double fact_e = rescaling / ModuleBase::Ry_to_eV; const double fact_f = rescaling / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); @@ -226,22 +276,26 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) dp_potential = local_energy * fact_e; for (int iat = 0; iat < nowned_atoms; ++iat) { - LocalAtom& atom = mutable_owned_atoms[static_cast(iat)]; + LocalAtom &atom = mutable_owned_atoms[static_cast(iat)]; atom.force *= fact_f; } - for (LocalAtom& atom : mutable_ghost_atoms) + for (LocalAtom &atom : mutable_ghost_atoms) { atom.force *= fact_f; } for (int i = 0; i < 3; ++i) + { for (int j = 0; j < 3; ++j) + { dp_virial(i, j) = local_virial[static_cast(3 * i + j)] * fact_v; + } + } #endif ModuleBase::timer::end("ESolver_DP", "runner"); return; } - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); std::vector cell(9, 0.0); cell[0] = ucell.latvec.e11 * ucell.lat0_angstrom; @@ -274,7 +328,15 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) dp_force.zero_out(); dp_virial.zero_out(); - dp.compute(dp_potential, f, v, coord, atype, cell, fparam, aparam); + dp.compute( + dp_potential, + f, + v, + coord, + atype, + cell, + fparam, + aparam); // rescale the energy, force, and stress const double fact_e = rescaling / ModuleBase::Ry_to_eV; @@ -305,20 +367,17 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) ModuleBase::timer::end("ESolver_DP", "runner"); } -double ESolver_DP::cal_energy() -{ - return dp_potential; -} +double ESolver_DP::cal_energy() { return dp_potential; } -void ESolver_DP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_DP::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { if (basecell.kind() == BaseCell::Kind::mdcell) { - const MDCell& mdcell = static_cast(basecell); + const MDCell &mdcell = static_cast(basecell); force.create(mdcell.owned_atoms().size(), 3); for (int iat = 0; iat < mdcell.owned_atoms().size(); ++iat) { - const LocalAtom& atom = mdcell.owned_atoms()[static_cast(iat)]; + const LocalAtom &atom = mdcell.owned_atoms()[static_cast(iat)]; force(iat, 0) = atom.force.x; force(iat, 1) = atom.force.y; force(iat, 2) = atom.force.z; @@ -326,26 +385,39 @@ void ESolver_DP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) return; } force = dp_force; - ModuleIO::print_force(GlobalV::ofs_running, - static_cast(basecell), - "TOTAL-FORCE (eV/Angstrom)", force, false); + ModuleIO::print_force( + GlobalV::ofs_running, + static_cast(basecell), + "TOTAL-FORCE (eV/Angstrom)", + force, + false); } -void ESolver_DP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_DP::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { stress = dp_virial; if (basecell.kind() == BaseCell::Kind::unitcell) { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } else { #ifdef __MPI - if (static_cast(basecell).mpi_rank() == 0) + if (static_cast(basecell).mpi_rank() == 0) #endif { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } } @@ -358,7 +430,7 @@ void ESolver_DP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) } } -void ESolver_DP::after_all_runners(BaseCell& basecell) +void ESolver_DP::after_all_runners(BaseCell &basecell) { static_cast(basecell); @@ -369,7 +441,7 @@ void ESolver_DP::after_all_runners(BaseCell& basecell) } #ifdef __DPMD -void ESolver_DP::type_map(const UnitCell& ucell) +void ESolver_DP::type_map(const UnitCell &ucell) { std::vector type_labels(static_cast(ucell.ntype)); for (int it = 0; it < ucell.ntype; ++it) @@ -389,7 +461,7 @@ void ESolver_DP::type_map(const UnitCell& ucell) assert(ucell.nat == iat); } -void ESolver_DP::initialize_type_map_(const std::vector& type_labels) +void ESolver_DP::initialize_type_map_(const std::vector &type_labels) { std::string type = ""; dp.get_type_map(type); @@ -425,8 +497,7 @@ void ESolver_DP::initialize_type_map_(const std::vector& type_label const std::unordered_map::const_iterator found = label.find(type_labels[it]); if (found == label.end()) { - ModuleBase::WARNING_QUIT("ESolver_DP", - "The label " + type_labels[it] + " is not found in the type map."); + ModuleBase::WARNING_QUIT("ESolver_DP", "The label " + type_labels[it] + " is not found in the type map."); } md_type_to_dp_type_[it] = found->second; } diff --git a/source/source_esolver/esolver_dp.h b/source/source_esolver/esolver_dp.h index 8b8067552d..741ee762b5 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -17,13 +17,13 @@ class ESolver_DP : public ESolver { public: #ifdef __DPMD - ESolver_DP(const std::string& pot_file) : dp(pot_file) + ESolver_DP(const std::string &pot_file) : dp(pot_file) { classname = "ESolver_DP"; dp_file = pot_file; } #else - ESolver_DP(const std::string& pot_file) + ESolver_DP(const std::string &pot_file) { classname = "ESolver_DP"; dp_file = pot_file; @@ -36,7 +36,7 @@ class ESolver_DP : public ESolver * @param inp input parameters * @param cell unitcell information */ - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; /** * @brief Run the DP solver for a given ion/md step and unit cell @@ -44,7 +44,7 @@ class ESolver_DP : public ESolver * @param istep the current ion/md step * @param cell unitcell information */ - void runner(BaseCell& basecell, const int istep) override; + void runner(BaseCell &basecell, const int istep) override; /** * @brief get the total energy without ion kinetic energy @@ -59,21 +59,21 @@ class ESolver_DP : public ESolver * * @param force the computed atomic forces */ - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; /** * @brief get the computed lattice virials * * @param stress the computed lattice virials */ - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; /** * @brief Prints the final total energy of the DP model to the output file * * This function prints the final total energy of the DP model in eV to the output file along with some formatting. */ - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; //==================================================================== // Test seam. @@ -86,25 +86,13 @@ class ESolver_DP : public ESolver //==================================================================== /// @brief atom type index corresponding to the DP model - std::vector& get_atype() - { - return atype; - } + std::vector &get_atype() { return atype; } /// @brief computed potential energy - double& get_dp_potential() - { - return dp_potential; - } + double &get_dp_potential() { return dp_potential; } /// @brief computed atomic forces - ModuleBase::matrix& get_dp_force() - { - return dp_force; - } + ModuleBase::matrix &get_dp_force() { return dp_force; } /// @brief computed lattice virials - ModuleBase::matrix& get_dp_virial() - { - return dp_virial; - } + ModuleBase::matrix &get_dp_virial() { return dp_virial; } private: /** @@ -112,8 +100,8 @@ class ESolver_DP : public ESolver * * @param ucell unitcell information */ - void type_map(const UnitCell& ucell); - void initialize_type_map_(const std::vector& type_labels); + void type_map(const UnitCell &ucell); + void initialize_type_map_(const std::vector &type_labels); /** * @brief DeePMD related variables for ESolver_DP class @@ -139,8 +127,8 @@ class ESolver_DP : public ESolver * */ - std::string dp_file; ///< directory of DP model file - std::vector atype = {}; ///< atom type corresponding to DP model + std::string dp_file; ///< directory of DP model file + std::vector atype = {}; ///< atom type corresponding to DP model std::vector md_type_to_dp_type_; std::vector fparam = {}; ///< frame parameter for dp potential: dim_fparam std::vector aparam = {}; ///< atomic parameter for dp potential: natoms x dim_aparam diff --git a/source/source_esolver/esolver_factory.cpp b/source/source_esolver/esolver_factory.cpp index de52d69a84..d6f98205a2 100644 --- a/source/source_esolver/esolver_factory.cpp +++ b/source/source_esolver/esolver_factory.cpp @@ -1,10 +1,10 @@ #include "esolver_factory.h" #include "esolver.h" -#include "esolver_ks_pw.h" #include "esolver_dfpt_pw.h" -#include "esolver_sdft_pw.h" +#include "esolver_ks_pw.h" #include "esolver_ks_pw_tddft.h" +#include "esolver_sdft_pw.h" #include "source_base/module_device/device.h" #include "source_hamilt/module_xc/general_exx_info.h" #include "source_io/module_parameter/parameter.h" @@ -22,8 +22,8 @@ #include "source_base/module_external/blacs_connector.h" #endif #include "esolver_dp.h" -#include "esolver_nep.h" #include "esolver_lj.h" +#include "esolver_nep.h" #include "esolver_of.h" #include "esolver_of_tddft.h" @@ -32,7 +32,7 @@ namespace ModuleESolver { -std::string determine_type(const Input_para& inp) +std::string determine_type(const Input_para &inp) { std::string esolver_type = "none"; if (inp.basis_type == "pw") @@ -122,7 +122,7 @@ std::string determine_type(const Input_para& inp) auto device_info = inp.device; - for (char& c: device_info) + for (char &c : device_info) { if (std::islower(c)) { @@ -138,7 +138,7 @@ std::string determine_type(const Input_para& inp) } // Some API to operate E_Solver -ESolver* init_esolver(const Input_para& inp) +ESolver *init_esolver(const Input_para &inp) { // determine type of esolver based on INPUT information const std::string esolver_type = determine_type(inp); @@ -326,17 +326,25 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "lr_lcao") { - const std::string& in_dir = PARAM.globalv.global_readin_dir; - const std::string& out_dir = PARAM.globalv.global_out_dir; + const std::string &in_dir = PARAM.globalv.global_readin_dir; + const std::string &out_dir = PARAM.globalv.global_out_dir; if (inp.xc_kernel != "bse") { if (gamma_only) { - return new ModuleESolver::ESolver_LR(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_LR( + inp, + in_dir, + out_dir, + lr_runtime); } else { - return new ModuleESolver::ESolver_LR, double>(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_LR, double>( + inp, + in_dir, + out_dir, + lr_runtime); } } else @@ -344,11 +352,19 @@ ESolver* init_esolver(const Input_para& inp) #ifdef __EXX if (gamma_only) { - return new ModuleESolver::ESolver_BSE(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_BSE( + inp, + in_dir, + out_dir, + lr_runtime); } else { - return new ModuleESolver::ESolver_BSE, double>(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_BSE, double>( + inp, + in_dir, + out_dir, + lr_runtime); } #else ModuleBase::WARNING_QUIT("ESolver", "BSE requires ENABLE_LIBRI=ON"); @@ -358,15 +374,23 @@ ESolver* init_esolver(const Input_para& inp) } else if (esolver_type == "ksdft_lr_lcao") { - const std::string& in_dir = PARAM.globalv.global_readin_dir; - const std::string& out_dir = PARAM.globalv.global_out_dir; + const std::string &in_dir = PARAM.globalv.global_readin_dir; + const std::string &out_dir = PARAM.globalv.global_out_dir; if (gamma_only) { - return new ModuleESolver::ESolver_LR(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_LR( + inp, + in_dir, + out_dir, + lr_runtime); } else { - return new ModuleESolver::ESolver_LR, double>(inp, in_dir, out_dir, lr_runtime); + return new ModuleESolver::ESolver_LR, double>( + inp, + in_dir, + out_dir, + lr_runtime); } } #endif @@ -390,8 +414,9 @@ ESolver* init_esolver(const Input_para& inp) { return new ESolver_NEP(PARAM.mdp.pot_file); } - throw std::invalid_argument("esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) - + " line " + std::to_string(__LINE__)); + throw std::invalid_argument( + "esolver_type = " + std::string(esolver_type) + ". Wrong in " + std::string(__FILE__) + " line " + + std::to_string(__LINE__)); } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_factory.h b/source/source_esolver/esolver_factory.h index 381bbf5bb0..801fe94d9b 100644 --- a/source/source_esolver/esolver_factory.h +++ b/source/source_esolver/esolver_factory.h @@ -19,7 +19,7 @@ class ESolver; * @param [in] inp Input parameters used to determine the ESolver type. * @return [out] std::string The type label consumed by init_esolver(). */ -std::string determine_type(const Input_para& inp); +std::string determine_type(const Input_para &inp); /** * @brief Determine and initialize an ESolver based on input information. @@ -32,7 +32,7 @@ std::string determine_type(const Input_para& inp); * @param [in] inp Input parameters used to select and configure the ESolver. * @return [out] A pointer to the newly created ESolver object. */ -ESolver* init_esolver(const Input_para& inp); +ESolver *init_esolver(const Input_para &inp); } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_fp.cpp b/source/source_esolver/esolver_fp.cpp index 070e860f38..43bcf8ecd2 100644 --- a/source/source_esolver/esolver_fp.cpp +++ b/source/source_esolver/esolver_fp.cpp @@ -1,49 +1,50 @@ #include "esolver_fp.h" -#include "source_basis/module_pw/pw_basis_big.h" // use PW_Basis_Big +#include "source_base/module_parallel/para_bridge.h" +#include "source_base/module_parallel/para_tag.h" +#include "source_base/module_parallel/para_world.h" #include "source_base/tool_quit.h" +#include "source_basis/module_pw/pw_basis_big.h" // use PW_Basis_Big #include "source_cell/cal_ux.h" +#include "source_cell/read_pp_ucell.h" #include "source_estate/module_charge/chg_atomic.h" +#include "source_estate/module_charge/chg_rhog_io.h" #include "source_estate/module_charge/chg_symm.h" -#include "source_cell/read_pp_ucell.h" #include "source_estate/param_update.h" +#include "source_estate/write_init.h" // write_chg_init, write_pot_init #include "source_hamilt/module_ewald/h_ewald_pw.h" #include "source_hamilt/module_vdw/vdw.h" +#include "source_hamilt/module_xc/xc_functional.h" // mohan 20251005 +#include "source_io/module_ctrl/ctrl_output_fp.h" #include "source_io/module_output/output_log.h" #include "source_io/module_output/print_info.h" -#include "source_estate/module_charge/chg_rhog_io.h" #include "source_io/module_parameter/parameter.h" - #include "source_pw/module_pwdft/setup_pwrho.h" // mohan 20251005 #include "source_pw/module_pwdft/uspp_support.h" -#include "source_hamilt/module_xc/xc_functional.h" // mohan 20251005 -#include "source_io/module_ctrl/ctrl_output_fp.h" -#include "source_estate/write_init.h" // write_chg_init, write_pot_init -#include "source_base/module_parallel/para_world.h" -#include "source_base/module_parallel/para_tag.h" -#include "source_base/module_parallel/para_bridge.h" namespace ModuleESolver { -ESolver_FP::ESolver_FP() -{ -} +ESolver_FP::ESolver_FP() {} ESolver_FP::~ESolver_FP() { - //**************************************************** - // do not add any codes in this deconstructor funcion - //**************************************************** + //**************************************************** + // do not add any codes in this deconstructor funcion + //**************************************************** // mohan add 20251005 - pw::teardown_pwrho(this->pw_rho_flag, PARAM.globalv.double_grid, this->pw_rho, this->pw_rhod); + pw::teardown_pwrho( + this->pw_rho_flag, + PARAM.globalv.double_grid, + this->pw_rho, + this->pw_rhod); - delete this->pelec; + delete this->pelec; } -void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_FP::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); this->inp_ = &inp; @@ -68,60 +69,82 @@ void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) const std::string global_out_dir = PARAM.globalv.global_out_dir; const int npol = PARAM.globalv.npol; const bool two_fermi = PARAM.globalv.two_fermi; - auto atoms_info = unitcell::read_pseudo(GlobalV::ofs_running, - ucell, - this->inp_->pseudo_dir, - global_out_dir, - this->inp_->out_element_info, - this->inp_->dft_functional, - this->inp_->lspinorb, - this->inp_->pseudo_rcut, - this->inp_->soc_lambda, - this->inp_->nspin, - npol, - this->inp_->basis_type, - this->inp_->esolver_type, - this->inp_->init_wfc, - this->inp_->nbands, - two_fermi, - this->inp_->nelec_delta, - this->inp_->smearing_method, - this->inp_->ks_solver, - this->inp_->bndpar, - this->inp_->nelec, - this->inp_->nupdown); + auto atoms_info = unitcell::read_pseudo( + GlobalV::ofs_running, + ucell, + this->inp_->pseudo_dir, + global_out_dir, + this->inp_->out_element_info, + this->inp_->dft_functional, + this->inp_->lspinorb, + this->inp_->pseudo_rcut, + this->inp_->soc_lambda, + this->inp_->nspin, + npol, + this->inp_->basis_type, + this->inp_->esolver_type, + this->inp_->init_wfc, + this->inp_->nbands, + two_fermi, + this->inp_->nelec_delta, + this->inp_->smearing_method, + this->inp_->ks_solver, + this->inp_->bndpar, + this->inp_->nelec, + this->inp_->nupdown); elecstate::ParamUpdater::update_from_atoms_info(atoms_info); XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); - pw::validate_uspp_support(atoms_info.use_uspp, - inp.basis_type, - inp.esolver_type, - inp.nspin, - XC_Functional::get_func_type(), - inp.berry_phase, - inp.towannier90, - inp.cal_cond); + pw::validate_uspp_support( + atoms_info.use_uspp, + inp.basis_type, + inp.esolver_type, + inp.nspin, + XC_Functional::get_func_type(), + inp.berry_phase, + inp.towannier90, + inp.cal_cond); GlobalV::ofs_running << XC_Functional::output_info() << std::endl; //! 2) setup pw_rho, pw_rhod, pw_big, sf, and read_pseudopotentials - pw::setup_pwrho(ucell, PARAM.globalv.double_grid, this->pw_rho_flag, - this->pw_rho, this->pw_rhod, this->pw_big, this->classname, inp); + pw::setup_pwrho( + ucell, + PARAM.globalv.double_grid, + this->pw_rho_flag, + this->pw_rho, + this->pw_rhod, + this->pw_big, + this->classname, + inp); //! 3) setup structure factors this->sf.set(this->pw_rhod, inp.nbspline); //! 4) init charge extrapolation - this->CE.Init_CE(inp.nspin, ucell.nat, this->pw_rhod->nrxx, inp.chg_extrap); + this->CE.Init_CE( + inp.nspin, + ucell.nat, + this->pw_rhod->nrxx, + inp.chg_extrap); //! 5) symmetry analysis should be performed every time the cell is changed if (ModuleSymmetry::Symmetry::symm_flag == 1) { const int cal_symm_repr[2] = {this->inp_->cal_symm_repr[0], this->inp_->cal_symm_repr[1]}; - ucell.symm.analy_sys(ucell.lat, ucell.atoms, - ucell.nat, ucell.ntype, ucell.iat2it, ucell.iat2ia, ucell.itia2iat, - GlobalV::ofs_running, - this->inp_->symmetry_prec, inp.nspin, this->inp_->calculation, cal_symm_repr); + ucell.symm.analy_sys( + ucell.lat, + ucell.atoms, + ucell.nat, + ucell.ntype, + ucell.iat2it, + ucell.iat2ia, + ucell.itia2iat, + GlobalV::ofs_running, + this->inp_->symmetry_prec, + inp.nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SYMMETRY"); } @@ -132,7 +155,21 @@ void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) const bool gamma_only_local = PARAM.globalv.gamma_only_local; const double kspacing[3] = {this->inp_->kspacing[0], this->inp_->kspacing[1], this->inp_->kspacing[2]}; const double koffset[3] = {this->inp_->koffset[0], this->inp_->koffset[1], this->inp_->koffset[2]}; - this->kv.set(ucell, ucell.symm, inp.kpoint_file, inp.nspin, ucell.G, ucell.latvec, GlobalV::ofs_running, GlobalV::ofs_warning, use_ibz, global_out_dir, gamma_only_local, kspacing, this->inp_->kmesh_type, koffset); + this->kv.set( + ucell, + ucell.symm, + inp.kpoint_file, + inp.nspin, + ucell.G, + ucell.latvec, + GlobalV::ofs_running, + GlobalV::ofs_warning, + use_ibz, + global_out_dir, + gamma_only_local, + kspacing, + this->inp_->kmesh_type, + koffset); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); //! 8) print information @@ -140,24 +177,37 @@ void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) //! 9) parallel of FFT grid const int nprocgroup = (this->inp_->esolver_type == "sdft") ? GlobalV::NPROC_IN_BNDGROUP : GlobalV::NPROC; - this->Pgrid.init(this->pw_rhod->nx, this->pw_rhod->ny, this->pw_rhod->nz, - this->pw_rhod->nplane, this->pw_rhod->nrxx, pw_big->nbz, pw_big->bz, - nprocgroup); + this->Pgrid.init( + this->pw_rhod->nx, + this->pw_rhod->ny, + this->pw_rhod->nz, + this->pw_rhod->nplane, + this->pw_rhod->nrxx, + pw_big->nbz, + pw_big->bz, + nprocgroup); //! 10) calculate the structure factor - this->sf.setup(&ucell, Pgrid, this->pw_rhod, PARAM.globalv.has_float_data); + this->sf.setup( + &ucell, + Pgrid, + this->pw_rhod, + PARAM.globalv.has_float_data); //! 11) initialize the charge density, we need to first set xc_type, // then we can call chr.allocate() - this->chr.set_rhopw(this->pw_rhod); // mohan add 20251130 + this->chr.set_rhopw(this->pw_rhod); // mohan add 20251130 const bool kin_den = XC_Functional::get_ked_flag() || (inp.out_elf[0] > 0); // mohan add 20251202 - this->chr.allocate(inp.nspin, kin_den, XC_Functional::get_ked_flag(), inp.test_charge); // mohan move this from setup_estate_pw, 20251128 - + this->chr.allocate( + inp.nspin, + kin_den, + XC_Functional::get_ked_flag(), + inp.test_charge); // mohan move this from setup_estate_pw, 20251128 return; } -void ESolver_FP::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_FP::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_FP", "after_scf"); @@ -168,21 +218,33 @@ void ESolver_FP::after_scf(UnitCell& ucell, const int istep, const bool conv_eso ModuleIO::output_efermi(conv_esolver, this->pelec->eferm, GlobalV::ofs_running); //! Update delta_rho for charge extrapolation - const module_charge::AtomicRhoCfg atomic_rho_cfg_after{ - PARAM.inp.nelec, + const module_charge::AtomicRhoCfg atomic_rho_cfg_after{PARAM.inp.nelec, PARAM.inp.test_charge, PARAM.globalv.domag, PARAM.globalv.domag_z, GlobalV::ofs_warning}; - CE.update_delta_rho(ucell, &(this->chr), *this->pw_rhod, &(this->sf), atomic_rho_cfg_after); + CE.update_delta_rho( + ucell, + &(this->chr), + *this->pw_rhod, + &(this->sf), + atomic_rho_cfg_after); //! print out charge density, potential, elf, etc. - ModuleIO::ctrl_output_fp(ucell, *this->inp_, this->pelec, this->pw_big, this->pw_rhod, - this->chr, this->solvent, this->Pgrid, istep, GlobalV::ofs_running); - + ModuleIO::ctrl_output_fp( + ucell, + *this->inp_, + this->pelec, + this->pw_big, + this->pw_rhod, + this->chr, + this->solvent, + this->Pgrid, + istep, + GlobalV::ofs_running); } -void ESolver_FP::before_scf(UnitCell& ucell, const int istep) +void ESolver_FP::before_scf(UnitCell &ucell, const int istep) { ModuleBase::TITLE("ESolver_FP", "before_scf"); @@ -191,22 +253,35 @@ void ESolver_FP::before_scf(UnitCell& ucell, const int istep) { // only G-vector and K-vector are changed due to the change of lattice // vector FFT grids do not change!! - this->pw_rho->initgrids(ucell.lat0, ucell.latvec, pw_rho->nx, pw_rho->ny, pw_rho->nz); + this->pw_rho->initgrids( + ucell.lat0, + ucell.latvec, + pw_rho->nx, + pw_rho->ny, + pw_rho->nz); this->pw_rho->collect_local_pw(); this->pw_rho->collect_uniqgg(); // if double grid used in USPP, update related quantities in dense grid if (PARAM.globalv.double_grid) { - this->pw_rhod->initgrids(ucell.lat0, ucell.latvec, pw_rhod->nx, pw_rhod->ny, pw_rhod->nz); + this->pw_rhod->initgrids( + ucell.lat0, + ucell.latvec, + pw_rhod->nx, + pw_rhod->ny, + pw_rhod->nz); this->pw_rhod->collect_local_pw(); this->pw_rhod->collect_uniqgg(); } // reset local pseudopotentials this->locpp.init_vloc(ucell, this->pw_rhod); - this->locpp.print_vloc(ucell, this->pw_rhod, - this->inp_->out_element_info, PARAM.globalv.global_out_dir); + this->locpp.print_vloc( + ucell, + this->pw_rhod, + this->inp_->out_element_info, + PARAM.globalv.global_out_dir); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "LOCAL POTENTIAL"); // perform symmetry analysis @@ -214,15 +289,28 @@ void ESolver_FP::before_scf(UnitCell& ucell, const int istep) if (update_symmetry) { const int cal_symm_repr[2] = {this->inp_->cal_symm_repr[0], this->inp_->cal_symm_repr[1]}; - ucell.symm.analy_sys(ucell.lat, ucell.atoms, - ucell.nat, ucell.ntype, ucell.iat2it, ucell.iat2ia, ucell.itia2iat, - GlobalV::ofs_running, - this->inp_->symmetry_prec, this->inp_->nspin, this->inp_->calculation, cal_symm_repr); + ucell.symm.analy_sys( + ucell.lat, + ucell.atoms, + ucell.nat, + ucell.ntype, + ucell.iat2it, + ucell.iat2ia, + ucell.itia2iat, + GlobalV::ofs_running, + this->inp_->symmetry_prec, + this->inp_->nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SYMMETRY"); } // reset k-points - kv.set_after_vc(ucell.G, ucell.symm, update_symmetry, GlobalV::ofs_running); + kv.set_after_vc( + ucell.G, + ucell.symm, + update_symmetry, + GlobalV::ofs_running); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); } @@ -230,15 +318,21 @@ void ESolver_FP::before_scf(UnitCell& ucell, const int istep) if (ucell.ionic_position_updated) { this->CE.update_all_dis(ucell); - const module_charge::AtomicRhoCfg atomic_rho_cfg_before{ - PARAM.inp.nelec, + const module_charge::AtomicRhoCfg atomic_rho_cfg_before{PARAM.inp.nelec, PARAM.inp.test_charge, PARAM.globalv.domag, PARAM.globalv.domag_z, GlobalV::ofs_warning}; - this->CE.extrapolate_charge(&this->Pgrid, ucell, &this->chr, *this->pw_rhod, - &this->sf, GlobalV::ofs_running, GlobalV::ofs_warning, - atomic_rho_cfg_before, PARAM.globalv.has_float_data); + this->CE.extrapolate_charge( + &this->Pgrid, + ucell, + &this->chr, + *this->pw_rhod, + &this->sf, + GlobalV::ofs_running, + GlobalV::ofs_warning, + atomic_rho_cfg_before, + PARAM.globalv.has_float_data); } //! Evaluate the vdW correction once for this ionic configuration. @@ -258,58 +352,75 @@ void ESolver_FP::before_scf(UnitCell& ucell, const int istep) //! calculate ewald energy if (!this->inp_->test_skip_ewald) { - this->pelec->f_en.ewald_energy = H_Ewald_pw::compute_ewald(ucell, this->pw_rhod, this->sf.strucFac, this->inp_->test_energy, GlobalV::ofs_running); + this->pelec->f_en.ewald_energy = H_Ewald_pw::compute_ewald( + ucell, + this->pw_rhod, + this->sf.strucFac, + this->inp_->test_energy, + GlobalV::ofs_running); } - //! set direction of magnetism, used in non-collinear case + //! set direction of magnetism, used in non-collinear case unitcell::cal_ux(ucell, this->inp_->nspin); //! output the initial charge density - ModuleIO::write_chg_init(ucell, this->Pgrid, this->chr, this->pelec->eferm, istep, - PARAM.globalv.global_out_dir, *this->inp_, PARAM.globalv.two_fermi, GlobalV::ofs_running); + ModuleIO::write_chg_init( + ucell, + this->Pgrid, + this->chr, + this->pelec->eferm, + istep, + PARAM.globalv.global_out_dir, + *this->inp_, + PARAM.globalv.two_fermi, + GlobalV::ofs_running); return; } -void ESolver_FP::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) +void ESolver_FP::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { //! output charge density in G-space, or if available, kinetic energy density in G-space if (this->inp_->out_chg[0] != -1) { if (iter % this->inp_->out_freq_elec == 0 || iter == this->inp_->scf_nmax || conv_esolver) { - const System_para& system = PARAM.globalv; + const System_para &system = PARAM.globalv; const bool write_restart = this->inp_->out_chg[0] != -1; const std::string prefix = system.global_out_dir + this->inp_->suffix; const bool write_tau = XC_Functional::get_ked_flag(); const bool writer_pool = GlobalV::MY_POOL == 0; const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); - module_charge::write_density_restart(this->chr, - *this->pw_rhod, - ucell.GT, - prefix, - this->inp_->nspin, - write_restart, - system.gamma_only_pw, - write_tau, - writer_pool, - pw_world, - &GlobalV::ofs_warning); + module_charge::write_density_restart( + this->chr, + *this->pw_rhod, + ucell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); } } } -void ESolver_FP::after_all_runners(BaseCell& basecell) +void ESolver_FP::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); // print out the final total energy GlobalV::ofs_running << "\n --------------------------------------------" << std::endl; GlobalV::ofs_running << std::setprecision(16); GlobalV::ofs_running << " !FINAL_ETOT_IS " << this->pelec->f_en.etot * ModuleBase::Ry_to_eV << " eV" << std::endl; GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; - } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_fp.h b/source/source_esolver/esolver_fp.h index 39612979a9..944cebf5da 100644 --- a/source/source_esolver/esolver_fp.h +++ b/source/source_esolver/esolver_fp.h @@ -2,14 +2,14 @@ #define ESOLVER_FP_H #include "esolver.h" +#include "source_base/parallel_grid.h" // Parallel_Grid (value member below) #include "source_base/timer_wrapper.h" -#include "source_basis/module_pw/pw_basis_sup.h" // plane wave basis -#include "source_estate/elecstate.h" // electronic states +#include "source_basis/module_pw/pw_basis_sup.h" // plane wave basis +#include "source_cell/stru_fac.h" // structure factor +#include "source_estate/elecstate.h" // electronic states #include "source_estate/module_charge/chg_extra.h" // charge extrapolation -#include "source_hamilt/module_surchem/surchem.h" // solvation model -#include "source_base/parallel_grid.h" // Parallel_Grid (value member below) -#include "source_cell/stru_fac.h" // structure factor -#include "source_pw/module_pwdft/vl_pw.h" // local pseudopotential +#include "source_hamilt/module_surchem/surchem.h" // solvation model +#include "source_pw/module_pwdft/vl_pw.h" // local pseudopotential #include #include @@ -37,24 +37,28 @@ class ESolver_FP : public ESolver virtual ~ESolver_FP(); //! Initialize of the first-principels energy solver - virtual void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + virtual void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - virtual void after_all_runners(BaseCell& basecell) override; + virtual void after_all_runners(BaseCell &basecell) override; protected: - virtual void before_scf(UnitCell& ucell, const int istep); + virtual void before_scf(UnitCell &ucell, const int istep); - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver); + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver); - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver); + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver); - const vdw::VdwResult* get_vdw_result() const { return this->vdw_result_.get(); } + const vdw::VdwResult *get_vdw_result() const { return this->vdw_result_.get(); } //! vdW correction evaluated once for the current ionic configuration. std::unique_ptr vdw_result_; //! These pointers will be deleted in the free_pointers() function every ion step. - elecstate::ElecState* pelec = nullptr; ///< Electronic states + elecstate::ElecState *pelec = nullptr; ///< Electronic states //! K points in Brillouin zone K_Vectors kv; @@ -67,9 +71,9 @@ class ESolver_FP : public ESolver //! dense grid for for uspp, used for ultrasoft augmented charge density. //! charge density and potential are defined on dense grids, //! but effective potential needs to be interpolated on smooth grids in order to compute Veff|psi> - ModulePW::PW_Basis* pw_rho = nullptr; - ModulePW::PW_Basis* pw_rhod = nullptr; //! dense grid for USPP - ModulePW::PW_Basis_Big* pw_big = nullptr; ///< [temp] pw_basis_big class + ModulePW::PW_Basis *pw_rho = nullptr; + ModulePW::PW_Basis *pw_rhod = nullptr; //! dense grid for USPP + ModulePW::PW_Basis_Big *pw_big = nullptr; ///< [temp] pw_basis_big class //! parallel for rho grid Parallel_Grid Pgrid; diff --git a/source/source_esolver/esolver_gets.cpp b/source/source_esolver/esolver_gets.cpp index d0a2d72758..a4c0e28396 100644 --- a/source/source_esolver/esolver_gets.cpp +++ b/source/source_esolver/esolver_gets.cpp @@ -5,11 +5,11 @@ #include "source_cell/read_pp_ucell.h" #include "source_estate/elecstate_lcao.h" #include "source_estate/param_update.h" -#include "source_io/module_hs/pos_op_mat.h" #include "source_io/module_hs/hsr_legacy.h" +#include "source_io/module_hs/pos_op_mat.h" #include "source_io/module_output/print_info.h" -#include "source_lcao/lcao_domain.h" #include "source_lcao/hamilt_lcao.h" +#include "source_lcao/lcao_domain.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" namespace ModuleESolver @@ -21,14 +21,12 @@ ESolver_GetS::ESolver_GetS() this->basisname = "LCAO"; } -ESolver_GetS::~ESolver_GetS() -{ -} +ESolver_GetS::~ESolver_GetS() {} -void ESolver_GetS::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_GetS::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); this->inp_ = &inp; @@ -40,46 +38,48 @@ void ESolver_GetS::before_all_runners(BaseCell& basecell, const Input_para& inp) const int npol = PARAM.globalv.npol; const bool two_fermi = PARAM.globalv.two_fermi; // nlocal is calculated inside read_pseudo() via CalAtomsInfo::cal_atoms_info() - auto atoms_info = unitcell::read_pseudo(GlobalV::ofs_running, - ucell, - this->inp_->pseudo_dir, - global_out_dir, - this->inp_->out_element_info, - this->inp_->dft_functional, - this->inp_->lspinorb, - this->inp_->pseudo_rcut, - this->inp_->soc_lambda, - this->inp_->nspin, - npol, - this->inp_->basis_type, - this->inp_->esolver_type, - this->inp_->init_wfc, - this->inp_->nbands, - two_fermi, - this->inp_->nelec_delta, - this->inp_->smearing_method, - this->inp_->ks_solver, - this->inp_->bndpar, - this->inp_->nelec, - this->inp_->nupdown); + auto atoms_info = unitcell::read_pseudo( + GlobalV::ofs_running, + ucell, + this->inp_->pseudo_dir, + global_out_dir, + this->inp_->out_element_info, + this->inp_->dft_functional, + this->inp_->lspinorb, + this->inp_->pseudo_rcut, + this->inp_->soc_lambda, + this->inp_->nspin, + npol, + this->inp_->basis_type, + this->inp_->esolver_type, + this->inp_->init_wfc, + this->inp_->nbands, + two_fermi, + this->inp_->nelec_delta, + this->inp_->smearing_method, + this->inp_->ks_solver, + this->inp_->bndpar, + this->inp_->nelec, + this->inp_->nupdown); elecstate::ParamUpdater::update_from_atoms_info(atoms_info); // 1.2) symmetrize things if (ModuleSymmetry::Symmetry::symm_flag == 1) { const int cal_symm_repr[2] = {this->inp_->cal_symm_repr[0], this->inp_->cal_symm_repr[1]}; - ucell.symm.analy_sys(ucell.lat, - ucell.atoms, - ucell.nat, - ucell.ntype, - ucell.iat2it, - ucell.iat2ia, - ucell.itia2iat, - GlobalV::ofs_running, - this->inp_->symmetry_prec, - inp.nspin, - this->inp_->calculation, - cal_symm_repr); + ucell.symm.analy_sys( + ucell.lat, + ucell.atoms, + ucell.nat, + ucell.ntype, + ucell.iat2it, + ucell.iat2ia, + ucell.itia2iat, + GlobalV::ofs_running, + this->inp_->symmetry_prec, + inp.nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SYMMETRY"); } @@ -88,20 +88,21 @@ void ESolver_GetS::before_all_runners(BaseCell& basecell, const Input_para& inp) const bool gamma_only_local = PARAM.globalv.gamma_only_local; const double kspacing[3] = {this->inp_->kspacing[0], this->inp_->kspacing[1], this->inp_->kspacing[2]}; const double koffset[3] = {this->inp_->koffset[0], this->inp_->koffset[1], this->inp_->koffset[2]}; - this->kv.set(ucell, - ucell.symm, - inp.kpoint_file, - inp.nspin, - ucell.G, - ucell.latvec, - GlobalV::ofs_running, - GlobalV::ofs_warning, - use_ibz, - global_out_dir, - gamma_only_local, - kspacing, - this->inp_->kmesh_type, - koffset); + this->kv.set( + ucell, + ucell.symm, + inp.kpoint_file, + inp.nspin, + ucell.G, + ucell.latvec, + GlobalV::ofs_running, + GlobalV::ofs_warning, + use_ibz, + global_out_dir, + gamma_only_local, + kspacing, + this->inp_->kmesh_type, + koffset); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT K-POINTS"); ModuleIO::print_parameters(ucell, this->kv, inp); @@ -111,55 +112,65 @@ void ESolver_GetS::before_all_runners(BaseCell& basecell, const Input_para& inp) if (this->pelec == nullptr) { // TK stands for double and std::complex? - this->pelec = new elecstate::ElecStateLCAO>(&(this->chr), // use which parameter? - &(this->kv), - this->kv.get_nks(), - this->pw_big); + this->pelec = new elecstate::ElecStateLCAO>( + &(this->chr), // use which parameter? + &(this->kv), + this->kv.get_nks(), + this->pw_big); } // 3) init LCAO basis // reading the localized orbitals/projectors // construct the interpolation tables. - LCAO_domain::init_basis_lcao(this->pv, - inp.onsite_radius, - inp.lcao_ecut, - inp.lcao_dk, - inp.lcao_dr, - inp.lcao_rmax, - ucell, - two_center_bundle_, - orb_); + LCAO_domain::init_basis_lcao( + this->pv, + inp.onsite_radius, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + ucell, + two_center_bundle_, + orb_); ModuleBase::timer::end("ESolver_GetS", "before_all_runners"); } -void ESolver_GetS::runner(BaseCell& basecell, const int istep) +void ESolver_GetS::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_GetS", "runner"); ModuleBase::timer::start("ESolver_GetS", "runner"); // (1) Find adjacent atoms for each atom. double search_radius = -1.0; - search_radius = atom_arrange::set_sr_NL(GlobalV::ofs_running, - this->inp_->out_level, - orb_.get_rcutmax_Phi(), - ucell.infoNL->get_rcutmax_Beta(), - PARAM.globalv.gamma_only_local); + search_radius = atom_arrange::set_sr_NL( + GlobalV::ofs_running, + this->inp_->out_level, + orb_.get_rcutmax_Phi(), + ucell.infoNL->get_rcutmax_Beta(), + PARAM.globalv.gamma_only_local); Grid_Driver gd; - atom_arrange::search(PARAM.globalv.search_pbc, - GlobalV::ofs_running, - gd, - ucell, - search_radius, - this->inp_->test_atom_input); + atom_arrange::search( + PARAM.globalv.search_pbc, + GlobalV::ofs_running, + gd, + ucell, + search_radius, + this->inp_->test_atom_input); Record_adj RA; - RA.for_2d(ucell, gd, this->pv, PARAM.globalv.gamma_only_local, PARAM.globalv.npol, orb_.cutoffs()); + RA.for_2d( + ucell, + gd, + this->pv, + PARAM.globalv.gamma_only_local, + PARAM.globalv.npol, + orb_.cutoffs()); if (this->inp_->out_level != "m" && !PARAM.globalv.gamma_only_local) { ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "ParaV.nnr", this->pv.nnr); @@ -169,69 +180,77 @@ void ESolver_GetS::runner(BaseCell& basecell, const int istep) { if (this->inp_->nspin == 4) { - this->p_hamilt - = new hamilt::HamiltLCAO, std::complex>(ucell, - gd, - &this->pv, - this->kv, - *(two_center_bundle_.overlap_orb), - orb_.cutoffs()); - auto* hamilt_ptr = static_cast>*>(this->p_hamilt); - auto* ops_ptr - = dynamic_cast, std::complex>*>(hamilt_ptr->ops); + this->p_hamilt = new hamilt::HamiltLCAO, std::complex>( + ucell, + gd, + &this->pv, + this->kv, + *(two_center_bundle_.overlap_orb), + orb_.cutoffs()); + auto *hamilt_ptr = static_cast> *>(this->p_hamilt); + auto *ops_ptr = + dynamic_cast, std::complex> *>(hamilt_ptr->ops); ops_ptr->contributeHR(); } else { - this->p_hamilt = new hamilt::HamiltLCAO, double>(ucell, - gd, - &this->pv, - this->kv, - *(two_center_bundle_.overlap_orb), - orb_.cutoffs()); - auto* hamilt_ptr = static_cast>*>(this->p_hamilt); - auto* ops_ptr = dynamic_cast, double>*>(hamilt_ptr->ops); + this->p_hamilt = new hamilt::HamiltLCAO, double>( + ucell, + gd, + &this->pv, + this->kv, + *(two_center_bundle_.overlap_orb), + orb_.cutoffs()); + auto *hamilt_ptr = static_cast> *>(this->p_hamilt); + auto *ops_ptr = dynamic_cast, double> *>(hamilt_ptr->ops); ops_ptr->contributeHR(); } } const std::string fn = PARAM.globalv.global_out_dir + "sr_nao.csr"; - auto* hamilt_ptr = static_cast>*>(this->p_hamilt); + auto *hamilt_ptr = static_cast> *>(this->p_hamilt); const bool binary = false; const double sparse_threshold = 1e-10; const int precision = 16; - ModuleIO::output_SR(pv, - gd, - hamilt_ptr, - fn, - binary, - sparse_threshold, - precision, - PARAM.globalv.global_out_dir, - PARAM.globalv.global_matrix_dir, - PARAM.inp.calculation, - PARAM.inp.out_app_flag, - PARAM.inp.nspin, - GlobalV::ofs_running); + ModuleIO::output_SR( + pv, + gd, + hamilt_ptr, + fn, + binary, + sparse_threshold, + precision, + PARAM.globalv.global_out_dir, + PARAM.globalv.global_matrix_dir, + PARAM.inp.calculation, + PARAM.inp.out_app_flag, + PARAM.inp.nspin, + GlobalV::ofs_running); if (this->inp_->out_mat_r[0]) { Position_op r_matrix; const bool cal_force = PARAM.inp.cal_force; const int nlocal = PARAM.globalv.nlocal; - r_matrix.init(ucell, pv, orb_, cal_force, nlocal); - r_matrix.out_rR(ucell, - gd, - -1, // get_s has no ionic step; use -1 for no step suffix - this->inp_->out_mat_r[1], - PARAM.globalv.global_out_dir, - PARAM.globalv.global_matrix_dir, - PARAM.inp.calculation, - PARAM.inp.out_app_flag, - nlocal, - PARAM.globalv.npol, - GlobalV::ofs_running); + r_matrix.init( + ucell, + pv, + orb_, + cal_force, + nlocal); + r_matrix.out_rR( + ucell, + gd, + -1, // get_s has no ionic step; use -1 for no step suffix + this->inp_->out_mat_r[1], + PARAM.globalv.global_out_dir, + PARAM.globalv.global_matrix_dir, + PARAM.inp.calculation, + PARAM.inp.out_app_flag, + nlocal, + PARAM.globalv.npol, + GlobalV::ofs_running); } if (this->inp_->out_mat_ds[0]) @@ -247,41 +266,39 @@ void ESolver_GetS::runner(BaseCell& basecell, const int istep) mat_R_options.out_app_flag = PARAM.inp.out_app_flag; mat_R_options.nspin = PARAM.inp.nspin; //! Print out sparse matrix - ModuleIO::output_dSR(istep, - ucell, - this->pv, - HS_Arrays, - gd, // mohan add 2024-04-06 - two_center_bundle_, - orb_, - mat_R_options, - PARAM.globalv.gamma_only_local, - PARAM.globalv.npol, - PARAM.globalv.nlocal, - GlobalV::ofs_running); + ModuleIO::output_dSR( + istep, + ucell, + this->pv, + HS_Arrays, + gd, // mohan add 2024-04-06 + two_center_bundle_, + orb_, + mat_R_options, + PARAM.globalv.gamma_only_local, + PARAM.globalv.npol, + PARAM.globalv.nlocal, + GlobalV::ofs_running); } ModuleBase::timer::end("ESolver_GetS", "runner"); } -void ESolver_GetS::after_all_runners(BaseCell& basecell) +void ESolver_GetS::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); -}; -double ESolver_GetS::cal_energy() -{ - return 0.0; + UnitCell &ucell = static_cast(basecell); }; -void ESolver_GetS::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +double ESolver_GetS::cal_energy() { return 0.0; }; +void ESolver_GetS::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); }; -void ESolver_GetS::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_GetS::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_gets.h b/source/source_esolver/esolver_gets.h index 81282b7ef1..269745d276 100644 --- a/source/source_esolver/esolver_gets.h +++ b/source/source_esolver/esolver_gets.h @@ -17,20 +17,20 @@ class ESolver_GetS : public ESolver_KS ESolver_GetS(); ~ESolver_GetS(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; - void runner(BaseCell& basecell, const int istep) override; + void runner(BaseCell &basecell, const int istep) override; //! calculate total energy of a given system double cal_energy() override; //! calcualte forces for the atoms in the given cell - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; //! calcualte stress of given cell - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; protected: // 2d block - cyclic distribution info diff --git a/source/source_esolver/esolver_ks.cpp b/source/source_esolver/esolver_ks.cpp index d81f3bf435..80d5a94751 100644 --- a/source/source_esolver/esolver_ks.cpp +++ b/source/source_esolver/esolver_ks.cpp @@ -1,32 +1,31 @@ #include "esolver_ks.h" -#include "source_base/timer_wrapper.h" + #include "source_base/module_parallel/para_bridge.h" +#include "source_base/timer_wrapper.h" // for jason output information -#include "source_io/module_json/output_info.h" - -#include "source_estate/update_pot.h" // mohan add 20251016 -#include "source_estate/module_charge/chg_routine.h" // mohan add 20251018 +#include "source_estate/elecstate_print.h" // print_etot #include "source_estate/module_charge/chg_drho.h" // module_charge::cal_drho/cal_dkin #include "source_estate/module_charge/chg_init.h" // module_charge::InitRhoCfg -#include "source_estate/module_charge/chg_tools.h" // module_charge::check_rho #include "source_estate/module_charge/chg_rhog_io.h" -#include "source_pw/module_pwdft/setup_pwwfc.h" // mohan add 20251018 +#include "source_estate/module_charge/chg_routine.h" // mohan add 20251018 +#include "source_estate/module_charge/chg_tools.h" // module_charge::check_rho +#include "source_estate/update_pot.h" // mohan add 20251016 +#include "source_hamilt/module_xc/general_exx_info.h" // for init_general_exx_info +#include "source_hamilt/module_xc/xc_functional.h" #include "source_hsolver/hsolver.h" -#include "source_io/module_energy/write_eig_occ.h" #include "source_io/module_energy/write_bands.h" -#include "source_hamilt/module_xc/xc_functional.h" +#include "source_io/module_energy/write_eig_occ.h" +#include "source_io/module_json/output_info.h" #include "source_io/module_output/output_log.h" // use write_head -#include "source_estate/elecstate_print.h" // print_etot -#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base::u_converged in iter_finish -#include "source_hamilt/module_xc/general_exx_info.h" // for init_general_exx_info +#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base::u_converged in iter_finish +#include "source_pw/module_pwdft/setup_pwwfc.h" // mohan add 20251018 namespace ModuleESolver { ESolver_KS::ESolver_KS() {} - ESolver_KS::~ESolver_KS() { //**************************************************** @@ -40,11 +39,10 @@ ESolver_KS::~ESolver_KS() pw::teardown_pwwfc(this->pw_wfc); } - -void ESolver_KS::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_KS::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS", "before_all_runners"); @@ -75,30 +73,40 @@ void ESolver_KS::before_all_runners(BaseCell& basecell, const Input_para& inp) #pragma GCC diagnostic push #pragma GCC diagnostic error "-Wmissing-field-initializers" MixingConfig mix_cfg{ - inp.mixing_mode, // mixing_mode - inp.mixing_beta, // mixing_beta - inp.mixing_ndim, // mixing_ndim - inp.mixing_gg0, // mixing_gg0 - inp.mixing_tau && XC_Functional::get_ked_flag(), // mixing_tau - inp.mixing_beta_mag, // mixing_beta_mag - inp.mixing_gg0_mag, // mixing_gg0_mag - inp.mixing_gg0_min, // mixing_gg0_min - inp.mixing_angle, // mixing_angle - inp.mixing_dmr, // mixing_dmr - inp.nspin, // nspin - inp.scf_thr_type, // scf_thr_type - PARAM.globalv.double_grid, // double_grid - PARAM.globalv.gamma_only_pw, // gamma_only_pw - PARAM.globalv.domag, // domag - PARAM.globalv.domag_z, // domag_z - inp.scf_nmax // scf_nmax + inp.mixing_mode, // mixing_mode + inp.mixing_beta, // mixing_beta + inp.mixing_ndim, // mixing_ndim + inp.mixing_gg0, // mixing_gg0 + inp.mixing_tau && XC_Functional::get_ked_flag(), // mixing_tau + inp.mixing_beta_mag, // mixing_beta_mag + inp.mixing_gg0_mag, // mixing_gg0_mag + inp.mixing_gg0_min, // mixing_gg0_min + inp.mixing_angle, // mixing_angle + inp.mixing_dmr, // mixing_dmr + inp.nspin, // nspin + inp.scf_thr_type, // scf_thr_type + PARAM.globalv.double_grid, // double_grid + PARAM.globalv.gamma_only_pw, // gamma_only_pw + PARAM.globalv.domag, // domag + PARAM.globalv.domag_z, // domag_z + inp.scf_nmax // scf_nmax }; #pragma GCC diagnostic pop - p_chgmix->set_mixing(mix_cfg, this->pw_rho, this->pw_rhod, ucell.omega, ucell.tpiba); + p_chgmix->set_mixing( + mix_cfg, + this->pw_rho, + this->pw_rhod, + ucell.omega, + ucell.tpiba); p_chgmix->init_mixing(); //! 4) setup plane wave for electronic wave functions - pw::setup_pwwfc(inp, ucell, *this->pw_rho, this->kv, this->pw_wfc); + pw::setup_pwwfc( + inp, + ucell, + *this->pw_rho, + this->kv, + this->pw_wfc); //! 5) read in charge density, mohan add 2025-11-28 //! Inititlize the charge density. @@ -114,25 +122,46 @@ void ESolver_KS::before_all_runners(BaseCell& basecell, const Input_para& inp) init_rho_cfg.domag_z = PARAM.globalv.domag_z; init_rho_cfg.npol = PARAM.globalv.npol; init_rho_cfg.meta_gga = XC_Functional::get_ked_flag(); - this->chr.init_rho(ucell, this->Pgrid, this->sf.strucFac, ucell.symm, &this->kv, this->pw_wfc, init_rho_cfg); - module_charge::check_rho(this->chr.rho, this->chr.nspin, this->chr.rhopw->nrxx, ucell.omega, - this->chr.rhopw->nxyz, inp.nelec); // check the rho - + this->chr.init_rho( + ucell, + this->Pgrid, + this->sf.strucFac, + ucell.symm, + &this->kv, + this->pw_wfc, + init_rho_cfg); + module_charge::check_rho( + this->chr.rho, + this->chr.nspin, + this->chr.rhopw->nrxx, + ucell.omega, + this->chr.rhopw->nxyz, + inp.nelec); // check the rho } -void ESolver_KS::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) -{} - -std::string ESolver_KS::diag_policy(const int istep) const +void ESolver_KS::hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) { - return this->inp_->esolver_type; } -void ESolver_KS::hamilt2rho(UnitCell& ucell, const int istep, const int iter, const double ethr) +std::string ESolver_KS::diag_policy(const int istep) const { return this->inp_->esolver_type; } + +void ESolver_KS::hamilt2rho( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) { const std::string policy = this->diag_policy(istep); // 1) use Hamiltonian to obtain charge density - this->hamilt2rho_single(ucell, istep, iter, diag_ethr); + this->hamilt2rho_single( + ucell, + istep, + iter, + diag_ethr); // 2) for MPI: STOGROUP? need to rewrite // It may be changed when more clever parallel algorithm is put forward. @@ -143,38 +172,64 @@ void ESolver_KS::hamilt2rho(UnitCell& ucell, const int istep, const int iter, co // example wavefunctions uses 20 processors while density uses 10. if (PARAM.globalv.ks_run) { - drho = module_charge::cal_drho(&this->chr, this->inp_->nelec, *this->pw_rho, - p_chgmix->get_mixing_config(), ucell.omega, ucell.tpiba); + drho = module_charge::cal_drho( + &this->chr, + this->inp_->nelec, + *this->pw_rho, + p_chgmix->get_mixing_config(), + ucell.omega, + ucell.tpiba); hsolver_error = 0.0; if (iter == 1 && this->inp_->calculation != "nscf") { - hsolver_error - = hsolver::cal_hsolve_error(this->inp_->basis_type, policy, diag_ethr, this->inp_->nelec); + hsolver_error = hsolver::cal_hsolve_error( + this->inp_->basis_type, + policy, + diag_ethr, + this->inp_->nelec); // The error of HSolver is larger than drho, // so a more precise HSolver should be executed. if (hsolver_error > drho) { - diag_ethr = hsolver::reset_diag_ethr(GlobalV::ofs_running, this->inp_->basis_type, - policy, this->inp_->precision, hsolver_error, - drho, diag_ethr, this->inp_->nelec); - - this->hamilt2rho_single(ucell, istep, iter, diag_ethr); - - drho = module_charge::cal_drho(&this->chr, this->inp_->nelec, *this->pw_rho, - p_chgmix->get_mixing_config(), ucell.omega, ucell.tpiba); - - hsolver_error = hsolver::cal_hsolve_error(this->inp_->basis_type, - policy, diag_ethr, this->inp_->nelec); + diag_ethr = hsolver::reset_diag_ethr( + GlobalV::ofs_running, + this->inp_->basis_type, + policy, + this->inp_->precision, + hsolver_error, + drho, + diag_ethr, + this->inp_->nelec); + + this->hamilt2rho_single( + ucell, + istep, + iter, + diag_ethr); + + drho = module_charge::cal_drho( + &this->chr, + this->inp_->nelec, + *this->pw_rho, + p_chgmix->get_mixing_config(), + ucell.omega, + ucell.tpiba); + + hsolver_error = hsolver::cal_hsolve_error( + this->inp_->basis_type, + policy, + diag_ethr, + this->inp_->nelec); } } } } -void ESolver_KS::runner(BaseCell& basecell, const int istep) +void ESolver_KS::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS", "runner"); ModuleBase::timer::start(this->classname, "runner"); @@ -190,39 +245,44 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) ModuleBase::timer::end(this->classname, "runner"); } -int ESolver_KS::scf_iter_limit(const int istep) const -{ - return this->maxniter; -} +int ESolver_KS::scf_iter_limit(const int istep) const { return this->maxniter; } -bool ESolver_KS::scf_loop(UnitCell& ucell, int istep, int iter_limit) +bool ESolver_KS::scf_loop(UnitCell &ucell, int istep, int iter_limit) { ModuleBase::timer::start("ESolver_KS", "scf_loop"); // 2) SCF iterations bool conv_esolver = false; this->niter = iter_limit; this->diag_ethr = this->inp_->pw_diag_thr; - this->scf_nmax_flag = false; // mohan add 2025-09-21 - this->scf_rerun_ = false; // clear any stale rerun request before the loop - this->oscillate_esolver = false; // clear any stale oscillation flag before the loop + this->scf_nmax_flag = false; // mohan add 2025-09-21 + this->scf_rerun_ = false; // clear any stale rerun request before the loop + this->oscillate_esolver = false; // clear any stale oscillation flag before the loop int iter = 1; int rerun_count = 0; - const int max_rerun = 100; // safety net: EXX rerun should never exceed this + const int max_rerun = 100; // safety net: EXX rerun should never exceed this while (iter <= iter_limit) { - if(iter == iter_limit) + if (iter == iter_limit) { - this->scf_nmax_flag=true; + this->scf_nmax_flag = true; } // 3) initialization of SCF iterations this->iter_init(ucell, istep, iter); // 4) use Hamiltonian to obtain charge density - this->hamilt2rho(ucell, istep, iter, diag_ethr); + this->hamilt2rho( + ucell, + istep, + iter, + diag_ethr); // 5) finish scf iterations - this->iter_finish(ucell, istep, iter, conv_esolver); + this->iter_finish( + ucell, + istep, + iter, + conv_esolver); // 6) check convergence if (conv_esolver || this->oscillate_esolver) @@ -247,8 +307,7 @@ bool ESolver_KS::scf_loop(UnitCell& ucell, int istep, int iter_limit) { if (++rerun_count > max_rerun) { - std::cout << " WARNING: SCF rerun limit (" << max_rerun - << ") reached, stopping." << std::endl; + std::cout << " WARNING: SCF rerun limit (" << max_rerun << ") reached, stopping." << std::endl; break; } this->scf_rerun_ = false; @@ -263,17 +322,21 @@ bool ESolver_KS::scf_loop(UnitCell& ucell, int istep, int iter_limit) return conv_esolver; } -void ESolver_KS::before_scf(UnitCell& ucell, const int istep) +void ESolver_KS::before_scf(UnitCell &ucell, const int istep) { ModuleBase::TITLE("ESolver_KS", "before_scf"); ESolver_FP::before_scf(ucell, istep); } -void ESolver_KS::iter_init(UnitCell& ucell, const int istep, const int iter) +void ESolver_KS::iter_init(UnitCell &ucell, const int istep, const int iter) { - if(this->inp_->esolver_type != "tddft") + if (this->inp_->esolver_type != "tddft") { - ModuleIO::write_head(GlobalV::ofs_running, istep, iter, this->basisname); + ModuleIO::write_head( + GlobalV::ofs_running, + istep, + iter, + this->basisname); } iter_time = ModuleBase::get_time(); @@ -285,16 +348,36 @@ void ESolver_KS::iter_init(UnitCell& ucell, const int istep, const int iter) const std::string policy = this->diag_policy(istep); if (policy == "ksdft") { - diag_ethr = hsolver::set_diagethr_ks(this->inp_->basis_type, policy, - this->inp_->calculation, this->inp_->init_chg, this->inp_->precision, istep, iter, - drho, this->inp_->pw_diag_thr, diag_ethr, this->inp_->nelec, this->inp_->scf_thr); + diag_ethr = hsolver::set_diagethr_ks( + this->inp_->basis_type, + policy, + this->inp_->calculation, + this->inp_->init_chg, + this->inp_->precision, + istep, + iter, + drho, + this->inp_->pw_diag_thr, + diag_ethr, + this->inp_->nelec, + this->inp_->scf_thr); } else if (policy == "sdft") { - diag_ethr = hsolver::set_diagethr_sdft(this->inp_->basis_type, policy, - this->inp_->calculation, this->inp_->init_chg, istep, iter, drho, - this->inp_->pw_diag_thr, diag_ethr, this->inp_->nbands, esolver_KS_ne, - this->inp_->nelec, this->inp_->scf_thr); + diag_ethr = hsolver::set_diagethr_sdft( + this->inp_->basis_type, + policy, + this->inp_->calculation, + this->inp_->init_chg, + istep, + iter, + drho, + this->inp_->pw_diag_thr, + diag_ethr, + this->inp_->nbands, + esolver_KS_ne, + this->inp_->nelec, + this->inp_->scf_thr); } // save input charge density (rho) @@ -306,16 +389,17 @@ ESolver_KS::DensityStage ESolver_KS::density_stage(const int istep, const int it return DensityStage::standard; } -bool ESolver_KS::defer_iter_output(const int istep) const -{ - return false; -} +bool ESolver_KS::defer_iter_output(const int istep) const { return false; } -void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool &conv_esolver) +void ESolver_KS::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { const int iter_limit = this->scf_iter_limit(istep); - // 1.1) print out band gap + // 1.1) print out band gap if (!PARAM.globalv.two_fermi) { this->pelec->cal_bandgap(); @@ -335,9 +419,15 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & } // 2.1) compute magnetization, only for spin==2 - ucell.magnet.compute_mag(ucell.omega, this->chr.nrxx, this->chr.nxyz, this->chr.rho, - this->inp_->nspin, PARAM.globalv.two_fermi, this->inp_->nelec, - this->pelec->nelec_spin.data()); + ucell.magnet.compute_mag( + ucell.omega, + this->chr.nrxx, + this->chr.nxyz, + this->chr.rho, + this->inp_->nspin, + PARAM.globalv.two_fermi, + this->inp_->nelec, + this->pelec->nelec_spin.data()); // 2.2) charge mixing // SCF will continue if U is not converged for uramping calculation @@ -370,27 +460,40 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & } else { - module_charge::chgmixing_ks(iter, ucell, this->pelec, this->chr, - *this->chr.rhopw, this->p_chgmix, ctx, *this->inp_); + module_charge::chgmixing_ks( + iter, + ucell, + this->pelec, + this->chr, + *this->chr.rhopw, + this->p_chgmix, + ctx, + *this->inp_); } this->drho = ctx.drho; this->oscillate_esolver = ctx.oscillate_esolver; conv_esolver = ctx.conv_esolver; // 2.3) Update potentials (should be done every SF iter) - elecstate::update_pot(ucell, this->pelec, this->chr, conv_esolver); + elecstate::update_pot( + ucell, + this->pelec, + this->chr, + conv_esolver); // 3.1) calculate energies - this->pelec->cal_energies(1, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); // Harris-Foulkes functional - this->pelec->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); // Kohn-Sham functional + this->pelec->cal_energies( + 1, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); // Harris-Foulkes functional + this->pelec->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); // Kohn-Sham functional if (iter == 1) { @@ -403,40 +506,57 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool & double dkin = 0.0; // for meta-GGA if (XC_Functional::get_ked_flag()) { - dkin = module_charge::cal_dkin(&this->chr, this->inp_->nelec, *this->pw_rho, - p_chgmix->get_mixing_config(), ucell.omega); + dkin = module_charge::cal_dkin( + &this->chr, + this->inp_->nelec, + *this->pw_rho, + p_chgmix->get_mixing_config(), + ucell.omega); } // Iter finish const bool output_charge = iter % this->inp_->out_freq_elec == 0 || conv_esolver || iter == iter_limit; if (!this->defer_iter_output(istep) && output_charge) { - const System_para& system = PARAM.globalv; + const System_para &system = PARAM.globalv; const bool write_restart = this->inp_->out_chg[0] != -1; const std::string prefix = system.global_out_dir + this->inp_->suffix; const bool write_tau = XC_Functional::get_ked_flag(); const bool writer_pool = GlobalV::MY_POOL == 0; const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); - module_charge::write_density_restart(this->chr, - *this->pw_rhod, - ucell.GT, - prefix, - this->inp_->nspin, - write_restart, - system.gamma_only_pw, - write_tau, - writer_pool, - pw_world, - &GlobalV::ofs_warning); + module_charge::write_density_restart( + this->chr, + *this->pw_rhod, + ucell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); } // the end, print time double duration = ModuleBase::get_duration(iter_time, ModuleBase::get_time()); // print energies - elecstate::print_etot(ucell.magnet, *pelec, conv_esolver, iter, iter_limit, drho, - dkin, duration, *this->inp_, PARAM.globalv.two_fermi, diag_ethr, 0, true, this->ds_rms_); - + elecstate::print_etot( + ucell.magnet, + *pelec, + conv_esolver, + iter, + iter_limit, + drho, + dkin, + duration, + *this->inp_, + PARAM.globalv.two_fermi, + diag_ethr, + 0, + true, + this->ds_rms_); if (!this->defer_iter_output(istep)) { @@ -448,56 +568,67 @@ void ESolver_KS::write_iter_bands() { if (this->inp_->out_band[0]) { - ModuleIO::write_eig_iter(this->pelec->ekb, this->pelec->wg, *this->pelec->klist, - this->inp_->nbands, this->inp_->nspin); + ModuleIO::write_eig_iter( + this->pelec->ekb, + this->pelec->wg, + *this->pelec->klist, + this->inp_->nbands, + this->inp_->nspin); } } -void ESolver_KS::record_iteration(const UnitCell& ucell, double duration) +void ESolver_KS::record_iteration(const UnitCell &ucell, double duration) { #ifdef __JSON - Json::add_output_scf_mag(ucell.magnet.tot_mag, ucell.magnet.abs_mag, - this->pelec->f_en.etot * ModuleBase::Ry_to_eV, - this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV, - drho, duration); + Json::add_output_scf_mag( + ucell.magnet.tot_mag, + ucell.magnet.abs_mag, + this->pelec->f_en.etot * ModuleBase::Ry_to_eV, + this->pelec->f_en.etot_delta * ModuleBase::Ry_to_eV, + drho, + duration); #endif //__JSON } //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. -void ESolver_KS::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_KS::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_KS", "after_scf"); - -/* - // 1) calculate the kinetic energy density tau - if (this->inp_->out_elf[0] > 0) - { - assert(this->psi != nullptr); - this->pelec->cal_tau(*(this->psi)); - } -*/ - + + /* + // 1) calculate the kinetic energy density tau + if (this->inp_->out_elf[0] > 0) + { + assert(this->psi != nullptr); + this->pelec->cal_tau(*(this->psi)); + } + */ + // 2) call after_scf() of ESolver_FP ESolver_FP::after_scf(ucell, istep, conv_esolver); // 3) write eigenvalues and occupations to eig_occ.txt - ModuleIO::write_eig_file(this->pelec->ekb, - this->pelec->wg, - this->kv, - this->inp_->nbands, - this->inp_->nspin, - PARAM.globalv.global_out_dir, - istep); + ModuleIO::write_eig_file( + this->pelec->ekb, + this->pelec->wg, + this->kv, + this->inp_->nbands, + this->inp_->nspin, + PARAM.globalv.global_out_dir, + istep); // 4) write band information to band.txt - ModuleIO::write_bands(*this->inp_, this->pelec->ekb, this->kv, GlobalV::ofs_running); - + ModuleIO::write_bands( + *this->inp_, + this->pelec->ekb, + this->kv, + GlobalV::ofs_running); } -void ESolver_KS::after_all_runners(BaseCell& basecell) +void ESolver_KS::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); // 1) write Etot information ESolver_FP::after_all_runners(ucell); diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index 6fde06b0d3..4ac55c08f4 100644 --- a/source/source_esolver/esolver_ks.h +++ b/source/source_esolver/esolver_ks.h @@ -1,14 +1,14 @@ #ifndef ESOLVER_KS_H #define ESOLVER_KS_H -#include "esolver_fp.h" // first-principles esolver -#include "source_basis/module_pw/pw_basis_k.h" // use plane wave -#include "source_cell/klist.h" // use k-points in Brillouin zone -#include "source_estate/module_charge/chg_mix.h" // use charge mixing -#include "source_hamilt/hamilt.h" // use Hamiltonian -#include "source_hamilt/hamilt_base.h" // use Hamiltonian base class -#include "source_hamilt/module_xc/general_exx_info.h" // ESolver owns General_Exx_Info value -#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base for dftu_ member +#include "esolver_fp.h" // first-principles esolver +#include "source_basis/module_pw/pw_basis_k.h" // use plane wave +#include "source_cell/klist.h" // use k-points in Brillouin zone +#include "source_estate/module_charge/chg_mix.h" // use charge mixing +#include "source_hamilt/hamilt.h" // use Hamiltonian +#include "source_hamilt/hamilt_base.h" // use Hamiltonian base class +#include "source_hamilt/module_xc/general_exx_info.h" // ESolver owns General_Exx_Info value +#include "source_pw/module_pwdft/dftu_base.h" // Plus_U_Base for dftu_ member #include "source_pw/module_pwdft/vnl_pw.h" #include // std::unique_ptr for dftu_ member @@ -25,20 +25,20 @@ class ESolver_KS : public ESolver_FP //! Deconstructor virtual ~ESolver_KS(); - virtual void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + virtual void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - virtual void runner(BaseCell& basecell, const int istep) override; + virtual void runner(BaseCell &basecell, const int istep) override; - virtual void after_all_runners(BaseCell& basecell) override; + virtual void after_all_runners(BaseCell &basecell) override; protected: //! Maximum SCF iterations for the current electronic step. virtual int scf_iter_limit(const int istep) const; /** @brief Run SCF iterations without preparing or committing a physical endpoint. */ - bool scf_loop(UnitCell& ucell, int istep, int iter_limit); + bool scf_loop(UnitCell &ucell, int istep, int iter_limit); /** @brief Record an accepted iteration in JSON without changing its convergence status. */ - void record_iteration(const UnitCell& ucell, double duration); + void record_iteration(const UnitCell &ucell, double duration); /** @brief Write current band expectations when iterative band output is requested. */ void write_iter_bands(); @@ -53,22 +53,34 @@ class ESolver_KS : public ESolver_FP virtual DensityStage density_stage(const int istep, const int iter) const; //! Something to do before SCF iterations. - virtual void before_scf(UnitCell& ucell, const int istep) override; + virtual void before_scf(UnitCell &ucell, const int istep) override; //! Something to do before hamilt2rho function in each iter loop. - virtual void iter_init(UnitCell& ucell, const int istep, const int iter); + virtual void iter_init(UnitCell &ucell, const int istep, const int iter); //! Whether KS iterations defer output until the final state is accepted. virtual bool defer_iter_output(const int istep) const; //! Something to do after hamilt2rho function in each iter loop. - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; // calculate electron density from a specific Hamiltonian with ethr - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr); + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr); // calculate electron density from a specific Hamiltonian - void hamilt2rho(UnitCell& ucell, const int istep, const int iter, const double ethr); + void hamilt2rho( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr); /** * @brief Select the diagonalization threshold and error-control policy for the current stage. @@ -78,16 +90,16 @@ class ESolver_KS : public ESolver_FP virtual std::string diag_policy(const int istep) const; //! Something to do after SCF iterations when SCF is converged or comes to the max iter step. - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; //! Hamiltonian (base class pointer, actual type determined at runtime) - hamilt::HamiltBase* p_hamilt = nullptr; + hamilt::HamiltBase *p_hamilt = nullptr; //! PW for wave functions, only used in KSDFT, not in OFDFT - ModulePW::PW_Basis_K* pw_wfc = nullptr; + ModulePW::PW_Basis_K *pw_wfc = nullptr; //! Charge mixing method - Charge_Mixing* p_chgmix = nullptr; + Charge_Mixing *p_chgmix = nullptr; //! nonlocal pseudopotentials pseudopot_cell_vnl ppcell; @@ -96,13 +108,13 @@ class ESolver_KS : public ESolver_FP //! Owned by ESolver_KS via unique_ptr; released automatically in ~ESolver_KS. std::unique_ptr dftu_; - std::string basisname; //! esolver_ks_lcao.cpp - double esolver_KS_ne = 0.0; //! number of electrons - double diag_ethr; //! the threshold for diagonalization - double scf_thr; //! scf density threshold - double scf_ene_thr; //! scf energy threshold - double drho; //! the difference between rho_in (before HSolver) and rho_out (After HSolver) - double hsolver_error; //! the error of HSolver + std::string basisname; //! esolver_ks_lcao.cpp + double esolver_KS_ne = 0.0; //! number of electrons + double diag_ethr; //! the threshold for diagonalization + double scf_thr; //! scf density threshold + double scf_ene_thr; //! scf energy threshold + double drho; //! the difference between rho_in (before HSolver) and rho_out (After HSolver) + double hsolver_error; //! the error of HSolver /// DeltaSpin RMS from the most recent lambda optimization loop; -1.0 means no DeltaSpin. /// Set by ESolver_KS_LCAO after run_lambda_loop, read by ESolver_KS::iter_finish when calling print_etot. double ds_rms_ = -1.0; diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index f476cf78d9..37420b5f71 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -44,37 +44,36 @@ namespace ModuleESolver #ifdef __EXX namespace { -void validate_librpa_v1_kpoints(const Input_para& input, const K_Vectors& kv) +void validate_librpa_v1_kpoints(const Input_para &input, const K_Vectors &kv) { // Reader-v1 writes the complete Monkhorst-Pack mesh for LibRPA. if (input.rpa && input.out_librpa_ver == 1 && !kv.is_uniform_mp()) { - ModuleBase::WARNING_QUIT("ESolver_KS_LCAO::before_all_runners", "out_librpa_ver=1 requires a uniform Monkhorst-Pack k-point grid."); + ModuleBase::WARNING_QUIT( + "ESolver_KS_LCAO::before_all_runners", "out_librpa_ver=1 requires a uniform Monkhorst-Pack k-point grid."); } } } // namespace #endif -template -ESolver_KS_LCAO::ESolver_KS_LCAO() +template ESolver_KS_LCAO::ESolver_KS_LCAO() { this->classname = "ESolver_KS_LCAO"; this->basisname = "LCAO"; this->dftu_.reset(new Plus_U_Base()); } -template -ESolver_KS_LCAO::~ESolver_KS_LCAO() +template ESolver_KS_LCAO::~ESolver_KS_LCAO() { // Release the electronic wave functions owned by this solver. Setup_Psi::deallocate_psi(this->psi); } template -void ESolver_KS_LCAO::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_KS_LCAO::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO", "before_all_runners"); ModuleBase::timer::start("ESolver_KS_LCAO", "before_all_runners"); @@ -96,49 +95,66 @@ void ESolver_KS_LCAO::before_all_runners(BaseCell& basecell, const Input if (this->pelec == nullptr) { // TK is double or std::complex. - this->pelec = new elecstate::ElecStateLCAO(&(this->chr), &(this->kv), this->kv.get_nks(), this->pw_big); + this->pelec = new elecstate::ElecStateLCAO( + &(this->chr), + &(this->kv), + this->kv.get_nks(), + this->pw_big); } // 5) read LCAO orbitals/projectors and construct the interpolation tables. - LCAO_domain::init_basis_lcao(this->pv, - inp.onsite_radius, - inp.lcao_ecut, - inp.lcao_dk, - inp.lcao_dr, - inp.lcao_rmax, - ucell, - two_center_bundle_, - orb_); + LCAO_domain::init_basis_lcao( + this->pv, + inp.onsite_radius, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + ucell, + two_center_bundle_, + orb_); // 6) generate matrices for optimized auxiliary basis functions when requested if (inp.calculation == "gen_opt_abfs") { #ifdef __EXX Exx_Opt_Orb exx_opt_orb; - exx_opt_orb.generate_matrix(exx_info_.info_opt_abfs, this->kv, ucell, this->orb_); + exx_opt_orb.generate_matrix( + exx_info_.info_opt_abfs, + this->kv, + ucell, + this->orb_); #else ModuleBase::WARNING_QUIT("ESolver_KS_LCAO::before_all_runners", "calculation=gen_opt_abfs must compile __EXX"); #endif return; } - LCAO_domain::set_psi_occ_dm_chg(this->kv, this->psi, this->pv, this->pelec, this->dmat, this->chr, inp); - - LCAO_domain::set_pot(ucell, - this->kv, - this->sf, - *this->pw_rho, - *this->pw_rhod, - this->pelec, - this->orb_, - this->pv, - this->locpp, - *this->dftu_, - this->solvent, - this->exx_nao, - this->deepks, - inp, - this->exx_info_); + LCAO_domain::set_psi_occ_dm_chg( + this->kv, + this->psi, + this->pv, + this->pelec, + this->dmat, + this->chr, + inp); + + LCAO_domain::set_pot( + ucell, + this->kv, + this->sf, + *this->pw_rho, + *this->pw_rhod, + this->pelec, + this->orb_, + this->pv, + this->locpp, + *this->dftu_, + this->solvent, + this->exx_nao, + this->deepks, + inp, + this->exx_info_); //! if nks is not divisible by kpar, print a warning ModuleIO::print_kpar(this->kv.get_nks(), PARAM.globalv.kpar_lcao); @@ -146,30 +162,30 @@ void ESolver_KS_LCAO::before_all_runners(BaseCell& basecell, const Input //! init rdmft, added by jghan if (inp.rdmft == true) { - rdmft_solver.init(this->pv, - ucell, - this->gd, - this->kv, - *(this->pelec), - this->orb_, - two_center_bundle_, - inp.dft_functional, - inp.rdmft_power_alpha, - this->exx_info_); + rdmft_solver.init( + this->pv, + ucell, + this->gd, + this->kv, + *(this->pelec), + this->orb_, + two_center_bundle_, + inp.dft_functional, + inp.rdmft_power_alpha, + this->exx_info_); } ModuleBase::timer::end("ESolver_KS_LCAO", "before_all_runners"); return; } -template -void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep) +template void ESolver_KS_LCAO::before_scf(UnitCell &ucell, const int istep) { this->before_scf(ucell, istep, istep); } template -void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const int output_step) +void ESolver_KS_LCAO::before_scf(UnitCell &ucell, const int istep, const int output_step) { ModuleBase::TITLE("ESolver_KS_LCAO", "before_scf"); ModuleBase::timer::start("ESolver_KS_LCAO", "before_scf"); @@ -179,42 +195,56 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const ESolver_KS::before_scf(ucell, output_step); //! 2) find search radius - double search_radius = atom_arrange::set_sr_NL(GlobalV::ofs_running, - this->inp_->out_level, - orb_.get_rcutmax_Phi(), - ucell.infoNL->get_rcutmax_Beta(), - PARAM.globalv.gamma_only_local); + double search_radius = atom_arrange::set_sr_NL( + GlobalV::ofs_running, + this->inp_->out_level, + orb_.get_rcutmax_Phi(), + ucell.infoNL->get_rcutmax_Beta(), + PARAM.globalv.gamma_only_local); //! 3) use search_radius to search adj atoms - atom_arrange::search(PARAM.globalv.search_pbc, GlobalV::ofs_running, this->gd, ucell, search_radius, this->inp_->test_atom_input); + atom_arrange::search( + PARAM.globalv.search_pbc, + GlobalV::ofs_running, + this->gd, + ucell, + search_radius, + this->inp_->test_atom_input); //! 4) initialize grid-integration information // The unique pointer owns the grid-integration information. - gint_info_.reset(new ModuleGint::GintInfo(this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbz, - this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz, - 0, - 0, - this->pw_big->nbzp_start, - this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbzp, - orb_.Phi, - ucell, - this->gd, - this->inp_->nspin, - PARAM.globalv.gamma_only_local, - PARAM.globalv.domag, - this->inp_->device == "gpu", - this->inp_->nstream)); + gint_info_.reset(new ModuleGint::GintInfo( + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbz, + this->pw_rho->nx, + this->pw_rho->ny, + this->pw_rho->nz, + 0, + 0, + this->pw_big->nbzp_start, + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbzp, + orb_.Phi, + ucell, + this->gd, + this->inp_->nspin, + PARAM.globalv.gamma_only_local, + PARAM.globalv.domag, + this->inp_->device == "gpu", + this->inp_->nstream)); ModuleGint::Gint::set_gint_info(gint_info_.get()); // 5) For each atom, record the adjacent atoms in different cells // and determine the local real-space matrix layout for multi-k calculations. - this->RA.for_2d(ucell, this->gd, this->pv, PARAM.globalv.gamma_only_local, PARAM.globalv.npol, orb_.cutoffs()); + this->RA.for_2d( + ucell, + this->gd, + this->pv, + PARAM.globalv.gamma_only_local, + PARAM.globalv.npol, + orb_.cutoffs()); if (this->inp_->out_level != "m" && !PARAM.globalv.gamma_only_local) { ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "ParaV.nnr", this->pv.nnr); @@ -230,22 +260,23 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const if (this->p_hamilt == nullptr) { const bool load_exx_flag = !GlobalC::restart.info_load.restart_exx && GlobalC::restart.info_load.load_H; - this->p_hamilt = new hamilt::HamiltLCAO(ucell, - this->gd, - &this->pv, - this->pelec->pot, - this->kv, - two_center_bundle_, - orb_, - this->dmat.dm, - this->dftu_.get(), - this->deepks, - istep, - exx_nao, - this->exx_info_, - *this->inp_, - load_exx_flag, - this->get_td_info()); + this->p_hamilt = new hamilt::HamiltLCAO( + ucell, + this->gd, + &this->pv, + this->pelec->pot, + this->kv, + two_center_bundle_, + orb_, + this->dmat.dm, + this->dftu_.get(), + this->deepks, + istep, + exx_nao, + this->exx_info_, + *this->inp_, + load_exx_flag, + this->get_td_info()); } // 7) for each ionic step, the overlap must be rebuilt @@ -255,17 +286,39 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const // reference from a null unique_ptr (undefined behaviour). if (two_center_bundle_.overlap_orb_alpha) { - this->deepks.build_overlap(ucell, orb_, pv, gd, *(two_center_bundle_.overlap_orb_alpha), *this->inp_); + this->deepks.build_overlap( + ucell, + orb_, + pv, + gd, + *(two_center_bundle_.overlap_orb_alpha), + *this->inp_); } // 8) prepare the DeltaSpin spin-constrained calculation - init_deltaspin_lcao(ucell, *this->inp_, &(this->pv), this->kv, this->p_hamilt, this->psi, this->dmat.dm, this->pelec); + init_deltaspin_lcao( + ucell, + *this->inp_, + &(this->pv), + this->kv, + this->p_hamilt, + this->psi, + this->dmat.dm, + this->pelec); // 9) set the XC type before the first XC calculation in elecstate::init_scf, Peize Lin add 2016-12-03 - this->exx_nao.before_scf(ucell, this->kv, orb_, this->pv, this->p_chgmix, istep, *this->inp_, this->exx_info_); + this->exx_nao.before_scf( + ucell, + this->kv, + orb_, + this->pv, + this->p_chgmix, + istep, + *this->inp_, + this->exx_info_); // 10) initialize DM(R) with the sparsity pattern of H(R) - auto* hamilt_lcao = dynamic_cast*>(this->p_hamilt); + auto *hamilt_lcao = dynamic_cast *>(this->p_hamilt); if (!hamilt_lcao) { @@ -280,26 +333,28 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const if (this->inp_->init_chg == "dm" || this->inp_->init_chg == "dm_no_renormalize") { //! 11.1) init charge density from density matrix file - LCAO_domain::init_chg_dm(PARAM.globalv.global_readin_dir, - this->inp_->nspin, - this->dmat, - ucell, - &(this->pv), - this->pelec->charge); + LCAO_domain::init_chg_dm( + PARAM.globalv.global_readin_dir, + this->inp_->nspin, + this->dmat, + ucell, + &(this->pv), + this->pelec->charge); } if (this->inp_->init_chg == "hr") { //! 11.2) init charge density from Hamiltonian matrix file - LCAO_domain::init_chg_hr(PARAM.globalv.global_readin_dir, - this->inp_->nspin, - static_cast*>(this->p_hamilt), - ucell, - &(this->pv), - this->psi[0], - this->pelec, - *this->dmat.dm, - this->chr, - this->inp_->ks_solver); + LCAO_domain::init_chg_hr( + PARAM.globalv.global_readin_dir, + this->inp_->nspin, + static_cast *>(this->p_hamilt), + ucell, + &(this->pv), + this->psi[0], + this->pelec, + *this->dmat.dm, + this->chr, + this->inp_->ks_solver); } } else if (this->inp_->esolver_type != "tddft") // for later non-TDDFT steps, reuse the previous DMK @@ -308,44 +363,53 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const this->dmat.dm->cal_dmr(-1); } // 12) initialize core charge and potential, and write the initial potential using output_step, mohan add 2025-03-10 - elecstate::init_scf(ucell, - this->Pgrid, - this->sf.strucFac, - this->locpp.numeric, - output_step, - PARAM.globalv.global_out_dir, - *this->inp_, - this->pelec); + elecstate::init_scf( + ucell, + this->Pgrid, + this->sf.strucFac, + this->locpp.numeric, + output_step, + PARAM.globalv.global_out_dir, + *this->inp_, + this->pelec); #ifdef __MLALGO // 13) initialize the DeePKS density-matrix storage with its own adjacency pattern - this->deepks.ld.init_dmr(ucell, orb_, this->pv, this->gd); + this->deepks.ld.init_dmr( + ucell, + orb_, + this->pv, + this->gd); #endif // 14) the electron charge density should be symmetrized - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rho, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rho, + ucell.symm); // 15) update of RDMFT, added by jghan if (this->inp_->rdmft == true) { - rdmft_solver.update_ion(ucell, *(this->pw_rho), this->locpp.vloc, this->sf.strucFac); + rdmft_solver.update_ion( + ucell, + *(this->pw_rho), + this->locpp.vloc, + this->sf.strucFac); } ModuleBase::timer::end("ESolver_KS_LCAO", "before_scf"); return; } -template -double ESolver_KS_LCAO::cal_energy() -{ - return this->pelec->f_en.etot; -} +template double ESolver_KS_LCAO::cal_energy() { return this->pelec->f_en.etot; } template -void ESolver_KS_LCAO::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_KS_LCAO::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO", "cal_force"); ModuleBase::timer::start("ESolver_KS_LCAO", "cal_force"); @@ -355,44 +419,45 @@ void ESolver_KS_LCAO::cal_force(BaseCell& basecell, ModuleBase::matrix& deepks.dpks_out_type = "tot"; // for deepks method const FSCalcConfig fs_cfg{this->inp_->nspin, - this->inp_->nbands, - this->inp_->t_in_h, - this->inp_->sc_mag_switch, - this->inp_->device, - PARAM.globalv.domag, - PARAM.globalv.domag_z, - this->inp_->gga_grad, - PARAM.globalv.gamma_only_pw, - this->inp_->imp_sol}; - - fsl.getForceStress(ucell, - this->get_vdw_result(), - this->inp_->cal_force, - this->inp_->cal_stress, - this->inp_->test_force, - this->inp_->test_stress, - this->gd, - this->pv, - this->pelec, - this->dmat, - this->psi, - two_center_bundle_, - orb_, - force, - this->scs, - this->locpp, - this->sf, - this->kv, - this->pw_rho, - this->solvent, - *this->dftu_, - this->deepks, - this->exx_nao, - &ucell.symm, - this->exx_info_, - fs_cfg, - this->get_td_info(), - static_cast*>(this->p_hamilt)); + this->inp_->nbands, + this->inp_->t_in_h, + this->inp_->sc_mag_switch, + this->inp_->device, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + PARAM.globalv.gamma_only_pw, + this->inp_->imp_sol}; + + fsl.getForceStress( + ucell, + this->get_vdw_result(), + this->inp_->cal_force, + this->inp_->cal_stress, + this->inp_->test_force, + this->inp_->test_stress, + this->gd, + this->pv, + this->pelec, + this->dmat, + this->psi, + two_center_bundle_, + orb_, + force, + this->scs, + this->locpp, + this->sf, + this->kv, + this->pw_rho, + this->solvent, + *this->dftu_, + this->deepks, + this->exx_nao, + &ucell.symm, + this->exx_info_, + fs_cfg, + this->get_td_info(), + static_cast *>(this->p_hamilt)); // Release the adjacency records after the force/stress calculation. this->RA.delete_grid(); @@ -403,10 +468,10 @@ void ESolver_KS_LCAO::cal_force(BaseCell& basecell, ModuleBase::matrix& } template -void ESolver_KS_LCAO::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_KS_LCAO::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO", "cal_stress"); ModuleBase::timer::start("ESolver_KS_LCAO", "cal_stress"); @@ -424,50 +489,50 @@ void ESolver_KS_LCAO::cal_stress(BaseCell& basecell, ModuleBase::matrix& ModuleBase::timer::end("ESolver_KS_LCAO", "cal_stress"); } -template -void ESolver_KS_LCAO::after_all_runners(BaseCell& basecell) +template void ESolver_KS_LCAO::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO", "after_all_runners"); ModuleBase::timer::start("ESolver_KS_LCAO", "after_all_runners"); ESolver_KS::after_all_runners(ucell); - auto* hamilt_lcao = dynamic_cast*>(this->p_hamilt); + auto *hamilt_lcao = dynamic_cast *>(this->p_hamilt); if (!hamilt_lcao) { ModuleBase::WARNING_QUIT("ESolver_KS_LCAO::after_all_runners", "p_hamilt does not exist"); } - ModuleIO::ctrl_runner_lcao(ucell, - *this->inp_, - this->kv, - this->pelec, - this->dmat, - this->pv, - this->Pgrid, - this->gd, - this->psi, - this->chr, - hamilt_lcao, - this->two_center_bundle_, - this->orb_, - this->pw_rho, - this->pw_rhod, - this->sf, - this->locpp.vloc, - this->exx_nao, - this->exx_info_, - this->solvent, - GlobalV::ofs_running); + ModuleIO::ctrl_runner_lcao( + ucell, + *this->inp_, + this->kv, + this->pelec, + this->dmat, + this->pv, + this->Pgrid, + this->gd, + this->psi, + this->chr, + hamilt_lcao, + this->two_center_bundle_, + this->orb_, + this->pw_rho, + this->pw_rhod, + this->sf, + this->locpp.vloc, + this->exx_nao, + this->exx_info_, + this->solvent, + GlobalV::ofs_running); ModuleBase::timer::end("ESolver_KS_LCAO", "after_all_runners"); } template -void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const int iter) +void ESolver_KS_LCAO::iter_init(UnitCell &ucell, const int istep, const int iter) { ModuleBase::TITLE("ESolver_KS_LCAO", "iter_init"); @@ -476,7 +541,13 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const const int iter_limit = this->scf_iter_limit(istep); const int nnr = this->dmat.dm->get_dmr_ptr(1)->get_nnr(); - module_charge::chgmixing_ks_lcao(iter, iter_limit, this->p_chgmix, *this->dftu_, nnr, *this->inp_); + module_charge::chgmixing_ks_lcao( + iter, + iter_limit, + this->p_chgmix, + *this->dftu_, + nnr, + *this->inp_); if (iter == 1) { @@ -492,7 +563,8 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const else if (this->inp_->gint_precision == "single") { GlobalV::ofs_running << "\n >> Gint single-precision mode: using fp32 throughout SCF" << std::endl; - std::cout << " >> NOTICE: Gint grid-integration uses fp32 throughout SCF (single-precision mode)" << std::endl; + std::cout << " >> NOTICE: Gint grid-integration uses fp32 throughout SCF (single-precision mode)" + << std::endl; } } @@ -506,21 +578,32 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const if (exx_info_.info_global.cal_exx) { // init_dm initializes the density only in the first iteration of the first outer EXX loop. - exx_two_level_step = exx_info_.info_ri.real_number ? this->exx_nao.exd->two_level_step : this->exx_nao.exc->two_level_step; + exx_two_level_step = + exx_info_.info_ri.real_number ? this->exx_nao.exd->two_level_step : this->exx_nao.exc->two_level_step; } #endif module_dm::Init_DM_Config init_dm_cfg; init_dm_cfg.esolver_type = PARAM.inp.esolver_type; - TD_info* td_info = this->get_td_info(); + TD_info *td_info = this->get_td_info(); init_dm_cfg.td_stype = td_info != nullptr ? td_info->field().gauge() : 0; init_dm_cfg.nspin = PARAM.inp.nspin; init_dm_cfg.nelec = PARAM.inp.nelec; - init_dm_cfg.td_phase_hybrid - = (init_dm_cfg.td_stype == 2 && init_dm_cfg.esolver_type != "tddft") ? &td_info->get_phase_hybrid() : nullptr; - init_dm_cfg.td_cart_At - = (init_dm_cfg.td_stype == 2 && init_dm_cfg.esolver_type != "tddft") ? td_info->endpoint_A() : ModuleBase::Vector3(); + init_dm_cfg.td_phase_hybrid = + (init_dm_cfg.td_stype == 2 && init_dm_cfg.esolver_type != "tddft") ? &td_info->get_phase_hybrid() : nullptr; + init_dm_cfg.td_cart_At = (init_dm_cfg.td_stype == 2 && init_dm_cfg.esolver_type != "tddft") + ? td_info->endpoint_A() + : ModuleBase::Vector3(); init_dm_cfg.dm2rho_func = &LCAO_domain::dm2rho; - module_dm::init_dm(ucell, this->pelec, this->dmat, this->psi, this->chr, this->pv, iter, exx_two_level_step, init_dm_cfg); + module_dm::init_dm( + ucell, + this->pelec, + this->dmat, + this->psi, + this->chr, + this->pv, + iter, + exx_two_level_step, + init_dm_cfg); } #ifdef __EXX @@ -529,16 +612,34 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const { if (exx_info_.info_ri.real_number) { - this->exx_nao.exd->exx_eachiterinit(istep, ucell, *this->dmat.dm, this->kv, this->pv, iter); + this->exx_nao.exd->exx_eachiterinit( + istep, + ucell, + *this->dmat.dm, + this->kv, + this->pv, + iter); } else { - this->exx_nao.exc->exx_eachiterinit(istep, ucell, *this->dmat.dm, this->kv, this->pv, iter); + this->exx_nao.exc->exx_eachiterinit( + istep, + ucell, + *this->dmat.dm, + this->kv, + this->pv, + iter); } } #endif - init_dftu_lcao(this->inp_->dft_plus_u, this->dftu_.get(), ucell, this->chr.rho, this->pw_rho->nrxx, &this->orb_); + init_dftu_lcao( + this->inp_->dft_plus_u, + this->dftu_.get(), + ucell, + this->chr.rho, + this->pw_rho->nrxx, + &this->orb_); #ifdef __MLALGO // Mark the DeePKS Hamiltonian correction for recalculation from the updated density matrix. @@ -565,7 +666,11 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const } template -void ESolver_KS_LCAO::hamilt2rho_single(UnitCell& ucell, int istep, int iter, double ethr) +void ESolver_KS_LCAO::hamilt2rho_single( + UnitCell &ucell, + int istep, + int iter, + double ethr) { ModuleBase::TITLE("ESolver_KS_LCAO", "hamilt2rho_single"); @@ -578,7 +683,7 @@ void ESolver_KS_LCAO::hamilt2rho_single(UnitCell& ucell, int istep, int bool skip_solve = false; if (this->inp_->sc_mag_switch) { - spinconstrain::SpinConstrain& sc = spinconstrain::SpinConstrain::getScInstance(); + spinconstrain::SpinConstrain &sc = spinconstrain::SpinConstrain::getScInstance(); if (this->inp_->sc_lambda_strategy == "linear_scan") { sc.run_lambda_linear_scan(iter - 1, GlobalV::ofs_running); @@ -602,24 +707,39 @@ void ESolver_KS_LCAO::hamilt2rho_single(UnitCell& ucell, int istep, int // 3) run HSolver if (!skip_solve) { - hsolver::HSolverLCAO hsolver_lcao_obj(&(this->pv), - this->inp_->ks_solver, - PARAM.globalv.kpar_lcao, - PARAM.globalv.nlocal, - this->inp_->nbands, - this->inp_->nelec, - this->inp_->device == "gpu", - GlobalV::NPROC, - GlobalV::MY_RANK); + hsolver::HSolverLCAO hsolver_lcao_obj( + &(this->pv), + this->inp_->ks_solver, + PARAM.globalv.kpar_lcao, + PARAM.globalv.nlocal, + this->inp_->nbands, + this->inp_->nelec, + this->inp_->device == "gpu", + GlobalV::NPROC, + GlobalV::MY_RANK); // the eigensolvers only ever ask the Hamiltonian for H(k) and S(k) - hamilt::HamiltHSMatrix hs(static_cast*>(this->p_hamilt)); - hsolver_lcao_obj.solve(hs, this->psi[0], this->pelec, *this->dmat.dm, this->chr, this->inp_->nspin, ucell.omega, skip_charge); + hamilt::HamiltHSMatrix hs(static_cast *>(this->p_hamilt)); + hsolver_lcao_obj.solve( + hs, + this->psi[0], + this->pelec, + *this->dmat.dm, + this->chr, + this->inp_->nspin, + ucell.omega, + skip_charge); } else { // Lambda loop updated the density matrix (DM) but not the real-space charge density. // HSolver was skipped, so we need to sync rho from DM manually. - LCAO_domain::dm2rho(this->dmat.dm->get_dmr_vec(), this->inp_->nspin, &this->chr, this->inp_->nelec, ucell.omega, false); + LCAO_domain::dm2rho( + this->dmat.dm->get_dmr_vec(), + this->inp_->nspin, + &this->chr, + this->inp_->nelec, + ucell.omega, + false); } // 4) EXX @@ -641,61 +761,72 @@ void ESolver_KS_LCAO::hamilt2rho_single(UnitCell& ucell, int istep, int // Sync the energy to f_en.exx so that the output prints the correct E_exx. if (exx_info_.info_ri.real_number) { - this->pelec->set_exx(this->exx_nao.exd->get_Eexx(), exx_info_.info_global.cal_exx, exx_info_.info_global.hybrid_alpha); + this->pelec->set_exx( + this->exx_nao.exd->get_Eexx(), exx_info_.info_global.cal_exx, exx_info_.info_global.hybrid_alpha); } else { - this->pelec->set_exx(this->exx_nao.exc->get_Eexx(), exx_info_.info_global.cal_exx, exx_info_.info_global.hybrid_alpha); + this->pelec->set_exx( + this->exx_nao.exc->get_Eexx(), exx_info_.info_global.cal_exx, exx_info_.info_global.hybrid_alpha); } } #endif // 5) symmetrize the charge density - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rho, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rho, + ucell.symm); // 6) calculate delta energy this->pelec->f_en.deband = this->pelec->cal_delta_eband(ucell); } template -void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) +void ESolver_KS_LCAO::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { ModuleBase::TITLE("ESolver_KS_LCAO", "iter_finish"); - auto* hamilt_lcao = dynamic_cast*>(this->p_hamilt); + auto *hamilt_lcao = dynamic_cast *>(this->p_hamilt); if (!hamilt_lcao) { ModuleBase::WARNING_QUIT("ESolver_KS_LCAO::iter_finish", "p_hamilt does not exist"); } - const std::vector>& dm_vec = this->dmat.dm->get_dmk_vec(); + const std::vector> &dm_vec = this->dmat.dm->get_dmk_vec(); // 1) calculate the local occupation number matrix and energy correction in DFT+U const int iter_limit = this->scf_iter_limit(istep); const DFTU_BASE::OccmatOutputCfg occmat_cfg{this->inp_->out_freq_ion, - this->inp_->out_freq_elec, - iter_limit, - this->inp_->out_occ_mat, - this->inp_->dft_plus_u}; + this->inp_->out_freq_elec, + iter_limit, + this->inp_->out_occ_mat, + this->inp_->dft_plus_u}; // Read globalv values once into locals so the repeated DFT+U call sites // below do not each re-enter the global dependency surface. - const std::string& global_out_dir = PARAM.globalv.global_out_dir; + const std::string &global_out_dir = PARAM.globalv.global_out_dir; const bool gamma_only_local = PARAM.globalv.gamma_only_local; - finish_dftu_lcao(conv_esolver, - this->inp_->dft_plus_u, - this->dftu_.get(), - ucell, - dm_vec, - this->kv, - this->p_chgmix->get_mixing_beta(), - hamilt_lcao, - global_out_dir, - this->inp_->nspin, - gamma_only_local, - istep, - iter, - occmat_cfg); + finish_dftu_lcao( + conv_esolver, + this->inp_->dft_plus_u, + this->dftu_.get(), + ucell, + dm_vec, + this->kv, + this->p_chgmix->get_mixing_beta(), + hamilt_lcao, + global_out_dir, + this->inp_->nspin, + gamma_only_local, + istep, + iter, + occmat_cfg); // mohan add 2025-11: push DFT+U energy from Plus_U_Base to ElecState. // Covers both dft_plus_u==1 (new method, energy accumulated by DFTU_onsite::contributeHR @@ -706,7 +837,15 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& } // 2) for DeePKS, update the density matrix and energy corrections - this->deepks.delta_e(ucell, this->kv, this->orb_, this->pv, this->gd, dm_vec, this->pelec->f_en, *this->inp_); + this->deepks.delta_e( + ucell, + this->kv, + this->orb_, + this->pv, + this->gd, + dm_vec, + this->pelec->f_en, + *this->inp_); // 3) for DeltaSpin, calculate atomic magnetic moments cal_mi_lcao_wrapper(iter, *this->inp_); @@ -716,39 +855,46 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& // charge mixing is performed, potential is updated, // Harris-Foulkes and Kohn-Sham energies are computed, and meta-GGA terms, // JSON output and density restart files are handled - ESolver_KS::iter_finish(ucell, istep, iter, conv_esolver); + ESolver_KS::iter_finish( + ucell, + istep, + iter, + conv_esolver); // overwrite occ_mat.txt with the latest occupation matrix and the // actual charge-density residual; ESolver_KS::iter_finish() above has // computed drho for this electronic step. const DFTU_BASE::OccmatStepInfo occmat_step{istep, - iter, - this->scf_thr, - this->drho}; - DFTU_BASE::write_latest_occmat(*this->dftu_, - ucell, - global_out_dir, - occmat_step, - occmat_cfg, - DFTU_BASE::SOC_LAYOUT_SPIN_BASIS_REAL); + iter, + this->scf_thr, + this->drho}; + DFTU_BASE::write_latest_occmat( + *this->dftu_, + ucell, + global_out_dir, + occmat_step, + occmat_cfg, + DFTU_BASE::SOC_LAYOUT_SPIN_BASIS_REAL); // append the current SCF-iteration section to occ_matg{#}.txt // LCAO computes the occupation matrix in every electronic iteration, so // the snapshot always carries a real matrix. - DFTU_BASE::append_ion_step_snapshot(*this->dftu_, - ucell, - global_out_dir, - occmat_step, - conv_esolver, - true, - occmat_cfg, - DFTU_BASE::SOC_LAYOUT_SPIN_BASIS_REAL); + DFTU_BASE::append_ion_step_snapshot( + *this->dftu_, + ucell, + global_out_dir, + occmat_step, + conv_esolver, + true, + occmat_cfg, + DFTU_BASE::SOC_LAYOUT_SPIN_BASIS_REAL); const bool precision_switched = this->gint_precision_controller_.update_after_iteration(this->drho, this->scf_thr); this->gint_info_->set_exec_precision(this->gint_precision_controller_.current_precision()); if (precision_switched) { - GlobalV::ofs_running << "\n >> Gint precision switched: fp32 -> fp64 (drho = " << this->drho << ")" << std::endl; + GlobalV::ofs_running << "\n >> Gint precision switched: fp32 -> fp64 (drho = " << this->drho << ")" + << std::endl; std::cout << " >> NOTICE: Gint grid-integration precision switched from fp32 to fp64" << std::endl; } @@ -760,53 +906,55 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& { // Extract the contiguous per-spin DMR buffers expected by the // stateless mixing kernel. - const std::vector*>& dmr_containers = this->dmat.dm->get_dmr_vec(); - const std::vector>& dmr_save = this->dmat.dm->get_dmr_save(); - std::vector dmr_out; - std::vector dmr_in; + const std::vector *> &dmr_containers = this->dmat.dm->get_dmr_vec(); + const std::vector> &dmr_save = this->dmat.dm->get_dmr_save(); + std::vector dmr_out; + std::vector dmr_in; for (std::size_t is = 0; is < dmr_containers.size(); ++is) { dmr_out.push_back(dmr_containers[is]->get_wrapper()); dmr_in.push_back(dmr_save[is].data()); } - module_charge::mix_dmr(dmr_out, - dmr_in, - dmr_containers[0]->get_nnr(), - this->p_chgmix->get_mixing(), - this->p_chgmix->get_dmr_mdata(), - this->p_chgmix->get_mixing_config()); + module_charge::mix_dmr( + dmr_out, + dmr_in, + dmr_containers[0]->get_nnr(), + this->p_chgmix->get_mixing(), + this->p_chgmix->get_dmr_mdata(), + this->p_chgmix->get_mixing_config()); } } // control the output related to the finished iteration - ModuleIO::ctrl_iter_lcao(ucell, - *this->inp_, - this->kv, - this->pelec, - *this->dmat.dm, - this->pv, - this->gd, - this->psi, - this->chr, - this->p_chgmix, - hamilt_lcao, - this->orb_, - this->deepks, - this->exx_nao, - this->exx_info_, - iter, - istep, - conv_esolver, - this->scf_ene_thr); + ModuleIO::ctrl_iter_lcao( + ucell, + *this->inp_, + this->kv, + this->pelec, + *this->dmat.dm, + this->pv, + this->gd, + this->psi, + this->chr, + this->p_chgmix, + hamilt_lcao, + this->orb_, + this->deepks, + this->exx_nao, + this->exx_info_, + iter, + istep, + conv_esolver, + this->scf_ene_thr); } template -void ESolver_KS_LCAO::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_KS_LCAO::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_KS_LCAO", "after_scf"); ModuleBase::timer::start("ESolver_KS_LCAO", "after_scf"); - auto* hamilt_lcao = dynamic_cast*>(this->p_hamilt); + auto *hamilt_lcao = dynamic_cast *>(this->p_hamilt); if (!hamilt_lcao) { @@ -822,33 +970,34 @@ void ESolver_KS_LCAO::after_scf(UnitCell& ucell, const int istep, const ESolver_KS::after_scf(ucell, istep, conv_esolver); //! 2) write LCAO output using the applicable ionic or RT-TDDFT electronic step - ModuleIO::ctrl_scf_lcao(ucell, - *this->inp_, - this->kv, - this->pelec, - this->dmat.dm, - this->pv, - this->gd, - this->psi, - hamilt_lcao, - *this->dftu_, - this->two_center_bundle_, - this->orb_, - this->pw_wfc, - this->pw_rho, - this->pw_big, - this->sf, - this->pw_rhod, - this->locpp.vloc, - this->solvent, - this->rdmft_solver, - this->deepks, - this->exx_nao, - this->exx_info_, - conv_esolver, - this->scf_nmax_flag, - istep, - GlobalV::ofs_running); + ModuleIO::ctrl_scf_lcao( + ucell, + *this->inp_, + this->kv, + this->pelec, + this->dmat.dm, + this->pv, + this->gd, + this->psi, + hamilt_lcao, + *this->dftu_, + this->two_center_bundle_, + this->orb_, + this->pw_wfc, + this->pw_rho, + this->pw_big, + this->sf, + this->pw_rhod, + this->locpp.vloc, + this->solvent, + this->rdmft_solver, + this->deepks, + this->exx_nao, + this->exx_info_, + conv_esolver, + this->scf_nmax_flag, + istep, + GlobalV::ofs_running); //! 3) Clean up the adjacency records in RA when forces and stress are not needed if (!this->inp_->cal_force && !this->inp_->cal_stress) diff --git a/source/source_esolver/esolver_ks_lcao.h b/source/source_esolver/esolver_ks_lcao.h index 6fca9c417e..496e5edab2 100644 --- a/source/source_esolver/esolver_ks_lcao.h +++ b/source/source_esolver/esolver_ks_lcao.h @@ -22,12 +22,10 @@ namespace ModuleESolver { //! Forward declaration for the linear-response solver. -template -class ESolver_LR; +template class ESolver_LR; //! Kohn-Sham energy solver using the LCAO basis. -template -class ESolver_KS_LCAO : public ESolver_KS +template class ESolver_KS_LCAO : public ESolver_KS { public: //! Initialize the solver identity and DFT+U storage. @@ -36,47 +34,55 @@ class ESolver_KS_LCAO : public ESolver_KS ~ESolver_KS_LCAO(); //! Initialize the LCAO basis, electronic state, and potentials before all steps. - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; //! Return the electronic total energy in Ry. double cal_energy() override; //! Calculate the requested forces and stress, caching the stress for cal_stress(). - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; //! Return the cached stress, calling cal_force() first when needed. - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; //! Perform final LCAO output and postprocessing after all steps. - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; protected: //! Optional solver-owned RT state passed to LCAO consumers. - virtual TD_info* get_td_info() const { return nullptr; } + virtual TD_info *get_td_info() const { return nullptr; } //! Prepare an ionic step using istep for both initialization and initial-state output. - virtual void before_scf(UnitCell& ucell, const int istep) override; + virtual void before_scf(UnitCell &ucell, const int istep) override; //! Prepare an ionic step with a separate index for initial charge and potential output. - void before_scf(UnitCell& ucell, const int istep, const int output_step); + void before_scf(UnitCell &ucell, const int istep, const int output_step); //! Prepare charge mixing and Hamiltonian updates for an SCF iteration. - virtual void iter_init(UnitCell& ucell, const int istep, const int iter) override; + virtual void iter_init(UnitCell &ucell, const int istep, const int iter) override; //! Solve the Hamiltonian and update the charge density and energy terms. - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; //! Finish an SCF iteration with energy corrections, mixing, convergence checks, and output. - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; //! Write the SCF results and release adjacency records when forces and stress are not requested. - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; //! Run specialized LCAO calculations outside the standard SCF workflow. - virtual void others(BaseCell& basecell, const int istep) override; + virtual void others(BaseCell &basecell, const int istep) override; //! Electronic wave functions (moved from base class) - psi::Psi* psi = nullptr; + psi::Psi *psi = nullptr; //! Store information about adjacent atoms for the distributed matrix layout. Record_adj RA; diff --git a/source/source_esolver/esolver_ks_lcao_tddft.cpp b/source/source_esolver/esolver_ks_lcao_tddft.cpp index bc4c5bbc44..ff91c500d5 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.cpp +++ b/source/source_esolver/esolver_ks_lcao_tddft.cpp @@ -31,15 +31,13 @@ namespace ModuleESolver { -template -ESolver_KS_LCAO_TDDFT::ESolver_KS_LCAO_TDDFT() +template ESolver_KS_LCAO_TDDFT::ESolver_KS_LCAO_TDDFT() { this->classname = "ESolver_rtTDDFT"; this->basisname = "LCAO"; } -template -ESolver_KS_LCAO_TDDFT::~ESolver_KS_LCAO_TDDFT() +template ESolver_KS_LCAO_TDDFT::~ESolver_KS_LCAO_TDDFT() { if (psi_laststep != nullptr) { @@ -64,11 +62,11 @@ ESolver_KS_LCAO_TDDFT::~ESolver_KS_LCAO_TDDFT() } template -void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - const std::string& output_dir = PARAM.globalv.global_out_dir; + UnitCell &ucell = static_cast(basecell); + const std::string &output_dir = PARAM.globalv.global_out_dir; // If the device is GPU, enable use_tensor; also enable use_lapack unless ks_solver is cuSOLVERMp. ct::DeviceType ct_device_type = ct::DeviceTypeToEnum::value; @@ -114,40 +112,44 @@ void ESolver_KS_LCAO_TDDFT::before_all_runners(BaseCell& basecell, c this->pelec->pot->set_td_field_manager(td_field_manager_); restart_step_ = inp.mdp.md_restart ? td_field_manager_->current_step() : 0; - td_p = new TD_info(&ucell, this->pv, this->orb_, *td_field_manager_); + td_p = new TD_info( + &ucell, + this->pv, + this->orb_, + *td_field_manager_); totstep += restart_step_; if (this->inp_->init_wfc == "file") { - if (!ModuleIO::read_wfc_nao(PARAM.globalv.global_readin_dir, - this->pv, - *(this->psi), - this->pelec->ekb, - this->pelec->wg, - this->kv.ik2iktot, - this->kv.get_nkstot(), - this->inp_->nspin, - this->inp_->init_wfc_file_format == "binary", - 0, - restart_step_)) + if (!ModuleIO::read_wfc_nao( + PARAM.globalv.global_readin_dir, + this->pv, + *(this->psi), + this->pelec->ekb, + this->pelec->wg, + this->kv.ik2iktot, + this->kv.get_nkstot(), + this->inp_->nspin, + this->inp_->init_wfc_file_format == "binary", + 0, + restart_step_)) { ModuleBase::WARNING_QUIT("ESolver_KS_LCAO_TDDFT", "Read electronic wavefunction from file failed!"); } } } -template -int ESolver_KS_LCAO_TDDFT::scf_iter_limit(const int istep) const +template int ESolver_KS_LCAO_TDDFT::scf_iter_limit(const int istep) const { const int initial_step = this->inp_->init_wfc == "file" ? restart_step_ : 0; return istep > initial_step ? this->inp_->td_scf_nmax : this->inp_->scf_nmax; } template -void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int istep) +void ESolver_KS_LCAO_TDDFT::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO_TDDFT", "runner"); ModuleBase::timer::start(this->classname, "runner"); @@ -168,17 +170,27 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist } td_p->update_field(); this->before_scf(ucell, istep, first_estep); // From ESolver_KS_LCAO - td_p->initialize_phase_hybrid(ucell, dynamic_cast, TR>*>(this->p_hamilt)->getHR()); + td_p->initialize_phase_hybrid( + ucell, dynamic_cast, TR> *>(this->p_hamilt)->getHR()); // Refresh existing entries too: phase initialization updates geometry but only creates missing keys. td_p->update_field(); - td_p->calculate_grad_overlap(this->pv, ucell, this->gd, this->orb_.cutoffs(), this->two_center_bundle_.overlap_orb.get()); + td_p->calculate_grad_overlap( + this->pv, + ucell, + this->gd, + this->orb_.cutoffs(), + this->two_center_bundle_.overlap_orb.get()); // Initialize the moving spatial gauge if (use_td_moving_gauge && this->td_mg_ == nullptr) { this->td_mg_ = new module_rt::TD_MovingGauge(); - auto* hamilt_lcao = dynamic_cast, TR>*>(this->p_hamilt); - const hamilt::HContainer* sR_template = hamilt_lcao->getSR(); - this->td_mg_->init_DR(sR_template, &ucell, &this->pv, this->two_center_bundle_.overlap_orb.get()); + auto *hamilt_lcao = dynamic_cast, TR> *>(this->p_hamilt); + const hamilt::HContainer *sR_template = hamilt_lcao->getSR(); + this->td_mg_->init_DR( + sR_template, + &ucell, + &this->pv, + this->two_center_bundle_.overlap_orb.get()); } if (this->inp_->td_stype == 2) @@ -195,7 +207,12 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist if (this->inp_->td_stype != 1 && TD_info::out_current == 1) { // initialize the velocity operator - velocity_mat = new Velocity_op(&ucell, &(this->gd), &this->pv, this->orb_, this->two_center_bundle_.overlap_orb.get()); + velocity_mat = new Velocity_op( + &ucell, + &(this->gd), + &this->pv, + this->orb_, + this->two_center_bundle_.overlap_orb.get()); // calculate velocity operator velocity_mat->calculate_grad_term(); velocity_mat->calculate_vcomm_r(); @@ -210,7 +227,14 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist // Update the last-step matrices and wave functions if any atom crosses the boundary // Apply a phase correction to H, S, and psi to keep consistency when atoms cross periodic boundaries const size_t len_hs_ik = use_tensor && use_lapack ? PARAM.globalv.nlocal * PARAM.globalv.nlocal : this->pv.nloc; - module_rt::reset_matrix_boundary(ucell, this->kv, &(this->pv), this->Hk_laststep, this->Sk_laststep, this->psi_laststep, len_hs_ik); + module_rt::reset_matrix_boundary( + ucell, + this->kv, + &(this->pv), + this->Hk_laststep, + this->Sk_laststep, + this->psi_laststep, + len_hs_ik); for (int estep = 0; estep < estep_max; estep++) { @@ -237,9 +261,12 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist { ModuleIO::write_td_vecpot(PARAM.globalv.global_out_dir, this->totstep, td_field_manager_->A_right_ha()); } - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ax(t)", td_p->endpoint_A()[0]); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ay(t)", td_p->endpoint_A()[1]); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Az(t)", td_p->endpoint_A()[2]); + ModuleBase::GlobalFunc::OUT( + GlobalV::ofs_running, "Cartesian vector potential Ax(t)", td_p->endpoint_A()[0]); + ModuleBase::GlobalFunc::OUT( + GlobalV::ofs_running, "Cartesian vector potential Ay(t)", td_p->endpoint_A()[1]); + ModuleBase::GlobalFunc::OUT( + GlobalV::ofs_running, "Cartesian vector potential Az(t)", td_p->endpoint_A()[2]); } if (this->inp_->td_stype == 0) @@ -257,37 +284,48 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist { this->CE.update_all_dis(ucell); const module_charge::AtomicRhoCfg atomic_rho_cfg_tddft{PARAM.inp.nelec, - PARAM.inp.test_charge, - PARAM.globalv.domag, - PARAM.globalv.domag_z, - GlobalV::ofs_warning}; - this->CE.extrapolate_charge(&this->Pgrid, - ucell, - &this->chr, - *this->pw_rhod, - &this->sf, - GlobalV::ofs_running, - GlobalV::ofs_warning, - atomic_rho_cfg_tddft, - PARAM.globalv.has_float_data); - this->exx_nao.before_scf(ucell, this->kv, this->orb_, this->pv, this->p_chgmix, totstep, *this->inp_, this->exx_info_); - ModuleIO::write_chg_init(ucell, - this->Pgrid, - this->chr, - this->pelec->eferm, - totstep, - PARAM.globalv.global_out_dir, - *this->inp_, - PARAM.globalv.two_fermi, - GlobalV::ofs_running); - elecstate::init_scf(ucell, - this->Pgrid, - this->sf.strucFac, - this->locpp.numeric, - totstep, - PARAM.globalv.global_out_dir, - *this->inp_, - this->pelec); + PARAM.inp.test_charge, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + GlobalV::ofs_warning}; + this->CE.extrapolate_charge( + &this->Pgrid, + ucell, + &this->chr, + *this->pw_rhod, + &this->sf, + GlobalV::ofs_running, + GlobalV::ofs_warning, + atomic_rho_cfg_tddft, + PARAM.globalv.has_float_data); + this->exx_nao.before_scf( + ucell, + this->kv, + this->orb_, + this->pv, + this->p_chgmix, + totstep, + *this->inp_, + this->exx_info_); + ModuleIO::write_chg_init( + ucell, + this->Pgrid, + this->chr, + this->pelec->eferm, + totstep, + PARAM.globalv.global_out_dir, + *this->inp_, + PARAM.globalv.two_fermi, + GlobalV::ofs_running); + elecstate::init_scf( + ucell, + this->Pgrid, + this->sf.strucFac, + this->locpp.numeric, + totstep, + PARAM.globalv.global_out_dir, + *this->inp_, + this->pelec); if (totstep <= this->inp_->td_tend + 1) { @@ -305,16 +343,31 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist for (int iter = 1; iter <= iter_limit; ++iter) { this->scf_nmax_flag = iter == iter_limit; - ModuleIO::write_head_td(GlobalV::ofs_running, istep, totstep, iter, this->basisname); + ModuleIO::write_head_td( + GlobalV::ofs_running, + istep, + totstep, + iter, + this->basisname); // 2.1) Initialization of the SCF iteration this->iter_init(ucell, totstep, iter); // From ESolver_KS_LCAO // 2.2) Use Hamiltonian to obtain charge density - this->hamilt2rho(ucell, totstep, iter, this->diag_ethr); // From ESolver_KS + this->hamilt2rho( + ucell, + totstep, + iter, + this->diag_ethr); // From ESolver_KS // 2.3) Finish the SCF iteration - this->iter_finish(ucell, totstep, estep, estep_max, iter, conv_esolver); + this->iter_finish( + ucell, + totstep, + estep, + estep_max, + iter, + conv_esolver); // 2.4) Check convergence or density oscillation if (conv_esolver || this->oscillate_esolver) @@ -362,8 +415,7 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist } // Output electronic step information using a 1-based step number -template -void ESolver_KS_LCAO_TDDFT::print_step() +template void ESolver_KS_LCAO_TDDFT::print_step() { std::cout << " -------------------------------------------" << std::endl; std::cout << " STEP OF ELECTRON EVOLVE : " << unsigned(totstep) + 1 << std::endl; @@ -371,12 +423,16 @@ void ESolver_KS_LCAO_TDDFT::print_step() } template -void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) +void ESolver_KS_LCAO_TDDFT::hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) { std::vector eij_output(this->kv.get_nks()); for (int ik = 0; ik < this->kv.get_nks(); ++ik) { - module_rt::EijOutputInfo& info = eij_output[ik]; + module_rt::EijOutputInfo &info = eij_output[ik]; info.threshold = this->inp_->td_print_eij; info.electronic_step = istep + 1; info.scf_iteration = iter; @@ -392,58 +448,64 @@ void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const // Update the moving spatial gauge if (use_td_moving_gauge) { - auto* hamilt_lcao = dynamic_cast, TR>*>(this->p_hamilt); - const hamilt::HContainer* sR_template = hamilt_lcao->getSR(); - this->td_mg_->update_DR(sR_template, &ucell, &this->pv, this->two_center_bundle_.overlap_orb.get()); + auto *hamilt_lcao = dynamic_cast, TR> *>(this->p_hamilt); + const hamilt::HContainer *sR_template = hamilt_lcao->getSR(); + this->td_mg_->update_DR( + sR_template, + &ucell, + &this->pv, + this->two_center_bundle_.overlap_orb.get()); } if (this->inp_->init_wfc == "file") { if (istep >= restart_step_ + 1) { - module_rt::Evolve_elec::solve_psi(eij_output, - this->inp_->nbands, - PARAM.globalv.nlocal, - this->kv.get_nks(), - static_cast>*>(this->p_hamilt), - this->pv, - this->psi, - this->psi_laststep, - this->Hk_laststep, - this->Sk_laststep, - this->pelec->ekb, - GlobalV::ofs_running, - this->inp_->propagator, - use_tensor, - use_lapack, - this->td_mg_, - &ucell, - this->kv.kvec_d, - use_td_moving_gauge); + module_rt::Evolve_elec::solve_psi( + eij_output, + this->inp_->nbands, + PARAM.globalv.nlocal, + this->kv.get_nks(), + static_cast> *>(this->p_hamilt), + this->pv, + this->psi, + this->psi_laststep, + this->Hk_laststep, + this->Sk_laststep, + this->pelec->ekb, + GlobalV::ofs_running, + this->inp_->propagator, + use_tensor, + use_lapack, + this->td_mg_, + &ucell, + this->kv.kvec_d, + use_td_moving_gauge); } this->weight_dm_rho(ucell); } else if (istep >= 1) { - module_rt::Evolve_elec::solve_psi(eij_output, - this->inp_->nbands, - PARAM.globalv.nlocal, - this->kv.get_nks(), - static_cast>*>(this->p_hamilt), - this->pv, - this->psi, - this->psi_laststep, - this->Hk_laststep, - this->Sk_laststep, - this->pelec->ekb, - GlobalV::ofs_running, - this->inp_->propagator, - use_tensor, - use_lapack, - this->td_mg_, - &ucell, - this->kv.kvec_d, - use_td_moving_gauge); + module_rt::Evolve_elec::solve_psi( + eij_output, + this->inp_->nbands, + PARAM.globalv.nlocal, + this->kv.get_nks(), + static_cast> *>(this->p_hamilt), + this->pv, + this->psi, + this->psi_laststep, + this->Hk_laststep, + this->Sk_laststep, + this->pelec->ekb, + GlobalV::ofs_running, + this->inp_->propagator, + use_tensor, + use_lapack, + this->td_mg_, + &ucell, + this->kv.kvec_d, + use_td_moving_gauge); this->weight_dm_rho(ucell); } else @@ -454,35 +516,59 @@ void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const if (this->psi != nullptr) { const bool skip_charge = false; - hsolver::HSolverLCAO> hsolver_lcao_obj(&this->pv, - this->inp_->ks_solver, - PARAM.globalv.kpar_lcao, - PARAM.globalv.nlocal, - this->inp_->nbands, - this->inp_->nelec, - this->inp_->device == "gpu", - GlobalV::NPROC, - GlobalV::MY_RANK); - hamilt::HamiltHSMatrix> hs(static_cast>*>(this->p_hamilt)); - hsolver_lcao_obj.solve(hs, this->psi[0], this->pelec, *this->dmat.dm, this->chr, this->inp_->nspin, ucell.omega, skip_charge); + hsolver::HSolverLCAO> hsolver_lcao_obj( + &this->pv, + this->inp_->ks_solver, + PARAM.globalv.kpar_lcao, + PARAM.globalv.nlocal, + this->inp_->nbands, + this->inp_->nelec, + this->inp_->device == "gpu", + GlobalV::NPROC, + GlobalV::MY_RANK); + hamilt::HamiltHSMatrix> hs( + static_cast> *>(this->p_hamilt)); + hsolver_lcao_obj.solve( + hs, + this->psi[0], + this->pelec, + *this->dmat.dm, + this->chr, + this->inp_->nspin, + ucell.omega, + skip_charge); if (this->inp_->td_stype == 2) { // Taoni add 2026-10-11 // Ground-state diagonalization forms an ordinary DMR. Apply the // same hybrid phase convention as propagation before building rho. this->dmat.dm->cal_dmr_td(td_p->get_phase_hybrid(), td_p->endpoint_A(), -1); - LCAO_domain::dm2rho(this->dmat.dm->get_dmr_vec(), this->inp_->nspin, &this->chr, this->inp_->nelec, ucell.omega, false); + LCAO_domain::dm2rho( + this->dmat.dm->get_dmr_vec(), + this->inp_->nspin, + &this->chr, + this->inp_->nelec, + ucell.omega, + false); } } // Symmetrize the charge density only for the ground state - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rho, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rho, + ucell.symm); } #ifdef __EXX if (this->exx_info_.info_ri.real_number) + { this->exx_nao.exd->exx_hamilt2rho(*this->pelec, this->pv, iter); + } else + { this->exx_nao.exc->exx_hamilt2rho(*this->pelec, this->pv, iter); + } #endif // Calculate delta energy @@ -490,12 +576,13 @@ void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const } template -void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell, - const int istep, - const int estep, - const int estep_max, - int& iter, - bool& conv_esolver) +void ESolver_KS_LCAO_TDDFT::iter_finish( + UnitCell &ucell, + const int istep, + const int estep, + const int estep_max, + int &iter, + bool &conv_esolver) { // Print the occupation of each band at the first iteration of the first three electronic steps if (iter == 1 && istep <= 2) @@ -508,46 +595,63 @@ void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell, { for (int ib = 0; ib < this->inp_->nbands; ib++) { - GlobalV::ofs_running << " " << std::setw(9) << ik + 1 << std::setw(8) << ib + 1 << std::setw(12) << this->pelec->wg(ik, ib) - << std::endl; + GlobalV::ofs_running << " " << std::setw(9) << ik + 1 << std::setw(8) << ib + 1 << std::setw(12) + << this->pelec->wg(ik, ib) << std::endl; } } GlobalV::ofs_running << std::endl; } - ESolver_KS_LCAO, TR>::iter_finish(ucell, istep, iter, conv_esolver); + ESolver_KS_LCAO, TR>::iter_finish( + ucell, + istep, + iter, + conv_esolver); // Save the endpoint at convergence or the iteration limit for the next electronic step. const int iter_limit = this->scf_iter_limit(istep); const bool accept_state = conv_esolver || iter == iter_limit; - this->store_h_s_psi(ucell, istep, iter, accept_state); + this->store_h_s_psi( + ucell, + istep, + iter, + accept_state); // At an ionic-step boundary, runner exits immediately after replaying the restart endpoint. // Refresh EDM here before that early exit leads to force and stress calculations. - const bool replay_endpoint = this->inp_->mdp.md_restart && !restart_done && estep == 0 - && restart_step_ % this->inp_->estep_per_md == 0; + const bool replay_endpoint = + this->inp_->mdp.md_restart && !restart_done && estep == 0 && restart_step_ % this->inp_->estep_per_md == 0; const bool last_endpoint = estep == estep_max - 1 || replay_endpoint; // Refresh the energy-density matrix at convergence or the iteration limit for forces and stress. - if (accept_state && last_endpoint && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) && this->inp_->td_edm == 0 - && this->inp_->td_stype != 2) + if (accept_state && last_endpoint && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) && this->inp_->td_edm == 0 && + this->inp_->td_stype != 2) { if (use_tensor && use_lapack) { - module_dm::edm_tddft_lapack(this->pv, - this->dmat, - this->kv, - static_cast>*>(this->p_hamilt)); + module_dm::edm_tddft_lapack( + this->pv, + this->dmat, + this->kv, + static_cast> *>(this->p_hamilt)); } else { - module_dm::edm_tddft(this->pv, this->dmat, this->kv, static_cast>*>(this->p_hamilt)); + module_dm::edm_tddft( + this->pv, + this->dmat, + this->kv, + static_cast> *>(this->p_hamilt)); } } } template -void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int istep, const int iter, const bool conv_esolver) +void ESolver_KS_LCAO_TDDFT::store_h_s_psi( + UnitCell &ucell, + const int istep, + const int iter, + const bool conv_esolver) { const int nbands = this->inp_->nbands; const int nlocal = PARAM.globalv.nlocal; @@ -557,16 +661,17 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int { if (this->psi_laststep == nullptr) { - this->psi_laststep = new psi::Psi>(this->kv.get_nks(), + this->psi_laststep = new psi::Psi>( + this->kv.get_nks(), #ifdef __MPI - this->pv.ncol_bands, - this->pv.nrow, + this->pv.ncol_bands, + this->pv.nrow, #else - nbands, - nlocal, + nbands, + nlocal, #endif - this->kv.ngk, - true); + this->kv.ngk, + true); } // Length of Hk_laststep and Sk_laststep per k-point: nlocal * nlocal for full matrices, nloc for local blocks @@ -576,16 +681,16 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int // Allocate memory for Hk_laststep; use_tensor && use_lapack requires space for the full matrix if (this->Hk_laststep.NumElements() != len_HS_all) { - this->Hk_laststep - = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik})); + this->Hk_laststep = ct::Tensor( + ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik})); this->Hk_laststep.zero(); } // Allocate memory for Sk_laststep; use_tensor && use_lapack requires space for the full matrix if (this->Sk_laststep.NumElements() != len_HS_all) { - this->Sk_laststep - = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik})); + this->Sk_laststep = ct::Tensor( + ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik})); this->Sk_laststep.zero(); } @@ -606,7 +711,7 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int this->p_hamilt->updateHk(ik); hamilt::MatrixBlock> h_mat; hamilt::MatrixBlock> s_mat; - static_cast>*>(this->p_hamilt)->matrix(h_mat, s_mat); + static_cast> *>(this->p_hamilt)->matrix(h_mat, s_mat); // Store H and S matrices to Hk_laststep and Sk_laststep if (use_tensor && use_lapack) @@ -617,8 +722,8 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - std::complex* h_ptr = nullptr; - std::complex* s_ptr = nullptr; + std::complex *h_ptr = nullptr; + std::complex *s_ptr = nullptr; // Define containers for gathered data (only needed for multi-process) module_rt::Matrix_g> h_mat_g; @@ -633,8 +738,16 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int else { // Multiple processes: gather data to the root process (myid == 0) and point to the gathered data - module_rt::gatherMatrix(myid, 0, h_mat, h_mat_g); - module_rt::gatherMatrix(myid, 0, s_mat, s_mat_g); + module_rt::gatherMatrix( + myid, + 0, + h_mat, + h_mat_g); + module_rt::gatherMatrix( + myid, + 0, + s_mat, + s_mat_g); if (myid == 0) { h_ptr = h_mat_g.p.get(); @@ -645,22 +758,42 @@ void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell, const int // Only the root process (myid == 0) performs the copy if (myid == 0 && h_ptr != nullptr && s_ptr != nullptr) { - BlasConnector::copy(len_HS_ik, h_ptr, 1, this->Hk_laststep.template data>() + ik * len_HS_ik, 1); - BlasConnector::copy(len_HS_ik, s_ptr, 1, this->Sk_laststep.template data>() + ik * len_HS_ik, 1); + BlasConnector::copy( + len_HS_ik, + h_ptr, + 1, + this->Hk_laststep.template data>() + ik * len_HS_ik, + 1); + BlasConnector::copy( + len_HS_ik, + s_ptr, + 1, + this->Sk_laststep.template data>() + ik * len_HS_ik, + 1); } #endif } else { - BlasConnector::copy(len_HS_ik, h_mat.p, 1, this->Hk_laststep.template data>() + ik * len_HS_ik, 1); - BlasConnector::copy(len_HS_ik, s_mat.p, 1, this->Sk_laststep.template data>() + ik * len_HS_ik, 1); + BlasConnector::copy( + len_HS_ik, + h_mat.p, + 1, + this->Hk_laststep.template data>() + ik * len_HS_ik, + 1); + BlasConnector::copy( + len_HS_ik, + s_mat.p, + 1, + this->Sk_laststep.template data>() + ik * len_HS_ik, + 1); } // end use_tensor && use_lapack branch } // end ik } // save requested by the caller } template -void ESolver_KS_LCAO_TDDFT::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_KS_LCAO_TDDFT::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_LCAO_TDDFT", "after_scf"); ModuleBase::timer::start(this->classname, "after_scf"); @@ -674,46 +807,51 @@ void ESolver_KS_LCAO_TDDFT::after_scf(UnitCell& ucell, const int ist const bool replay_restart = this->inp_->mdp.md_restart && !restart_done; if (!replay_restart) { - auto* hamilt_lcao = dynamic_cast, TR>*>(this->p_hamilt); - ModuleIO::ctrl_output_td(ucell, - this->chr.rho_save, - this->chr.rhopw, - istep, - this->psi, - this->pelec, - this->kv, - this->two_center_bundle_.overlap_orb.get(), - &this->pv, - this->orb_, - this->velocity_mat, - this->gd, - hamilt_lcao, - this->RA, - this->td_p, - this->exx_nao, - this->exx_info_); + auto *hamilt_lcao = dynamic_cast, TR> *>(this->p_hamilt); + ModuleIO::ctrl_output_td( + ucell, + this->chr.rho_save, + this->chr.rhopw, + istep, + this->psi, + this->pelec, + this->kv, + this->two_center_bundle_.overlap_orb.get(), + &this->pv, + this->orb_, + this->velocity_mat, + this->gd, + hamilt_lcao, + this->RA, + this->td_p, + this->exx_nao, + this->exx_info_); } ModuleBase::timer::end(this->classname, "after_scf"); } -template -void ESolver_KS_LCAO_TDDFT::weight_dm_rho(const UnitCell& ucell) +template void ESolver_KS_LCAO_TDDFT::weight_dm_rho(const UnitCell &ucell) { if (this->inp_->ocp == 1) { - elecstate::fixed_weights(this->inp_->ocp_kb, - this->inp_->nbands, - this->inp_->nelec, - this->pelec->klist, - this->pelec->wg, - this->pelec->skip_weights); + elecstate::fixed_weights( + this->inp_->ocp_kb, + this->inp_->nbands, + this->inp_->nelec, + this->pelec->klist, + this->pelec->wg, + this->pelec->skip_weights); } // Calculate Eband energy elecstate::calEBand(this->pelec->ekb, this->pelec->wg, this->pelec->f_en); - module_dm::dm_from_psi(&this->pv, this->pelec->wg, this->psi[0], *this->dmat.dm); + module_dm::dm_from_psi( + &this->pv, + this->pelec->wg, + this->psi[0], + *this->dmat.dm); if (this->inp_->td_stype == 2) { this->dmat.dm->cal_dmr_td(td_p->get_phase_hybrid(), td_p->endpoint_A(), -1); @@ -724,7 +862,13 @@ void ESolver_KS_LCAO_TDDFT::weight_dm_rho(const UnitCell& ucell) } // get the real-space charge density, mohan add 2025-10-24 - LCAO_domain::dm2rho(this->dmat.dm->get_dmr_vec(), this->inp_->nspin, &this->chr, this->inp_->nelec, ucell.omega, false); + LCAO_domain::dm2rho( + this->dmat.dm->get_dmr_vec(), + this->inp_->nspin, + &this->chr, + this->inp_->nelec, + ucell.omega, + false); } template class ESolver_KS_LCAO_TDDFT; diff --git a/source/source_esolver/esolver_ks_lcao_tddft.h b/source/source_esolver/esolver_ks_lcao_tddft.h index b1401c16da..5d98ad1351 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.h +++ b/source/source_esolver/esolver_ks_lcao_tddft.h @@ -30,35 +30,49 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> ~ESolver_KS_LCAO_TDDFT(); //! Initialize the LCAO solver, shared field state, and optional restart wave functions. - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; protected: //! Use the initial-state limit for initialization or restart replay, and the RT limit for propagation. int scf_iter_limit(const int istep) const override; //! Return the solver-owned RT state used by LCAO operators and output. - TD_info* get_td_info() const override { return td_p; } + TD_info *get_td_info() const override { return td_p; } //! Run the electronic steps belonging to one MD call, including initialization or restart replay. - virtual void runner(BaseCell& basecell, const int istep) override; + virtual void runner(BaseCell &basecell, const int istep) override; //! Obtain the density from initial-state diagonalization, loaded wave functions, or time propagation. - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; //! Save H, S, and wave functions when requested at convergence or the maximum iteration count. - void store_h_s_psi(UnitCell& ucell, const int istep, const int iter, const bool conv_esolver); + void store_h_s_psi( + UnitCell &ucell, + const int istep, + const int iter, + const bool conv_esolver); //! Finish an electronic iteration and update the saved state and requested energy-density matrix. - void iter_finish(UnitCell& ucell, const int istep, const int estep, const int estep_max, int& iter, bool& conv_esolver); + void iter_finish( + UnitCell &ucell, + const int istep, + const int estep, + const int estep_max, + int &iter, + bool &conv_esolver); //! Write the electronic-step energy and TD observables after the SCF loop. - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; //! Print the electronic-step header using a 1-based step number. void print_step(); //! Wave functions for all local k-points of the last electronic step. - psi::Psi>* psi_laststep = nullptr; + psi::Psi> *psi_laststep = nullptr; //! Hamiltonian for all local k-points of the last electronic step. ct::Tensor Hk_laststep = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE); @@ -78,15 +92,15 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> int totstep = -1; //! Velocity matrix for calculating current - Velocity_op* velocity_mat = nullptr; + Velocity_op *velocity_mat = nullptr; //! Solver-owned TD context for field-dependent LCAO operators and observables. - TD_info* td_p = nullptr; + TD_info *td_p = nullptr; //! Moving spatial gauge for Ehrenfest dynamics, to calculate the correction term arising from the movement of basis bool use_td_moving_gauge = false; //! Moving-basis correction matrices, allocated when the moving spatial gauge is enabled. - module_rt::TD_MovingGauge* td_mg_ = nullptr; + module_rt::TD_MovingGauge *td_mg_ = nullptr; //! Whether the saved restart endpoint has been replayed to rebuild the electronic state. bool restart_done = false; @@ -99,7 +113,7 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> int restart_step_ = 0; //! Apply specified occupations and rebuild band energy, density matrices, and charge density. - void weight_dm_rho(const UnitCell& ucell); + void weight_dm_rho(const UnitCell &ucell); }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_ks_lcaopw.cpp b/source/source_esolver/esolver_ks_lcaopw.cpp index 5c6ba6e954..fa67f5cd24 100644 --- a/source/source_esolver/esolver_ks_lcaopw.cpp +++ b/source/source_esolver/esolver_ks_lcaopw.cpp @@ -1,6 +1,8 @@ #include "esolver_ks_lcaopw.h" -#include "source_pw/module_pwdft/elecond.h" + #include "source_io/module_parameter/input_conv.h" +#include "source_pw/module_pwdft/elecond.h" + #include //--------------temporary---------------------------- @@ -13,17 +15,17 @@ #include "source_pw/module_pwdft/stress_pw.h" //--------------------------------------------------- #include "source_base/global_variable.h" +#include "source_base/kernels/math_kernel_op.h" #include "source_base/parallel_comm.h" #include "source_estate/elecstate_pw.h" -#include "source_pw/module_pwdft/hamilt_lcaopw.h" -#include "source_pw/module_pwdft/hamilt_pw.h" +#include "source_hamilt/module_xc/xc_functional.h" #include "source_hsolver/diag_comm_info.h" #include "source_hsolver/diago_iter_assist.h" #include "source_hsolver/hsolver_lcaopw.h" #include "source_hsolver/kernels/hegvd_op.h" -#include "source_base/kernels/math_kernel_op.h" #include "source_io/module_parameter/parameter.h" -#include "source_hamilt/module_xc/xc_functional.h" +#include "source_pw/module_pwdft/hamilt_lcaopw.h" +#include "source_pw/module_pwdft/hamilt_pw.h" #include #include @@ -35,284 +37,305 @@ namespace ModuleESolver { - template - ESolver_KS_LIP::ESolver_KS_LIP() - { - this->classname = "ESolver_KS_LIP"; - this->basisname = "LIP"; - } - template - ESolver_KS_LIP::~ESolver_KS_LIP() +template ESolver_KS_LIP::ESolver_KS_LIP() +{ + this->classname = "ESolver_KS_LIP"; + this->basisname = "LIP"; +} +template ESolver_KS_LIP::~ESolver_KS_LIP() +{ + //**************************************************** + // do not add any codes in this deconstructor funcion + //**************************************************** + delete this->psi_local; + // delete Hamilt + if (this->p_hamilt != nullptr) { - //**************************************************** - // do not add any codes in this deconstructor funcion - //**************************************************** - delete this->psi_local; - // delete Hamilt - if (this->p_hamilt != nullptr) - { - delete this->p_hamilt; - this->p_hamilt = nullptr; - } + delete this->p_hamilt; + this->p_hamilt = nullptr; } +} - template - void ESolver_KS_LIP::allocate_hamilt(const UnitCell& ucell) - { - this->p_hamilt = new hamilt::HamiltLIP(this->pelec->pot, this->pw_wfc, &this->kv, &this->ppcell, &ucell +template void ESolver_KS_LIP::allocate_hamilt(const UnitCell &ucell) +{ + this->p_hamilt = new hamilt::HamiltLIP( + this->pelec->pot, + this->pw_wfc, + &this->kv, + &this->ppcell, + &ucell #ifdef __EXX - , *this->exx_lip + , + *this->exx_lip #endif - ); - } + ); +} + +template void ESolver_KS_LIP::before_scf(UnitCell &ucell, const int istep) +{ + ESolver_KS_PW::before_scf(ucell, istep); + auto *p_psi_init = static_cast *>(this->stp.p_psi_init); + p_psi_init->initialize_lcao_in_pw(this->psi_local, GlobalV::ofs_running); +} + +template void ESolver_KS_LIP::before_all_runners(BaseCell &basecell, const Input_para &inp) +{ + basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); + UnitCell &ucell = static_cast(basecell); + ESolver_KS_PW::before_all_runners(basecell, inp); - template - void ESolver_KS_LIP::before_scf(UnitCell& ucell, const int istep) + // Initialize LIP-specific info_lip_ from general_exx_info_ and input + this->info_lip_.ccp_type = this->general_exx_info_.ccp_type; + this->info_lip_.hse_omega = this->general_exx_info_.hse_omega; + if (!inp.exx_fock_lambda.empty()) { - ESolver_KS_PW::before_scf(ucell, istep); - auto* p_psi_init = static_cast*>(this->stp.p_psi_init); - p_psi_init->initialize_lcao_in_pw(this->psi_local, GlobalV::ofs_running); + this->info_lip_.lambda = std::stod(inp.exx_fock_lambda[0]); } - template - void ESolver_KS_LIP::before_all_runners(BaseCell& basecell, const Input_para& inp) + auto *p_psi_init = static_cast *>(this->stp.p_psi_init); + delete this->psi_local; + this->psi_local = new psi::Psi( + this->stp.psi_cpu->get_nk(), + p_psi_init->psi_initer->nbands_start(), + this->stp.psi_cpu->get_nbasis(), + this->kv.ngk, + true); +#ifdef __EXX + if (inp.calculation == "scf" || inp.calculation == "relax" || inp.calculation == "cell-relax" || + inp.calculation == "md") { - basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - ESolver_KS_PW::before_all_runners(basecell, inp); - - // Initialize LIP-specific info_lip_ from general_exx_info_ and input - this->info_lip_.ccp_type = this->general_exx_info_.ccp_type; - this->info_lip_.hse_omega = this->general_exx_info_.hse_omega; - if (!inp.exx_fock_lambda.empty()) + if (this->general_exx_info_.cal_exx) { - this->info_lip_.lambda = std::stod(inp.exx_fock_lambda[0]); + XC_Functional::set_xc_first_loop(ucell); + this->exx_lip = std::unique_ptr>(new Exx_Lip( + this->info_lip_, + &this->kv, + this->psi_local, + this->stp.template get_psi_t(), + this->pw_wfc, + this->pw_rho, + &ucell, + this->pelec)); } - - auto* p_psi_init = static_cast*>(this->stp.p_psi_init); - delete this->psi_local; - this->psi_local = new psi::Psi(this->stp.psi_cpu->get_nk(), - p_psi_init->psi_initer->nbands_start(), - this->stp.psi_cpu->get_nbasis(), - this->kv.ngk, - true); -#ifdef __EXX - if (inp.calculation == "scf" || inp.calculation == "relax" - || inp.calculation == "cell-relax" - || inp.calculation == "md") { - if (this->general_exx_info_.cal_exx) - { - XC_Functional::set_xc_first_loop(ucell); - this->exx_lip = std::unique_ptr>(new Exx_Lip(this->info_lip_, - &this->kv, - this->psi_local, - this->stp.template get_psi_t(), - this->pw_wfc, - this->pw_rho, - &ucell, - this->pelec)); - } -} -#endif } +#endif +} - template - void ESolver_KS_LIP::iter_init(UnitCell& ucell, const int istep, const int iter) - { - ESolver_KS_PW::iter_init(ucell, istep, iter); +template void ESolver_KS_LIP::iter_init(UnitCell &ucell, const int istep, const int iter) +{ + ESolver_KS_PW::iter_init(ucell, istep, iter); #ifdef __EXX - if (this->general_exx_info_.cal_exx && !this->general_exx_info_.separate_loop && this->two_level_step) { - this->exx_lip->cal_exx(); -} -#endif + if (this->general_exx_info_.cal_exx && !this->general_exx_info_.separate_loop && this->two_level_step) + { + this->exx_lip->cal_exx(); } +#endif +} - template - void ESolver_KS_LIP::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) - { - ModuleBase::TITLE("ESolver_KS_LIP", "hamilt2rho_single"); - ModuleBase::timer::start("ESolver_KS_LIP", "hamilt2rho_single"); +template +void ESolver_KS_LIP::hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) +{ + ModuleBase::TITLE("ESolver_KS_LIP", "hamilt2rho_single"); + ModuleBase::timer::start("ESolver_KS_LIP", "hamilt2rho_single"); - // reset energy - this->pelec->f_en.eband = 0.0; - this->pelec->f_en.demet = 0.0; - // choose if psi should be diag in subspace - // be careful that istep start from 0 and iter start from 1 - // if (iter == 1) - hsolver::DiagoIterAssist::need_subspace = ((istep == 0 || istep == 1) && iter == 1) ? false : true; - hsolver::DiagoIterAssist::SCF_ITER = iter; - hsolver::DiagoIterAssist::PW_DIAG_THR = ethr; - hsolver::DiagoIterAssist::PW_DIAG_NMAX = this->inp_->pw_diag_nmax; - bool skip_charge = this->inp_->calculation == "nscf" ? true : false; + // reset energy + this->pelec->f_en.eband = 0.0; + this->pelec->f_en.demet = 0.0; + // choose if psi should be diag in subspace + // be careful that istep start from 0 and iter start from 1 + // if (iter == 1) + hsolver::DiagoIterAssist::need_subspace = ((istep == 0 || istep == 1) && iter == 1) ? false : true; + hsolver::DiagoIterAssist::SCF_ITER = iter; + hsolver::DiagoIterAssist::PW_DIAG_THR = ethr; + hsolver::DiagoIterAssist::PW_DIAG_NMAX = this->inp_->pw_diag_nmax; + bool skip_charge = this->inp_->calculation == "nscf" ? true : false; - hsolver::HSolverLIP hsolver_lip_obj(this->pw_wfc, - PARAM.globalv.use_uspp, - this->inp_->basis_type, - this->inp_->calculation, - this->inp_->nbands); + hsolver::HSolverLIP hsolver_lip_obj( + this->pw_wfc, + PARAM.globalv.use_uspp, + this->inp_->basis_type, + this->inp_->calculation, + this->inp_->nbands); #ifdef __MPI - const hsolver::diag_comm_info diag_comm(POOL_WORLD, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL); + const hsolver::diag_comm_info diag_comm(POOL_WORLD, GlobalV::RANK_IN_POOL, GlobalV::NPROC_IN_POOL); #else - const hsolver::diag_comm_info diag_comm(0, 1); + const hsolver::diag_comm_info diag_comm(0, 1); #endif - // the solver sees the Hamiltonian only through this operator; the EXX - // subspace hooks live in the adapter, not in the solver - hamilt::HamiltLIPHSOperator op(dynamic_cast*>(this->p_hamilt), - this->pw_wfc, - this->general_exx_info_.cal_exx, - this->general_exx_info_.hybrid_alpha); - hsolver_lip_obj.solve(op, - *this->stp.template get_psi_t(), - this->pelec, - *this->psi_local, - diag_comm, - GlobalV::ofs_running, - skip_charge); + // the solver sees the Hamiltonian only through this operator; the EXX + // subspace hooks live in the adapter, not in the solver + hamilt::HamiltLIPHSOperator op( + dynamic_cast *>(this->p_hamilt), + this->pw_wfc, + this->general_exx_info_.cal_exx, + this->general_exx_info_.hybrid_alpha); + hsolver_lip_obj.solve( + op, + *this->stp.template get_psi_t(), + this->pelec, + *this->psi_local, + diag_comm, + GlobalV::ofs_running, + skip_charge); - // add exx + // add exx #ifdef __EXX - bool cal_exx = this->general_exx_info_.cal_exx; - double hybrid_alpha = this->general_exx_info_.hybrid_alpha; - if (cal_exx) - { - this->pelec->set_exx(this->exx_lip->get_exx_energy(), cal_exx, hybrid_alpha); // Peize Lin add 2019-03-09 - } + bool cal_exx = this->general_exx_info_.cal_exx; + double hybrid_alpha = this->general_exx_info_.hybrid_alpha; + if (cal_exx) + { + this->pelec->set_exx(this->exx_lip->get_exx_energy(), cal_exx, hybrid_alpha); // Peize Lin add 2019-03-09 + } #endif - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rhod, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rhod, + ucell.symm); - // deband is calculated from "output" charge density calculated - // in sum_band - // need 'rho(out)' and 'vr (v_h(in) and v_xc(in))' - this->pelec->f_en.deband = this->pelec->cal_delta_eband(ucell); + // deband is calculated from "output" charge density calculated + // in sum_band + // need 'rho(out)' and 'vr (v_h(in) and v_xc(in))' + this->pelec->f_en.deband = this->pelec->cal_delta_eband(ucell); - ModuleBase::timer::end("ESolver_KS_LIP", "hamilt2rho_single"); - } + ModuleBase::timer::end("ESolver_KS_LIP", "hamilt2rho_single"); +} - template - void ESolver_KS_LIP::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) - { - ESolver_KS_PW::iter_finish(ucell, istep, iter, conv_esolver); +template +void ESolver_KS_LIP::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) +{ + ESolver_KS_PW::iter_finish( + ucell, + istep, + iter, + conv_esolver); #ifdef __EXX - if (this->general_exx_info_.cal_exx && conv_esolver) - { - const int two_level_step_before = this->two_level_step; + if (this->general_exx_info_.cal_exx && conv_esolver) + { + const int two_level_step_before = this->two_level_step; - // no separate_loop case - if (!this->general_exx_info_.separate_loop) - { - this->general_exx_info_.hybrid_step = 1; + // no separate_loop case + if (!this->general_exx_info_.separate_loop) + { + this->general_exx_info_.hybrid_step = 1; - // in no_separate_loop case, scf loop only did twice - // in first scf loop, exx updated once in beginning, - // in second scf loop, exx updated every iter + // in no_separate_loop case, scf loop only did twice + // in first scf loop, exx updated once in beginning, + // in second scf loop, exx updated every iter - if (!this->two_level_step) - { - // update exx and redo scf - XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); - this->scf_rerun_ = true; - std::cout << " Entering 2nd SCF, where EXX is updated" << std::endl; - this->two_level_step++; - conv_esolver = false; - } - } - // has separate_loop case - // exx converged or get max exx steps - else if (this->two_level_step == this->general_exx_info_.hybrid_step - || (iter == 1 && this->two_level_step != 0)) - { - conv_esolver = true; - } - else + if (!this->two_level_step) { // update exx and redo scf - if (this->two_level_step == 0) - { - XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); - } - - std::cout << " Updating EXX " << std::flush; - timeval t_start; - gettimeofday(&t_start, nullptr); - - this->exx_lip->cal_exx(); + XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); this->scf_rerun_ = true; + std::cout << " Entering 2nd SCF, where EXX is updated" << std::endl; this->two_level_step++; - - timeval t_end; - gettimeofday(&t_end, nullptr); - std::cout << "and rerun SCF\t" << std::setprecision(3) << std::setiosflags(std::ios::scientific) - << (double)(t_end.tv_sec - t_start.tv_sec) - + (double)(t_end.tv_usec - t_start.tv_usec) / 1000000.0 - << std::defaultfloat << " (s)" << std::endl; conv_esolver = false; } - - // On the 0->1 transition, exx_after_converge switches the XC functional (PBE->hybrid), - // but v_eff was already set for this (converged) iteration under the OLD functional. - // Without this refresh, the 1st iteration of the EXX loop builds H from the stale GGA v_eff - // and then adds Hexx on top of it, double-counting exchange. - // Usually only that one iteration is affected and the loop washes it out; - // but when the 2nd loop converges immediately (density already exact, e.g. a minimal basis fixed by symmetry) - // the polluted H is the final one -- it gets diagonalized and written out by out_mat_hs. - // cal_converged() is used rather than a bare update_from_charge() so that vnew (used - // by force_scc) and descf stay consistent with the refreshed v_eff. - if (!conv_esolver && two_level_step_before == 0 && this->two_level_step == 1) + } + // has separate_loop case + // exx converged or get max exx steps + else if (this->two_level_step == this->general_exx_info_.hybrid_step || + (iter == 1 && this->two_level_step != 0)) + { + conv_esolver = true; + } + else + { + // update exx and redo scf + if (this->two_level_step == 0) { - this->pelec->cal_converged(); + XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); } + + std::cout << " Updating EXX " << std::flush; + timeval t_start; + gettimeofday(&t_start, nullptr); + + this->exx_lip->cal_exx(); + this->scf_rerun_ = true; + this->two_level_step++; + + timeval t_end; + gettimeofday(&t_end, nullptr); + std::cout << "and rerun SCF\t" << std::setprecision(3) << std::setiosflags(std::ios::scientific) + << (double)(t_end.tv_sec - t_start.tv_sec) + (double)(t_end.tv_usec - t_start.tv_usec) / 1000000.0 + << std::defaultfloat << " (s)" << std::endl; + conv_esolver = false; + } + + // On the 0->1 transition, exx_after_converge switches the XC functional (PBE->hybrid), + // but v_eff was already set for this (converged) iteration under the OLD functional. + // Without this refresh, the 1st iteration of the EXX loop builds H from the stale GGA v_eff + // and then adds Hexx on top of it, double-counting exchange. + // Usually only that one iteration is affected and the loop washes it out; + // but when the 2nd loop converges immediately (density already exact, e.g. a minimal basis fixed by symmetry) + // the polluted H is the final one -- it gets diagonalized and written out by out_mat_hs. + // cal_converged() is used rather than a bare update_from_charge() so that vnew (used + // by force_scc) and descf stay consistent with the refreshed v_eff. + if (!conv_esolver && two_level_step_before == 0 && this->two_level_step == 1) + { + this->pelec->cal_converged(); } -#endif } +#endif +} - template - void ESolver_KS_LIP::after_all_runners(BaseCell& basecell) - { - basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - ESolver_KS_PW::after_all_runners(basecell); +template void ESolver_KS_LIP::after_all_runners(BaseCell &basecell) +{ + basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); + UnitCell &ucell = static_cast(basecell); + ESolver_KS_PW::after_all_runners(basecell); #ifdef __LCAO - if (this->inp_->out_mat_xc) - { + if (this->inp_->out_mat_xc) + { #ifdef __EXX - bool cal_exx = this->general_exx_info_.cal_exx; - double hybrid_alpha = this->general_exx_info_.hybrid_alpha; + bool cal_exx = this->general_exx_info_.cal_exx; + double hybrid_alpha = this->general_exx_info_.hybrid_alpha; #else - bool cal_exx = false; - double hybrid_alpha = 0.0; + bool cal_exx = false; + double hybrid_alpha = 0.0; #endif - ModuleIO::write_Vxc_LIP(this->inp_->nspin, - PARAM.globalv.nlocal, - GlobalV::DRANK, - *this->stp.template get_psi_t(), - ucell, - this->sf, - this->solvent, - *this->pw_wfc, - *this->pw_rho, - *this->pw_rhod, - this->locpp.vloc, - this->chr, - this->kv, - this->pelec->wg, - PARAM.globalv.gamma_only_local, - PARAM.globalv.global_out_dir, - this->inp_->out_ndigits, - this->inp_->ks_solver, - cal_exx, - hybrid_alpha + ModuleIO::write_Vxc_LIP( + this->inp_->nspin, + PARAM.globalv.nlocal, + GlobalV::DRANK, + *this->stp.template get_psi_t(), + ucell, + this->sf, + this->solvent, + *this->pw_wfc, + *this->pw_rho, + *this->pw_rhod, + this->locpp.vloc, + this->chr, + this->kv, + this->pelec->wg, + PARAM.globalv.gamma_only_local, + PARAM.globalv.global_out_dir, + this->inp_->out_ndigits, + this->inp_->ks_solver, + cal_exx, + hybrid_alpha #ifdef __EXX - , - *this->exx_lip -#endif - ); - } + , + *this->exx_lip #endif + ); } - template class ESolver_KS_LIP>; - template class ESolver_KS_LIP>; - // LIP is not supported on GPU yet. +#endif +} +template class ESolver_KS_LIP>; +template class ESolver_KS_LIP>; +// LIP is not supported on GPU yet. } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_ks_lcaopw.h b/source/source_esolver/esolver_ks_lcaopw.h index 63dc3ed13c..da589d988c 100644 --- a/source/source_esolver/esolver_ks_lcaopw.h +++ b/source/source_esolver/esolver_ks_lcaopw.h @@ -1,8 +1,8 @@ #ifndef ESOLVER_KS_LIP_H #define ESOLVER_KS_LIP_H #include "source_esolver/esolver_ks_pw.h" -#include "source_hsolver/hsolver_lcaopw.h" #include "source_hamilt/module_xc/exx_info_lip.h" +#include "source_hsolver/hsolver_lcaopw.h" #ifdef __EXX #include "source_lcao/module_ri/exx_lip.h" @@ -10,8 +10,7 @@ namespace ModuleESolver { -template -class ESolver_KS_LIP : public ESolver_KS_PW +template class ESolver_KS_LIP : public ESolver_KS_PW { private: using Real = typename GetTypeReal::type; @@ -21,21 +20,29 @@ class ESolver_KS_LIP : public ESolver_KS_PW ~ESolver_KS_LIP(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; - void after_all_runners(BaseCell& basecell) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; + void after_all_runners(BaseCell &basecell) override; - virtual void before_scf(UnitCell& ucell, const int istep) override; + virtual void before_scf(UnitCell &ucell, const int istep) override; protected: - virtual void iter_init(UnitCell& ucell, const int istep, const int iter) override; - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + virtual void iter_init(UnitCell &ucell, const int istep, const int iter) override; + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; /// All the other interfaces except this one are the same as ESolver_KS_PW. - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; - virtual void allocate_hamilt(const UnitCell& ucell) override; + virtual void allocate_hamilt(const UnitCell &ucell) override; - psi::Psi* psi_local = nullptr; ///< psi for all local NAOs + psi::Psi *psi_local = nullptr; ///< psi for all local NAOs /// LIP-specific EXX info (lambda, ccp_type, hse_omega) Exx_Info_Lip info_lip_; diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index c700eefa05..ffbb4c1c9c 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -1,5 +1,4 @@ #include "esolver_ks_pw.h" -#include "source_pw/module_pwdft/pw_hybrid_nscf.h" #include "source_estate/elecstate_pw.h" #include "source_estate/module_charge/chg_symm.h" @@ -10,6 +9,7 @@ #include "source_io/module_parameter/parameter.h" #include "source_pw/module_pwdft/force_pw.h" #include "source_pw/module_pwdft/hamilt_pw.h" +#include "source_pw/module_pwdft/pw_hybrid_nscf.h" #include "source_pw/module_pwdft/stress_pw.h" #ifdef __DSP @@ -20,10 +20,10 @@ #include "source_estate/setup_estate_pw.h" // mohan add 20251005 #include "source_hamilt/module_xc/general_exx_info.h" // for General_Exx_Info type used via general_exx_info_ #include "source_io/module_ctrl/ctrl_output_pw.h" // mohan add 20250927 -#include "source_pw/module_pwdft/dftu_base.h" -#include "source_pw/module_pwdft/dftu_base_io.h" // append_ion_step_snapshot #include "source_lcao/module_deltaspin/spin_constrain.h" -#include "source_pw/module_pwdft/deltaspin_pw.h" // mohan add 20250309 +#include "source_pw/module_pwdft/deltaspin_pw.h" // mohan add 20250309 +#include "source_pw/module_pwdft/dftu_base.h" +#include "source_pw/module_pwdft/dftu_base_io.h" // append_ion_step_snapshot #include "source_pw/module_pwdft/setup_dftu_pw.h" // mohan add 20250309 #include "source_pw/module_pwdft/setup_pot.h" // mohan add 20250929 #include "source_pw/module_pwdft/update_cell_pw.h" // mohan add 20250309 @@ -31,8 +31,7 @@ namespace ModuleESolver { -template -ESolver_KS_PW::ESolver_KS_PW() +template ESolver_KS_PW::ESolver_KS_PW() { this->classname = "ESolver_KS_PW"; this->basisname = "PW"; @@ -40,8 +39,7 @@ ESolver_KS_PW::ESolver_KS_PW() this->dftu_.reset(new Plus_U_Base()); } -template -ESolver_KS_PW::~ESolver_KS_PW() +template ESolver_KS_PW::~ESolver_KS_PW() { //**************************************************** // do not add any codes in this deconstructor funcion @@ -64,65 +62,73 @@ ESolver_KS_PW::~ESolver_KS_PW() this->stp.clean(); } -template -void ESolver_KS_PW::allocate_hamilt(const UnitCell& ucell) +template void ESolver_KS_PW::allocate_hamilt(const UnitCell &ucell) { - this->p_hamilt = new hamilt::HamiltPW(this->pelec->pot, - this->pw_wfc, - &this->kv, - &this->ppcell, - this->dftu_.get(), - &ucell, - &this->general_exx_info_); + this->p_hamilt = new hamilt::HamiltPW( + this->pelec->pot, + this->pw_wfc, + &this->kv, + &this->ppcell, + this->dftu_.get(), + &ucell, + &this->general_exx_info_); } template -void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_KS_PW::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ESolver_KS::before_all_runners(ucell, inp); pw::validate_hybrid_nscf(inp, this->general_exx_info_); //! setup and allocation for pelec, potentials, etc. - elecstate::setup_estate_pw(ucell, - this->kv, - this->sf, - this->pelec, - this->chr, - this->locpp, - this->ppcell, - this->vsep_cell, - this->pw_wfc, - this->pw_rho, - this->pw_rhod, - this->pw_big, - this->solvent, - inp); + elecstate::setup_estate_pw( + ucell, + this->kv, + this->sf, + this->pelec, + this->chr, + this->locpp, + this->ppcell, + this->vsep_cell, + this->pw_wfc, + this->pw_rho, + this->pw_rhod, + this->pw_big, + this->solvent, + inp); if (inp.dft_plus_u) { - const System_para& sys = PARAM.globalv; - this->dftu_->init_base(ucell, - sys.npol, - inp.nspin, - inp.l_channel, - inp.yukawa_potential, - inp.yukawa_lambda, - sys.global_readin_dir, - sys.global_out_dir, - inp.init_chg, - inp.device, - sys.hubbard_u, - sys.uramping, - inp.init_occ_mat, - inp.mixing_dftu, - DFTU_BASE::SOC_LAYOUT_PAULI); + const System_para &sys = PARAM.globalv; + this->dftu_->init_base( + ucell, + sys.npol, + inp.nspin, + inp.l_channel, + inp.yukawa_potential, + inp.yukawa_lambda, + sys.global_readin_dir, + sys.global_out_dir, + inp.init_chg, + inp.device, + sys.hubbard_u, + sys.uramping, + inp.init_occ_mat, + inp.mixing_dftu, + DFTU_BASE::SOC_LAYOUT_PAULI); } - this->stp.before_runner(ucell, this->kv, this->sf, *this->pw_wfc, this->ppcell.lmaxkb, *this->inp_); + this->stp.before_runner( + ucell, + this->kv, + this->sf, + *this->pw_wfc, + this->ppcell.lmaxkb, + *this->inp_); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT BASIS"); @@ -156,11 +162,14 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu } //! Initialize exx pw - this->exx_helper->init(ucell, inp, this->pelec->wg, this->general_exx_info_); + this->exx_helper->init( + ucell, + inp, + this->pelec->wg, + this->general_exx_info_); } -template -void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) +template void ESolver_KS_PW::before_scf(UnitCell &ucell, const int istep) { ModuleBase::TITLE("ESolver_KS_PW", "before_scf"); ModuleBase::timer::start("ESolver_KS_PW", "before_scf"); @@ -168,7 +177,12 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) ESolver_KS::before_scf(ucell, istep); //! Init variables (once the cell has changed) - pw::update_cell_pw(ucell, this->ppcell, this->kv, this->pw_wfc, *this->inp_); + pw::update_cell_pw( + ucell, + this->ppcell, + this->kv, + this->pw_wfc, + *this->inp_); if (ucell.cell_parameter_updated) { @@ -188,30 +202,31 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) this->allocate_hamilt(ucell); //! Setup potentials (local, non-local, spin constraint, DFT-1/2) - psi::Psi, Device>* onsite_psi = nullptr; + psi::Psi, Device> *onsite_psi = nullptr; const bool spinor_rt = this->inp_->esolver_type == "tddft" && this->inp_->nspin == 4; if (this->inp_->onsite_radius > 0 && !spinor_rt) { this->stp.update_psi_d(); onsite_psi = this->stp.template get_psi_d(); } - pw::setup_pot(istep, - ucell, - this->kv, - this->sf, - this->pelec, - this->Pgrid, - this->chr, - this->locpp, - this->ppcell, - this->vsep_cell, - this->stp.template get_psi_t(), - onsite_psi, - this->p_hamilt, - this->pw_wfc, - this->pw_rhod, - PARAM.globalv.global_out_dir, - *this->inp_); + pw::setup_pot( + istep, + ucell, + this->kv, + this->sf, + this->pelec, + this->Pgrid, + this->chr, + this->locpp, + this->ppcell, + this->vsep_cell, + this->stp.template get_psi_t(), + onsite_psi, + this->p_hamilt, + this->pw_wfc, + this->pw_rhod, + PARAM.globalv.global_out_dir, + *this->inp_); // RT-TDDFT must bind the endpoint field before wavefunction initialization uses H. // This hook is a no-op for ordinary DFT. @@ -220,26 +235,32 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) this->stp.init(this->p_hamilt); //! Setup EXX helper for Hamiltonian and psi - exx_helper->before_scf(this->p_hamilt, this->stp.template get_psi_t(), *this->inp_, this->general_exx_info_); + exx_helper->before_scf( + this->p_hamilt, + this->stp.template get_psi_t(), + *this->inp_, + this->general_exx_info_); if (this->inp_->calculation == "nscf" && this->general_exx_info_.cal_exx) { - const Input_para& inp = *this->inp_; - const std::string& readin_dir = PARAM.globalv.global_readin_dir; - auto* helper = static_cast*>(this->exx_helper); - pw::prepare_exx_nscf(inp, ucell, this->pw_wfc, *helper->op_exx, readin_dir); + const Input_para &inp = *this->inp_; + const std::string &readin_dir = PARAM.globalv.global_readin_dir; + auto *helper = static_cast *>(this->exx_helper); + pw::prepare_exx_nscf( + inp, + ucell, + this->pw_wfc, + *helper->op_exx, + readin_dir); } ModuleBase::timer::end("ESolver_KS_PW", "before_scf"); } -template -void ESolver_KS_PW::prepare_init_hamilt(const UnitCell& ucell) -{ -} +template void ESolver_KS_PW::prepare_init_hamilt(const UnitCell &ucell) {} template -void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const int iter) +void ESolver_KS_PW::iter_init(UnitCell &ucell, const int istep, const int iter) { ESolver_KS::iter_init(ucell, istep, iter); @@ -247,12 +268,19 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const bool mag_converged = true; if (this->inp_->sc_mag_switch) { - spinconstrain::SpinConstrain>& sc = spinconstrain::SpinConstrain>::getScInstance(); + spinconstrain::SpinConstrain> &sc = + spinconstrain::SpinConstrain>::getScInstance(); mag_converged = sc.mag_converged(); } const int iter_limit = this->scf_iter_limit(istep); - module_charge::chgmixing_ks_pw(iter, iter_limit, this->p_chgmix, *this->dftu_, mag_converged, *this->inp_); + module_charge::chgmixing_ks_pw( + iter, + iter_limit, + this->p_chgmix, + *this->dftu_, + mag_converged, + *this->inp_); // mohan move harris functional here, 2012-06-05 // use 'rho(in)' and 'v_h and v_xc'(in) @@ -261,22 +289,23 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const // update local occupations for DFT+U // should before lambda loop in DeltaSpin const DFTU_BASE::OccmatOutputCfg init_occmat_cfg{this->inp_->out_freq_ion, - this->inp_->out_freq_elec, - iter_limit, - this->inp_->out_occ_mat, - this->inp_->dft_plus_u}; - DFTU_BASE::iter_init_dftu_pw(iter, - istep, - *this->dftu_, - this->stp.template get_psi_t(), - this->pelec->wg, - ucell, - this->p_chgmix, - PARAM.globalv.global_out_dir, - init_occmat_cfg, - this->kv.isk.data(), - this->inp_->nspin, - this->inp_->kpar); + this->inp_->out_freq_elec, + iter_limit, + this->inp_->out_occ_mat, + this->inp_->dft_plus_u}; + DFTU_BASE::iter_init_dftu_pw( + iter, + istep, + *this->dftu_, + this->stp.template get_psi_t(), + this->pelec->wg, + ucell, + this->p_chgmix, + PARAM.globalv.global_out_dir, + init_occmat_cfg, + this->kv.isk.data(), + this->inp_->nspin, + this->inp_->kpar); // mohan add 2025-11: push DFT+U energy from Plus_U instance to ElecState if (this->inp_->dft_plus_u) @@ -287,7 +316,11 @@ void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const // Temporary, it should be replaced by hsolver later. template -void ESolver_KS_PW::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) +void ESolver_KS_PW::hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) { ModuleBase::timer::start("ESolver_KS_PW", "hamilt2rho_single"); @@ -296,72 +329,96 @@ void ESolver_KS_PW::hamilt2rho_single(UnitCell& ucell, const int iste this->pelec->f_en.demet = 0.0; // setup diagonalization parameters - hsolver::setup_diago_params_pw(istep, iter, ethr, *this->inp_); + hsolver::setup_diago_params_pw( + istep, + iter, + ethr, + *this->inp_); bool skip_charge = this->inp_->calculation == "nscf" ? true : false; // run the inner lambda loop to contrain atomic moments with the DeltaSpin method - bool skip_solve = pw::run_deltaspin_lambda_loop(iter - 1, this->drho, *this->inp_, GlobalV::ofs_running); + bool skip_solve = pw::run_deltaspin_lambda_loop( + iter - 1, + this->drho, + *this->inp_, + GlobalV::ofs_running); if (skip_solve) { // Fetch the most recent DeltaSpin RMS for display in the SCF iteration table. - spinconstrain::SpinConstrain>& sc = spinconstrain::SpinConstrain>::getScInstance(); + spinconstrain::SpinConstrain> &sc = + spinconstrain::SpinConstrain>::getScInstance(); this->ds_rms_ = sc.get_last_rms_error(); } if (!skip_solve) { - hsolver::HSolverPW hsolver_pw_obj(this->pw_wfc, - this->inp_->calculation, - this->inp_->basis_type, - this->inp_->ks_solver, - PARAM.globalv.use_uspp, - this->inp_->nspin, - hsolver::DiagoIterAssist::SCF_ITER, - hsolver::DiagoIterAssist::PW_DIAG_NMAX, - hsolver::DiagoIterAssist::PW_DIAG_THR, - hsolver::DiagoIterAssist::need_subspace, - this->inp_->nbands, - this->inp_->diago_smooth_ethr, - this->inp_->pw_diag_ndim, - this->inp_->diag_subspace, - this->inp_->nb2d, - this->inp_->use_k_continuity); + hsolver::HSolverPW hsolver_pw_obj( + this->pw_wfc, + this->inp_->calculation, + this->inp_->basis_type, + this->inp_->ks_solver, + PARAM.globalv.use_uspp, + this->inp_->nspin, + hsolver::DiagoIterAssist::SCF_ITER, + hsolver::DiagoIterAssist::PW_DIAG_NMAX, + hsolver::DiagoIterAssist::PW_DIAG_THR, + hsolver::DiagoIterAssist::need_subspace, + this->inp_->nbands, + this->inp_->diago_smooth_ethr, + this->inp_->pw_diag_ndim, + this->inp_->diag_subspace, + this->inp_->nb2d, + this->inp_->use_k_continuity); // the iterative eigensolvers see the Hamiltonian only through this operator - hamilt::HamiltHSOperator op(static_cast*>(this->p_hamilt), this->pw_wfc); - hsolver_pw_obj.solve(op, - *this->stp.template get_psi_t(), - this->pelec, - this->pelec->ekb.c, - GlobalV::RANK_IN_POOL, - GlobalV::NPROC_IN_POOL, - GlobalV::ofs_running, - skip_charge); + hamilt::HamiltHSOperator op(static_cast *>(this->p_hamilt), this->pw_wfc); + hsolver_pw_obj.solve( + op, + *this->stp.template get_psi_t(), + this->pelec, + this->pelec->ekb.c, + GlobalV::RANK_IN_POOL, + GlobalV::NPROC_IN_POOL, + GlobalV::ofs_running, + skip_charge); } // symmetrize the charge density - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rhod, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rhod, + ucell.symm); ModuleBase::timer::end("ESolver_KS_PW", "hamilt2rho_single"); } template -void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) +void ESolver_KS_PW::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { // Related to EXX bool cal_exx = general_exx_info_.cal_exx; double hybrid_alpha = general_exx_info_.hybrid_alpha; if (cal_exx && this->inp_->calculation != "nscf" && !exx_helper->get_op_first_iter()) { - this->pelec->set_exx(exx_helper->cal_exx_energy(this->stp.template get_psi_t()), cal_exx, hybrid_alpha); + this->pelec->set_exx( + exx_helper->cal_exx_energy(this->stp.template get_psi_t()), cal_exx, hybrid_alpha); } // deband is calculated from "output" charge density this->pelec->f_en.deband = this->pelec->cal_delta_eband(ucell); // Call iter_finish() of ESolver_KS - ESolver_KS::iter_finish(ucell, istep, iter, conv_esolver); + ESolver_KS::iter_finish( + ucell, + istep, + iter, + conv_esolver); // D in USPP needs vloc, thus needs update when veff updated // calculate the effective coefficient matrix for non-local @@ -381,20 +438,25 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int // into the iter reference), which crashed DFT+U occupation-matrix writers // validating iter>=1 and broke the 1-based iteration invariant. const bool scf_converged = conv_esolver; - exx_helper->iter_finish(this->pelec, - &this->chr, - this->stp.template get_psi_t(), - ucell, - *this->inp_, - conv_esolver, - iter); + exx_helper->iter_finish( + this->pelec, + &this->chr, + this->stp.template get_psi_t(), + ucell, + *this->inp_, + conv_esolver, + iter); if (scf_converged && !conv_esolver) { this->scf_rerun_ = true; } // check if oscillate for delta_spin method - pw::check_deltaspin_oscillation(iter, this->drho, this->p_chgmix, *this->inp_); + pw::check_deltaspin_oscillation( + iter, + this->drho, + this->p_chgmix, + *this->inp_); // overwrite occ_mat.txt with the latest occupation matrix and the // actual charge-density residual of this electronic step. At the very @@ -403,26 +465,27 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int // keep the previous behavior where occ_mat.txt first appears at iter 2. const int iter_limit = this->scf_iter_limit(istep); const DFTU_BASE::OccmatOutputCfg occmat_cfg{this->inp_->out_freq_ion, - this->inp_->out_freq_elec, - iter_limit, - this->inp_->out_occ_mat, - this->inp_->dft_plus_u}; + this->inp_->out_freq_elec, + iter_limit, + this->inp_->out_occ_mat, + this->inp_->dft_plus_u}; const DFTU_BASE::OccmatStepInfo occmat_step{istep, - iter, - this->scf_thr, - this->drho}; + iter, + this->scf_thr, + this->drho}; // Read globalv values once into locals so the repeated DFT+U call sites // below do not each re-enter the global dependency surface. - const std::string& global_out_dir = PARAM.globalv.global_out_dir; + const std::string &global_out_dir = PARAM.globalv.global_out_dir; const bool latest_ready = (iter > 1 || istep > 0); if (latest_ready) { - DFTU_BASE::write_latest_occmat(*this->dftu_, - ucell, - global_out_dir, - occmat_step, - occmat_cfg, - DFTU_BASE::SOC_LAYOUT_PAULI); + DFTU_BASE::write_latest_occmat( + *this->dftu_, + ucell, + global_out_dir, + occmat_step, + occmat_cfg, + DFTU_BASE::SOC_LAYOUT_PAULI); } // append the current electronic-step section to occ_matg{#}.txt @@ -430,24 +493,34 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int // unless it was loaded from dm_onsite_ini.txt or a previous // occ_mat.txt; snapshot an "N/A" placeholder in that case. const bool occmat_ready = latest_ready || this->dftu_->is_occmat_ready(); - DFTU_BASE::append_ion_step_snapshot(*this->dftu_, - ucell, - global_out_dir, - occmat_step, - conv_esolver, - occmat_ready, - occmat_cfg, - DFTU_BASE::SOC_LAYOUT_PAULI); + DFTU_BASE::append_ion_step_snapshot( + *this->dftu_, + ucell, + global_out_dir, + occmat_step, + conv_esolver, + occmat_ready, + occmat_cfg, + DFTU_BASE::SOC_LAYOUT_PAULI); // the output quantities if (!this->defer_iter_output(istep)) { - ModuleIO::ctrl_iter_pw(istep, iter, conv_esolver, this->stp, this->kv, this->pw_wfc, *this->inp_, false, GlobalV::ofs_running); + ModuleIO::ctrl_iter_pw( + istep, + iter, + conv_esolver, + this->stp, + this->kv, + this->pw_wfc, + *this->inp_, + false, + GlobalV::ofs_running); } } template -void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_KS_PW::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_KS_PW", "after_scf"); ModuleBase::timer::start("ESolver_KS_PW", "after_scf"); @@ -455,43 +528,40 @@ void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const // Calculate kinetic energy density tau for ELF if needed if (this->inp_->out_elf[0] > 0) { - auto* elec_pw = static_cast*>(this->pelec); - auto& psi = *this->stp.template get_psi_t(); + auto *elec_pw = static_cast *>(this->pelec); + auto &psi = *this->stp.template get_psi_t(); elec_pw->cal_tau(psi); } ESolver_KS::after_scf(ucell, istep, conv_esolver); // Output quantities - ModuleIO::ctrl_scf_pw(istep, - ucell, - this->pelec, - this->chr, - this->ppcell, - this->kv, - this->pw_wfc, - this->pw_rho, - this->pw_rhod, - this->pw_big, - this->stp, - this->Pgrid, - *this->inp_, - GlobalV::ofs_running); + ModuleIO::ctrl_scf_pw( + istep, + ucell, + this->pelec, + this->chr, + this->ppcell, + this->kv, + this->pw_wfc, + this->pw_rho, + this->pw_rhod, + this->pw_big, + this->stp, + this->Pgrid, + *this->inp_, + GlobalV::ofs_running); ModuleBase::timer::end("ESolver_KS_PW", "after_scf"); } -template -double ESolver_KS_PW::cal_energy() -{ - return this->pelec->f_en.etot; -} +template double ESolver_KS_PW::cal_energy() { return this->pelec->f_en.etot; } template -void ESolver_KS_PW::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_KS_PW::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); Forces ff(ucell.nat); @@ -499,56 +569,58 @@ void ESolver_KS_PW::cal_force(BaseCell& basecell, ModuleBase::matrix& this->stp.update_psi_d(); // Calculate forces - ff.cal_force(this->inp_->nspin, - PARAM.globalv.domag, - PARAM.globalv.domag_z, - this->inp_->gga_grad, - this->inp_->dft_plus_u || this->inp_->sc_mag_switch, - ucell, - force, - this->get_vdw_result(), - *this->pelec, - this->pw_rhod, - &ucell.symm, - &this->sf, - this->solvent, - this->dftu_.get(), - &this->locpp, - &this->ppcell, - &this->kv, - this->pw_wfc, - this->stp.template get_psi_d()); + ff.cal_force( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + this->inp_->dft_plus_u || this->inp_->sc_mag_switch, + ucell, + force, + this->get_vdw_result(), + *this->pelec, + this->pw_rhod, + &ucell.symm, + &this->sf, + this->solvent, + this->dftu_.get(), + &this->locpp, + &this->ppcell, + &this->kv, + this->pw_wfc, + this->stp.template get_psi_d()); } template -void ESolver_KS_PW::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_KS_PW::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); Stress_PW ss(this->pelec); // mohan add 2025-10-12 this->stp.update_psi_d(); - ss.cal_stress(this->inp_->nspin, - PARAM.globalv.domag, - PARAM.globalv.domag_z, - this->inp_->gga_grad, - PARAM.globalv.gamma_only_pw, - stress, - ucell, - this->get_vdw_result(), - *this->dftu_, - this->locpp, - this->ppcell, - this->pw_rhod, - &ucell.symm, - &this->sf, - &this->kv, - this->pw_wfc, - this->general_exx_info_, - this->stp.template get_psi_d()); + ss.cal_stress( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + PARAM.globalv.gamma_only_pw, + stress, + ucell, + this->get_vdw_result(), + *this->dftu_, + this->locpp, + this->ppcell, + this->pw_rhod, + &ucell.symm, + &this->sf, + &this->kv, + this->pw_wfc, + this->general_exx_info_, + this->stp.template get_psi_d()); // external stress double unit_transform = 0.0; @@ -560,28 +632,28 @@ void ESolver_KS_PW::cal_stress(BaseCell& basecell, ModuleBase::matrix } } -template -void ESolver_KS_PW::after_all_runners(BaseCell& basecell) +template void ESolver_KS_PW::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ESolver_KS::after_all_runners(ucell); - ModuleIO::ctrl_runner_pw(ucell, - this->pelec, - this->pw_wfc, - this->pw_rho, - this->pw_rhod, - this->chr, - this->kv, - this->stp, - this->sf, - this->ppcell, - this->solvent, - this->Pgrid, - *this->inp_, - GlobalV::ofs_running); + ModuleIO::ctrl_runner_pw( + ucell, + this->pelec, + this->pw_wfc, + this->pw_rho, + this->pw_rhod, + this->chr, + this->kv, + this->stp, + this->sf, + this->ppcell, + this->solvent, + this->Pgrid, + *this->inp_, + GlobalV::ofs_running); elecstate::teardown_estate_pw(this->pelec, this->vsep_cell); } diff --git a/source/source_esolver/esolver_ks_pw.h b/source/source_esolver/esolver_ks_pw.h index a03e73c943..b8e646b289 100644 --- a/source/source_esolver/esolver_ks_pw.h +++ b/source/source_esolver/esolver_ks_pw.h @@ -11,8 +11,7 @@ namespace ModuleESolver { -template -class ESolver_KS_PW : public ESolver_KS +template class ESolver_KS_PW : public ESolver_KS { private: using Real = typename GetTypeReal::type; @@ -22,41 +21,50 @@ class ESolver_KS_PW : public ESolver_KS ~ESolver_KS_PW(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; double cal_energy() override; - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; - Exx_HelperBase* exx_helper = nullptr; + Exx_HelperBase *exx_helper = nullptr; protected: - virtual void before_scf(UnitCell& ucell, const int istep) override; + virtual void before_scf(UnitCell &ucell, const int istep) override; - virtual void iter_init(UnitCell& ucell, const int istep, const int iter) override; + virtual void iter_init(UnitCell &ucell, const int istep, const int iter) override; - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; - virtual void others(BaseCell& basecell, const int istep) override; + virtual void others(BaseCell &basecell, const int istep) override; - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; - virtual void allocate_hamilt(const UnitCell& ucell); + virtual void allocate_hamilt(const UnitCell &ucell); - /** @brief Let RT-TDDFT bind its endpoint field before wavefunction initialization uses H; ordinary DFT does nothing. */ - virtual void prepare_init_hamilt(const UnitCell& ucell); + /** @brief Let RT-TDDFT bind its endpoint field before wavefunction initialization uses H; ordinary DFT does + * nothing. */ + virtual void prepare_init_hamilt(const UnitCell &ucell); // Electronic wave function psi Setup_Psi_pw stp; // DFT-1/2 method - VSep* vsep_cell = nullptr; + VSep *vsep_cell = nullptr; }; } // namespace ModuleESolver #endif diff --git a/source/source_esolver/esolver_ks_pw_tddft.cpp b/source/source_esolver/esolver_ks_pw_tddft.cpp index cec0c4f8e1..6cd770d137 100644 --- a/source/source_esolver/esolver_ks_pw_tddft.cpp +++ b/source/source_esolver/esolver_ks_pw_tddft.cpp @@ -40,21 +40,22 @@ ESolver_KS_PW_TDDFT::ESolver_KS_PW_TDDFT() : log_(GlobalV::ofs_runnin } template -void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); - const std::string& output_dir = PARAM.globalv.global_out_dir; + UnitCell &ucell = static_cast(basecell); + const std::string &output_dir = PARAM.globalv.global_out_dir; this->td_field_manager_ = elecstate::create_td_field_manager(inp); if (inp.td_max_halvings > 0) { const int parts = 1 << inp.td_max_halvings; - for (const elecstate::TDField& field: this->td_field_manager_->fields()) + for (const elecstate::TDField &field : this->td_field_manager_->fields()) { if (field.subdivisions() > std::numeric_limits::max() / parts) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", "td_max_halvings exceeds the field sampling integer range."); + ModuleBase::WARNING_QUIT( + "ESolver_KS_PW_TDDFT", "td_max_halvings exceeds the field sampling integer range."); } } } @@ -69,25 +70,34 @@ void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell& basecell, cons // The parent resolves the XC functional, including pseudopotential defaults. const int xc_type = XC_Functional::get_func_type(); - pw::check_td_input(inp, ucell, xc_type, this->general_exx_info_.cal_exx); + pw::check_td_input( + inp, + ucell, + xc_type, + this->general_exx_info_.cal_exx); current_req_.charge_total = inp.out_current == 1; current_req_.charge_per_k = current_req_.charge_total && inp.out_current_k; current_req_.spin_current = inp.nspin == 4 && inp.td_out_spincur; - vel_.initialize(ucell, *this->pw_wfc, this->kv, this->ppcell); + vel_.initialize( + ucell, + *this->pw_wfc, + this->kv, + this->ppcell); if (inp.nspin == 4) { - spin_.initialize(ucell, - *this->pw_rhod, - *this->pw_wfc, - this->kv, - this->sf, - this->ppcell, - inp.td_out_mag, - inp.orbital_dir, - inp.onsite_radius, - inp.td_out_torque); + spin_.initialize( + ucell, + *this->pw_rhod, + *this->pw_wfc, + this->kv, + this->sf, + this->ppcell, + inp.td_out_mag, + inp.orbital_dir, + inp.onsite_radius, + inp.td_out_torque); } this->pelec->pot->set_td_field_manager(this->td_field_manager_); @@ -97,7 +107,13 @@ void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell& basecell, cons const hsolver::diag_comm_info comm(0, 1); #endif const int npol = ucell.get_npol(); - this->td_prop_ = pw::make_td_prop(*this->pw_wfc, inp, npol, this->kv.ik2iktot, comm, log_); + this->td_prop_ = pw::make_td_prop( + *this->pw_wfc, + inp, + npol, + this->kv.ik2iktot, + comm, + log_); this->history_.prepare(*this->pelec->pot); // Preserve existing field history until input validation and initialization succeed. @@ -119,8 +135,7 @@ void ESolver_KS_PW_TDDFT::before_all_runners(BaseCell& basecell, cons } } -template -void ESolver_KS_PW_TDDFT::runner(BaseCell& basecell, const int istep) +template void ESolver_KS_PW_TDDFT::runner(BaseCell &basecell, const int istep) { const int steps_per_md = this->inp_->estep_per_md; int first_step = 0; @@ -141,7 +156,7 @@ void ESolver_KS_PW_TDDFT::runner(BaseCell& basecell, const int istep) if (electronic_step > 0) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& cell = static_cast(basecell); + UnitCell &cell = static_cast(basecell); this->run_prop(cell, electronic_step); } else @@ -151,32 +166,35 @@ void ESolver_KS_PW_TDDFT::runner(BaseCell& basecell, const int istep) } } -template -bool ESolver_KS_PW_TDDFT::defer_iter_output(const int istep) const +template bool ESolver_KS_PW_TDDFT::defer_iter_output(const int istep) const { return istep > 0; } -template -int ESolver_KS_PW_TDDFT::scf_iter_limit(const int istep) const +template int ESolver_KS_PW_TDDFT::scf_iter_limit(const int istep) const { return istep > 0 ? this->inp_->td_scf_nmax : this->inp_->scf_nmax; } template -bool ESolver_KS_PW_TDDFT::advance_interval(UnitCell& cell, - int step, - int index, - int depth, - const elecstate::TDFieldState& full, - pw::TDElecSnap& accepted, - hsolver::TDOrthStats& stats) +bool ESolver_KS_PW_TDDFT::advance_interval( + UnitCell &cell, + int step, + int index, + int depth, + const elecstate::TDFieldState &full, + pw::TDElecSnap &accepted, + hsolver::TDOrthStats &stats) { const int parts = 1 << depth; if (depth > 0) { *this->stp.template get_psi_t() = this->history_.previous(); - pw::restore_td(accepted, this->pelec->f_en, this->pelec->ekb, this->chr); + pw::restore_td( + accepted, + this->pelec->f_en, + this->pelec->ekb, + this->chr); this->pelec->vnew_exist = false; this->td_prop_->invalidate_basis(); this->td_prop_->orbitals().reset_orth_stats(); @@ -193,7 +211,8 @@ bool ESolver_KS_PW_TDDFT::advance_interval(UnitCell& cell, const double left_time = (step - 1 + static_cast(index) / parts) * full.dt * ModuleBase::AU_to_FS; const double right_time = (step - 1 + static_cast(index + 1) / parts) * full.dt * ModuleBase::AU_to_FS; const std::streamsize precision = log_.precision(); - log_ << " TD trial: [" << std::setprecision(12) << left_time << ", " << right_time << "] fs, depth=" << depth << '\n'; + log_ << " TD trial: [" << std::setprecision(12) << left_time << ", " << right_time << "] fs, depth=" << depth + << '\n'; log_.precision(precision); std::ostringstream interval; @@ -213,45 +232,61 @@ bool ESolver_KS_PW_TDDFT::advance_interval(UnitCell& cell, << ", accepted=" << accept_trial << '\n'; if (!converged && depth < this->inp_->td_max_halvings) { - std::cout << " TD retry: SCF not converged; splitting " << interval_text << " into two half steps." << std::endl; + std::cout << " TD retry: SCF not converged; splitting " << interval_text << " into two half steps." + << std::endl; this->td_prop_->discard_trial(); const int next_depth = depth + 1; const int left_index = 2 * index; const int right_index = left_index + 1; - const bool left_converged = advance_interval(cell, step, left_index, next_depth, full, accepted, stats); - const bool right_converged = advance_interval(cell, step, right_index, next_depth, full, accepted, stats); + const bool left_converged = advance_interval( + cell, + step, + left_index, + next_depth, + full, + accepted, + stats); + const bool right_converged = advance_interval( + cell, + step, + right_index, + next_depth, + full, + accepted, + stats); return left_converged && right_converged; } if (!converged) { - psi::Psi& current = *this->stp.template get_psi_t(); - elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); - hamilt::HamiltPW& hamilt = *static_cast*>(this->p_hamilt); - const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); - pw::rebuild_td_end(current, - estate, - this->chr, - cell, - hamilt, - this->td_prop_->orbitals(), - *this->pw_wfc, - *this->pw_rhod, - vecpot, - this->inp_->nspin, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + psi::Psi ¤t = *this->stp.template get_psi_t(); + elecstate::ElecStatePW &estate = *static_cast *>(this->pelec); + hamilt::HamiltPW &hamilt = *static_cast *>(this->p_hamilt); + const ModuleBase::Vector3 &vecpot = this->td_field_manager_->A_right_ha(); + pw::rebuild_td_end( + current, + estate, + this->chr, + cell, + hamilt, + this->td_prop_->orbitals(), + *this->pw_wfc, + *this->pw_rhod, + vecpot, + this->inp_->nspin, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); } - const hsolver::TDOrthStats& trial_stats = this->td_prop_->orbitals().orth_stats(); + const hsolver::TDOrthStats &trial_stats = this->td_prop_->orbitals().orth_stats(); stats.before = std::max(stats.before, trial_stats.before); stats.after = std::max(stats.after, trial_stats.after); - const psi::Psi* current = this->stp.template get_psi_t(); + const psi::Psi *current = this->stp.template get_psi_t(); this->history_.save(*current, *this->pelec->pot); this->td_prop_->finish_trial(); if (this->inp_->td_max_halvings > 0) @@ -262,8 +297,7 @@ bool ESolver_KS_PW_TDDFT::advance_interval(UnitCell& cell, return converged; } -template -void ESolver_KS_PW_TDDFT::run_prop(UnitCell& cell, int step) +template void ESolver_KS_PW_TDDFT::run_prop(UnitCell &cell, int step) { ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "run_prop"); const ModuleBase::TimePoint started = ModuleBase::get_time(); @@ -279,33 +313,50 @@ void ESolver_KS_PW_TDDFT::run_prop(UnitCell& cell, int step) const elecstate::TDFieldState full = this->td_field_manager_->field_state(); hsolver::TDOrthStats stats; - const bool converged = advance_interval(cell, step, 0, 0, full, accepted, stats); + const bool converged = advance_interval( + cell, + step, + 0, + 0, + full, + accepted, + stats); // Restore original-grid sampling metadata without altering the accepted endpoint. this->td_field_manager_->bind_field(full); this->td_prop_->orbitals().set_orth_stats(stats); this->chr.save_rho_before_sum_band(); - const System_para& system = PARAM.globalv; + const System_para &system = PARAM.globalv; const bool write_restart = this->inp_->out_chg[0] != -1; const std::string prefix = system.global_out_dir + this->inp_->suffix; const bool write_tau = XC_Functional::get_ked_flag(); const bool writer_pool = GlobalV::MY_POOL == 0; const Parallel::ParaWorld pw_world = Parallel::make_pw_world(); - module_charge::write_density_restart(this->chr, - *this->pw_rhod, - cell.GT, - prefix, - this->inp_->nspin, - write_restart, - system.gamma_only_pw, - write_tau, - writer_pool, - pw_world, - &GlobalV::ofs_warning); + module_charge::write_density_restart( + this->chr, + *this->pw_rhod, + cell.GT, + prefix, + this->inp_->nspin, + write_restart, + system.gamma_only_pw, + write_tau, + writer_pool, + pw_world, + &GlobalV::ofs_warning); this->write_iter_bands(); - ModuleIO::ctrl_iter_pw(step, this->niter, converged, this->stp, this->kv, this->pw_wfc, *this->inp_, true, log_); + ModuleIO::ctrl_iter_pw( + step, + this->niter, + converged, + this->stp, + this->kv, + this->pw_wfc, + *this->inp_, + true, + log_); const double duration = ModuleBase::get_duration(started, ModuleBase::get_time()); this->record_iteration(cell, duration); @@ -318,8 +369,7 @@ void ESolver_KS_PW_TDDFT::run_prop(UnitCell& cell, int step) ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "run_prop"); } -template -void ESolver_KS_PW_TDDFT::print_step(const int istep) const +template void ESolver_KS_PW_TDDFT::print_step(const int istep) const { const int evolution_step = istep + 1; std::cout << " -------------------------------------------" << std::endl; @@ -327,8 +377,7 @@ void ESolver_KS_PW_TDDFT::print_step(const int istep) const std::cout << " -------------------------------------------" << std::endl; } -template -void ESolver_KS_PW_TDDFT::before_scf(UnitCell& ucell, const int istep) +template void ESolver_KS_PW_TDDFT::before_scf(UnitCell &ucell, const int istep) { this->print_step(istep); this->prep_td_step(istep); @@ -344,27 +393,30 @@ void ESolver_KS_PW_TDDFT::before_scf(UnitCell& ucell, const int istep this->history_.prepare(*this->pelec->pot); } -template -void ESolver_KS_PW_TDDFT::prepare_init_hamilt(const UnitCell& ucell) +template void ESolver_KS_PW_TDDFT::prepare_init_hamilt(const UnitCell &ucell) { if (this->td_field_manager_->gauge() == 1) { // Both endpoints also bound any interpolated sample inside the interval. const double q_unshifted = pw::td_momentum_bound(*this->pw_wfc, ucell.tpiba); - const ModuleBase::Vector3& left = this->td_field_manager_->A_left_ha(); - const ModuleBase::Vector3& right = this->td_field_manager_->A_right_ha(); - pw::ensure_td_vnl(ucell, q_unshifted, right, left, &this->ppcell); - - elecstate::Potential& potential = *this->pelec->pot; - const Real* veff = potential.template get_veff_smooth_data(); - auto* hamiltonian = static_cast*>(this->p_hamilt); + const ModuleBase::Vector3 &left = this->td_field_manager_->A_left_ha(); + const ModuleBase::Vector3 &right = this->td_field_manager_->A_right_ha(); + pw::ensure_td_vnl( + ucell, + q_unshifted, + right, + left, + &this->ppcell); + + elecstate::Potential &potential = *this->pelec->pot; + const Real *veff = potential.template get_veff_smooth_data(); + auto *hamiltonian = static_cast *>(this->p_hamilt); // A file can supply nonzero A(0), which must enter H before the initial wavefunctions are prepared. hamiltonian->bind_td_state(veff, this->td_field_manager_->A_right_ha()); } } -template -void ESolver_KS_PW_TDDFT::prep_td_step(const int istep) +template void ESolver_KS_PW_TDDFT::prep_td_step(const int istep) { ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "prep_td_step"); @@ -386,7 +438,7 @@ void ESolver_KS_PW_TDDFT::prep_td_step(const int istep) if (this->td_field_manager_->gauge() == 1) { - const ModuleBase::Vector3& A_right_ha = this->td_field_manager_->A_right_ha(); + const ModuleBase::Vector3 &A_right_ha = this->td_field_manager_->A_right_ha(); ModuleBase::GlobalFunc::OUT(log_, "Cartesian vector potential Ax(t)", A_right_ha[0]); ModuleBase::GlobalFunc::OUT(log_, "Cartesian vector potential Ay(t)", A_right_ha[1]); ModuleBase::GlobalFunc::OUT(log_, "Cartesian vector potential Az(t)", A_right_ha[2]); @@ -400,8 +452,7 @@ void ESolver_KS_PW_TDDFT::prep_td_step(const int istep) ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "prep_td_step"); } -template -void ESolver_KS_PW_TDDFT::output_field(int istep) const +template void ESolver_KS_PW_TDDFT::output_field(int istep) const { if (GlobalV::MY_RANK == 0) { @@ -416,8 +467,7 @@ void ESolver_KS_PW_TDDFT::output_field(int istep) const } } -template -std::string ESolver_KS_PW_TDDFT::diag_policy(const int istep) const +template std::string ESolver_KS_PW_TDDFT::diag_policy(const int istep) const { if (istep == 0) { @@ -427,14 +477,19 @@ std::string ESolver_KS_PW_TDDFT::diag_policy(const int istep) const } template -void ESolver_KS_PW_TDDFT::iter_init(UnitCell& ucell, const int istep, const int iter) +void ESolver_KS_PW_TDDFT::iter_init(UnitCell &ucell, const int istep, const int iter) { int ionic_step = 0; if (this->inp_->mdp.md_nstep > 1 && istep > 0) { ionic_step = (istep - 1) / this->inp_->estep_per_md + 1; } - ModuleIO::write_head_td(GlobalV::ofs_running, ionic_step, istep, iter, this->basisname); + ModuleIO::write_head_td( + GlobalV::ofs_running, + ionic_step, + istep, + iter, + this->basisname); ESolver_KS_PW::iter_init(ucell, istep, iter); } @@ -449,48 +504,69 @@ ESolver_KS::DensityStage ESolver_KS_PW_TDDFT::density_stage(const int } template -void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) +void ESolver_KS_PW_TDDFT::hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) { ModuleBase::timer::start("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); if (istep == 0) { - ESolver_KS_PW::hamilt2rho_single(ucell, istep, iter, ethr); - - psi::Psi& current = *this->stp.template get_psi_t(); - elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); - hamilt::Hamilt* hamilt = static_cast*>(this->p_hamilt); + ESolver_KS_PW::hamilt2rho_single( + ucell, + istep, + iter, + ethr); + + psi::Psi ¤t = *this->stp.template get_psi_t(); + elecstate::ElecStatePW &estate = *static_cast *>(this->pelec); + hamilt::Hamilt *hamilt = static_cast *>(this->p_hamilt); hamilt::HamiltHSOperator op(hamilt, this->pw_wfc); const bool do_orth = this->inp_->td_orthonormal != "none"; - pw::orth_init_pw(this->td_prop_->orbitals(), - op, - current, - estate, - this->chr, - ucell, - *this->pw_rhod, - this->inp_->nspin, - this->inp_->nbands, - iter, - do_orth); + pw::orth_init_pw( + this->td_prop_->orbitals(), + op, + current, + estate, + this->chr, + ucell, + *this->pw_rhod, + this->inp_->nspin, + this->inp_->nbands, + iter, + do_orth); ModuleBase::timer::end("ESolver_KS_PW_TDDFT", "hamilt2rho_single"); return; } ModuleBase::TITLE("ESolver_KS_PW_TDDFT", "hamilt2rho_single (RT-TDDFT)"); - psi::Psi* current = this->stp.template get_psi_t(); - elecstate::Potential& potential = *this->pelec->pot; - hamilt::HamiltPW* hamiltonian = static_cast*>(this->p_hamilt); + psi::Psi *current = this->stp.template get_psi_t(); + elecstate::Potential &potential = *this->pelec->pot; + hamilt::HamiltPW *hamiltonian = static_cast *>(this->p_hamilt); hamilt::HamiltHSOperator op(hamiltonian, this->pw_wfc); const bool detailed = this->inp_->out_level == "ie"; - this->td_prop_->evolve(*hamiltonian, potential, this->history_, *this->td_field_manager_, current, istep, iter, detailed); - - elecstate::ElecStatePW* estate = static_cast*>(this->pelec); + this->td_prop_->evolve( + *hamiltonian, + potential, + this->history_, + *this->td_field_manager_, + current, + istep, + iter, + detailed); + + elecstate::ElecStatePW *estate = static_cast *>(this->pelec); // Propagation keeps the occupations of the initial state fixed. estate->psiToRho(*current); - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rhod, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rhod, + ucell.symm); // Pair the band sum with KS double-counting terms using this same potential. // The later KS potential update belongs to the next SCF iteration. @@ -501,52 +577,54 @@ void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const in } template -void ESolver_KS_PW_TDDFT::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_KS_PW_TDDFT::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { if (istep == 0 && this->inp_->td_orthonormal == "none") { - const psi::Psi* current = this->stp.template get_psi_t(); + const psi::Psi *current = this->stp.template get_psi_t(); this->td_prop_->orbitals().check_initial(*current, this->niter); } if (!conv_esolver && istep == 0) { - psi::Psi& current = *this->stp.template get_psi_t(); - elecstate::ElecStatePW& estate = *static_cast*>(this->pelec); - hamilt::HamiltPW& hamilt = *static_cast*>(this->p_hamilt); - const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); - pw::rebuild_td_end(current, - estate, - this->chr, - ucell, - hamilt, - this->td_prop_->orbitals(), - *this->pw_wfc, - *this->pw_rhod, - vecpot, - this->inp_->nspin, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + psi::Psi ¤t = *this->stp.template get_psi_t(); + elecstate::ElecStatePW &estate = *static_cast *>(this->pelec); + hamilt::HamiltPW &hamilt = *static_cast *>(this->p_hamilt); + const ModuleBase::Vector3 &vecpot = this->td_field_manager_->A_right_ha(); + pw::rebuild_td_end( + current, + estate, + this->chr, + ucell, + hamilt, + this->td_prop_->orbitals(), + *this->pw_wfc, + *this->pw_rhod, + vecpot, + this->inp_->nspin, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); } // Endpoint diagnostics use the accepted endpoint, not the propagation midpoint or a mixed trial density. - hamilt::HamiltPW* endpoint_hamilt = static_cast*>(this->p_hamilt); - const Real* endpoint_veff = this->pelec->pot->template get_veff_smooth_data(); + hamilt::HamiltPW *endpoint_hamilt = static_cast *>(this->p_hamilt); + const Real *endpoint_veff = this->pelec->pot->template get_veff_smooth_data(); endpoint_hamilt->bind_td_state(endpoint_veff, this->td_field_manager_->A_right_ha()); if (this->inp_->td_print_eij >= 0.0) { - psi::Psi& current = *this->stp.template get_psi_t(); + psi::Psi ¤t = *this->stp.template get_psi_t(); hamilt::HamiltHSOperator op(endpoint_hamilt, this->pw_wfc); - ModuleIO::print_eij_pw(op, - this->td_prop_->orbitals(), - current, - this->kv, - this->inp_->nspin, - istep, - this->niter, - this->inp_->td_print_eij, - log_); + ModuleIO::print_eij_pw( + op, + this->td_prop_->orbitals(), + current, + this->kv, + this->inp_->nspin, + istep, + this->niter, + this->inp_->td_print_eij, + log_); } ESolver_KS_PW::after_scf(ucell, istep, conv_esolver); @@ -560,13 +638,17 @@ void ESolver_KS_PW_TDDFT::after_scf(UnitCell& ucell, const int istep, // Propagation intervals already saved their accepted endpoint before reaching this hook. if (istep == 0) { - psi::Psi* current = this->stp.template get_psi_t(); + psi::Psi *current = this->stp.template get_psi_t(); this->history_.save(*current, *this->pelec->pot); } - const psi::Psi& current = *this->stp.template get_psi_t(); - const ModuleBase::Vector3& vecpot = this->td_field_manager_->A_right_ha(); - const pw::TDVelResultPW currents = vel_.calculate(current, *this->pelec, vecpot, current_req_); + const psi::Psi ¤t = *this->stp.template get_psi_t(); + const ModuleBase::Vector3 &vecpot = this->td_field_manager_->A_right_ha(); + const pw::TDVelResultPW currents = vel_.calculate( + current, + *this->pelec, + vecpot, + current_req_); pw::TDSpinResultPW moments; if (this->inp_->nspin == 4 && (this->inp_->td_out_mag != "none" || this->inp_->td_out_torque)) @@ -576,42 +658,50 @@ void ESolver_KS_PW_TDDFT::after_scf(UnitCell& ucell, const int istep, const double dt_ha = this->td_field_manager_->dt_ha(); const int nkstot = this->kv.get_nkstot(); - ModuleIO::ctrl_output_td_pw(currents, - moments, - current_req_, - this->inp_->td_out_mag, - this->inp_->orbital_dir, - this->inp_->onsite_radius, - this->inp_->td_out_torque, - ucell.orbital_fn, - istep, - dt_ha, - this->inp_->nspin, - nkstot, - GlobalV::MY_RANK, - PARAM.globalv.global_out_dir, - log_); + ModuleIO::ctrl_output_td_pw( + currents, + moments, + current_req_, + this->inp_->td_out_mag, + this->inp_->orbital_dir, + this->inp_->onsite_radius, + this->inp_->td_out_torque, + ucell.orbital_fn, + istep, + dt_ha, + this->inp_->nspin, + nkstot, + GlobalV::MY_RANK, + PARAM.globalv.global_out_dir, + log_); } if (this->inp_->td_out_stat) { const double local_npsi = this->td_prop_->orbitals().wave_electrons(this->pelec->wg); - const hsolver::TDOrthStats& stats = this->td_prop_->orbitals().orth_stats(); + const hsolver::TDOrthStats &stats = this->td_prop_->orbitals().orth_stats(); const bool full_gram = this->inp_->td_orthonormal != "none"; - const pw::TDConserv values - = pw::cal_td_conserv(local_npsi, this->chr, ucell.omega, this->pw_wfc->poolrank, stats.before, stats.after, full_gram); + const pw::TDConserv values = pw::cal_td_conserv( + local_npsi, + this->chr, + ucell.omega, + this->pw_wfc->poolrank, + stats.before, + stats.after, + full_gram); if (istep == 0) { initial_wave_electrons_ = values.npsi; initial_rho_electrons_ = values.nrho; } - ModuleIO::print_conserv(values, - initial_wave_electrons_, - initial_rho_electrons_, - istep, - full_gram, - this->inp_->td_orthonormal, - log_); + ModuleIO::print_conserv( + values, + initial_wave_electrons_, + initial_rho_electrons_, + istep, + full_gram, + this->inp_->td_orthonormal, + log_); } } diff --git a/source/source_esolver/esolver_ks_pw_tddft.h b/source/source_esolver/esolver_ks_pw_tddft.h index cd7af6fcfd..fc9a9ff92f 100644 --- a/source/source_esolver/esolver_ks_pw_tddft.h +++ b/source/source_esolver/esolver_ks_pw_tddft.h @@ -22,10 +22,10 @@ class ESolver_KS_PW_TDDFT : public ESolver_KS_PW ~ESolver_KS_PW_TDDFT() override = default; /** @brief Initialize the field, propagation solver and time-step history. */ - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; /** @brief Run the electronic steps belonging to the current MD step. */ - void runner(BaseCell& basecell, const int istep) override; + void runner(BaseCell &basecell, const int istep) override; protected: /** @brief Use independent iteration limits for initial-state SCF and propagation. */ @@ -37,23 +37,27 @@ class ESolver_KS_PW_TDDFT : public ESolver_KS_PW ESolver_KS::DensityStage density_stage(const int istep, const int iter) const override; bool defer_iter_output(const int istep) const override; - void before_scf(UnitCell& ucell, const int istep) override; + void before_scf(UnitCell &ucell, const int istep) override; /** @brief Cover shifted projectors and bind endpoint A before the first Hamiltonian application. */ - void prepare_init_hamilt(const UnitCell& ucell) override; + void prepare_init_hamilt(const UnitCell &ucell) override; /** @brief Print the TDDFT iteration header and initialize the PW iteration. */ - void iter_init(UnitCell& ucell, const int istep, const int iter) override; + void iter_init(UnitCell &ucell, const int istep, const int iter) override; /** @brief Switch between ground-state diagonalization and real-time propagation. */ - void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; /** @brief Save the converged or iteration-limited endpoint for the next propagation step. */ - void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; private: using Real = typename GetTypeReal::type; - std::ofstream& log_; + std::ofstream &log_; std::unique_ptr> td_prop_; std::shared_ptr td_field_manager_; @@ -65,14 +69,15 @@ class ESolver_KS_PW_TDDFT : public ESolver_KS_PW double initial_wave_electrons_ = 0.0; double initial_rho_electrons_ = 0.0; - void run_prop(UnitCell& cell, int step); - bool advance_interval(UnitCell& cell, - int step, - int index, - int depth, - const elecstate::TDFieldState& full, - pw::TDElecSnap& accepted, - hsolver::TDOrthStats& stats); + void run_prop(UnitCell &cell, int step); + bool advance_interval( + UnitCell &cell, + int step, + int index, + int depth, + const elecstate::TDFieldState &full, + pw::TDElecSnap &accepted, + hsolver::TDOrthStats &stats); void output_field(int step) const; /** @brief Print the one-based electronic step header. */ void print_step(const int istep) const; diff --git a/source/source_esolver/esolver_lj.cpp b/source/source_esolver/esolver_lj.cpp index e30eef32e5..fe61dd4c4d 100644 --- a/source/source_esolver/esolver_lj.cpp +++ b/source/source_esolver/esolver_lj.cpp @@ -1,12 +1,12 @@ #include "esolver_lj.h" #include "source_base/global_variable.h" +#include "source_cell/cif_io.h" #include "source_cell/mdcell.h" #include "source_cell/module_neighlist/neighbor_search.h" #include "source_cell/module_neighlist/neighbor_types.h" -#include "source_io/module_parameter/parameter.h" -#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" +#include "source_io/module_parameter/parameter.h" #ifdef __MPI #include #endif @@ -18,7 +18,7 @@ namespace ModuleESolver { -void ESolver_LJ::before_all_runners(BaseCell& cell, const Input_para& inp) +void ESolver_LJ::before_all_runners(BaseCell &cell, const Input_para &inp) { this->inp_ = &inp; lj_potential = 0.0; @@ -26,7 +26,7 @@ void ESolver_LJ::before_all_runners(BaseCell& cell, const Input_para& inp) if (cell.kind() == BaseCell::Kind::mdcell) { - MDCell& mdcell = static_cast(cell); + MDCell &mdcell = static_cast(cell); double cutoff = 0.0; for (std::size_t i = 0; i < inp.mdp.lj_rcut.size(); ++i) { @@ -34,23 +34,32 @@ void ESolver_LJ::before_all_runners(BaseCell& cell, const Input_para& inp) } mdcell.set_neighbor_cutoff(cutoff); rcut_search_radius(static_cast(mdcell.type_labels().size()), inp.mdp.lj_rcut); - set_c6_c12(static_cast(mdcell.type_labels().size()), inp.mdp.lj_rule, inp.mdp.lj_epsilon, inp.mdp.lj_sigma); + set_c6_c12( + static_cast(mdcell.type_labels().size()), + inp.mdp.lj_rule, + inp.mdp.lj_epsilon, + inp.mdp.lj_sigma); cal_en_shift(static_cast(mdcell.type_labels().size()), inp.mdp.lj_eshift); return; } - UnitCell& ucell = static_cast(cell); + UnitCell &ucell = static_cast(cell); lj_force.create(ucell.nat, 3); - ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", - ucell, - "# Generated by ABACUS ModuleIO::CifParser", - "data_?"); + ModuleIO::CifParser::write( + PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); rcut_search_radius(ucell.ntype, inp.mdp.lj_rcut); - set_c6_c12(ucell.ntype, inp.mdp.lj_rule, inp.mdp.lj_epsilon, inp.mdp.lj_sigma); + set_c6_c12( + ucell.ntype, + inp.mdp.lj_rule, + inp.mdp.lj_epsilon, + inp.mdp.lj_sigma); cal_en_shift(ucell.ntype, inp.mdp.lj_eshift); } -void ESolver_LJ::runner(BaseCell& cell, const int istep) +void ESolver_LJ::runner(BaseCell &cell, const int istep) { static_cast(istep); @@ -60,14 +69,14 @@ void ESolver_LJ::runner(BaseCell& cell, const int istep) if (cell.kind() == BaseCell::Kind::unitcell) { NeighborSearch neighbor_search; - UnitCell& ucell = static_cast(cell); + UnitCell &ucell = static_cast(cell); lj_force.zero_out(); neighbor_search.init(ucell, search_radius); neighbor_search.build_neighbors(); - const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); - const std::vector& inside_atoms = neighbor_search.get_inside_atoms(); - const std::vector& all_atoms = neighbor_search.get_all_atoms(); + const NeighborList &neighbor_list = neighbor_search.get_neighbor_list(); + const std::vector &inside_atoms = neighbor_search.get_inside_atoms(); + const std::vector &all_atoms = neighbor_search.get_all_atoms(); std::array virial{}; std::vector atom_offsets(ucell.ntype + 1, 0); for (int it = 0; it < ucell.ntype; ++it) @@ -77,78 +86,85 @@ void ESolver_LJ::runner(BaseCell& cell, const int istep) for (int local_i = 0; local_i < neighbor_list.get_ncentral_atoms(); ++local_i) { - const NeighborAtom& center_atom = inside_atoms[static_cast(local_i)]; + const NeighborAtom ¢er_atom = inside_atoms[static_cast(local_i)]; const int it = center_atom.atom_type; const int ia = center_atom.atom_index; const int iat = atom_offsets[it] + ia; - const ModuleBase::Vector3 tau1(center_atom.position_x, - center_atom.position_y, - center_atom.position_z); + const ModuleBase::Vector3 tau1( + center_atom.position_x, center_atom.position_y, center_atom.position_z); for (int ad = 0; ad < neighbor_list.get_numneigh(local_i); ++ad) { - const NeighborAtom& neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; - const ModuleBase::Vector3 tau2(neighbor_atom.position_x, - neighbor_atom.position_y, - neighbor_atom.position_z); + const NeighborAtom &neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; + const ModuleBase::Vector3 tau2( + neighbor_atom.position_x, neighbor_atom.position_y, neighbor_atom.position_z); const ModuleBase::Vector3 dtau = (tau1 - tau2) * ucell.lat0; const double distance = dtau.norm(); if (distance < lj_rcut(it, neighbor_atom.atom_type)) { - lj_potential += LJ_energy(distance, it, neighbor_atom.atom_type) - - en_shift(it, neighbor_atom.atom_type); + lj_potential += + LJ_energy(distance, it, neighbor_atom.atom_type) - en_shift(it, neighbor_atom.atom_type); const ModuleBase::Vector3 f_ij = LJ_force(dtau, it, neighbor_atom.atom_type); lj_force(iat, 0) += f_ij.x; lj_force(iat, 1) += f_ij.y; lj_force(iat, 2) += f_ij.z; for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) virial[i * 3 + j] += dtau[i] * f_ij[j]; + { + for (int j = 0; j < 3; ++j) + { + virial[i * 3 + j] += dtau[i] * f_ij[j]; + } + } } } } lj_potential *= 0.5; for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) lj_virial(i, j) = virial[i * 3 + j] / (2.0 * ucell.omega); - GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) - << lj_potential * ModuleBase::Ry_to_eV << " eV" << std::endl; + { + for (int j = 0; j < 3; ++j) + { + lj_virial(i, j) = virial[i * 3 + j] / (2.0 * ucell.omega); + } + } + GlobalV::ofs_running << " #TOTAL ENERGY# " << std::setprecision(11) << lj_potential * ModuleBase::Ry_to_eV + << " eV" << std::endl; return; } - MDCell& mdcell = static_cast(cell); + MDCell &mdcell = static_cast(cell); if (!mdcell.has_neighbor_search()) { ModuleBase::WARNING_QUIT("ESolver", "MDCell neighbors must be prepared by the caller before runner()."); } - std::vector& owned_atoms = mdcell.owned_atoms(); + std::vector &owned_atoms = mdcell.owned_atoms(); for (std::size_t i = 0; i < owned_atoms.size(); ++i) { owned_atoms[i].force.set(0.0, 0.0, 0.0); } - const NeighborSearch& neighbor_search = mdcell.neighbor_search(); - const NeighborList& neighbor_list = neighbor_search.get_neighbor_list(); - const std::vector& all_atoms = neighbor_search.get_all_atoms(); + const NeighborSearch &neighbor_search = mdcell.neighbor_search(); + const NeighborList &neighbor_list = neighbor_search.get_neighbor_list(); + const std::vector &all_atoms = neighbor_search.get_all_atoms(); double local_potential = 0.0; std::array local_virial{}; for (int local_i = 0; local_i < neighbor_list.get_ncentral_atoms(); ++local_i) { - LocalAtom& center_atom = owned_atoms[static_cast(local_i)]; + LocalAtom ¢er_atom = owned_atoms[static_cast(local_i)]; ModuleBase::Vector3 tau1(center_atom.cart.x, center_atom.cart.y, center_atom.cart.z); for (int ad = 0; ad < neighbor_list.get_numneigh(local_i); ++ad) { - const NeighborAtom& neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; - ModuleBase::Vector3 tau2(neighbor_atom.position_x, - neighbor_atom.position_y, - neighbor_atom.position_z); + const NeighborAtom &neighbor_atom = all_atoms[neighbor_list.get_firstneigh(local_i)[ad]]; + ModuleBase::Vector3 tau2( + neighbor_atom.position_x, neighbor_atom.position_y, neighbor_atom.position_z); ModuleBase::Vector3 dtau = (tau1 - tau2) * mdcell.lat0(); const double distance = dtau.norm(); if (distance < lj_rcut(center_atom.type, neighbor_atom.atom_type)) { - local_potential += LJ_energy(distance, center_atom.type, neighbor_atom.atom_type) - - en_shift(center_atom.type, neighbor_atom.atom_type); + local_potential += LJ_energy(distance, center_atom.type, neighbor_atom.atom_type) - + en_shift(center_atom.type, neighbor_atom.atom_type); ModuleBase::Vector3 f_ij = LJ_force(dtau, center_atom.type, neighbor_atom.atom_type); center_atom.force += f_ij; for (int i = 0; i < 3; ++i) @@ -163,13 +179,20 @@ void ESolver_LJ::runner(BaseCell& cell, const int istep) } #ifdef __MPI - MPI_Allreduce(MPI_IN_PLACE, &local_potential, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); - MPI_Allreduce(MPI_IN_PLACE, - local_virial.data(), - static_cast(local_virial.size()), - MPI_DOUBLE, - MPI_SUM, - mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + &local_potential, + 1, + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + local_virial.data(), + static_cast(local_virial.size()), + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); #endif lj_potential = local_potential / 2.0; @@ -182,22 +205,24 @@ void ESolver_LJ::runner(BaseCell& cell, const int istep) } } -double ESolver_LJ::cal_energy() -{ - return lj_potential; -} +double ESolver_LJ::cal_energy() { return lj_potential; } -void ESolver_LJ::cal_force(BaseCell& cell, ModuleBase::matrix& force) +void ESolver_LJ::cal_force(BaseCell &cell, ModuleBase::matrix &force) { if (cell.kind() == BaseCell::Kind::unitcell) { - UnitCell& ucell = static_cast(cell); + UnitCell &ucell = static_cast(cell); force = lj_force; - ModuleIO::print_force(GlobalV::ofs_running, ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); + ModuleIO::print_force( + GlobalV::ofs_running, + ucell, + "TOTAL-FORCE (eV/Angstrom)", + force, + false); return; } - MDCell& mdcell = static_cast(cell); + MDCell &mdcell = static_cast(cell); force.create(mdcell.owned_atoms().size(), 3); for (int i = 0; i < mdcell.owned_atoms().size(); ++i) { @@ -207,21 +232,31 @@ void ESolver_LJ::cal_force(BaseCell& cell, ModuleBase::matrix& force) } } -void ESolver_LJ::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) +void ESolver_LJ::cal_stress(BaseCell &cell, ModuleBase::matrix &stress) { stress = lj_virial; if (cell.kind() == BaseCell::Kind::unitcell) { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } else { #ifdef __MPI - if (static_cast(cell).mpi_rank() == 0) + if (static_cast(cell).mpi_rank() == 0) #endif { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } } @@ -233,7 +268,7 @@ void ESolver_LJ::cal_stress(BaseCell& cell, ModuleBase::matrix& stress) } } -void ESolver_LJ::after_all_runners(BaseCell& cell) +void ESolver_LJ::after_all_runners(BaseCell &cell) { static_cast(cell); @@ -243,13 +278,13 @@ void ESolver_LJ::after_all_runners(BaseCell& cell) GlobalV::ofs_running << " --------------------------------------------\n\n" << std::endl; } -void ESolver_LJ::others(BaseCell& cell, const int istep) +void ESolver_LJ::others(BaseCell &cell, const int istep) { static_cast(istep); static_cast(cell); } -double ESolver_LJ::LJ_energy(const double& d, const int& i, const int& j) const +double ESolver_LJ::LJ_energy(const double &d, const int &i, const int &j) const { assert(d > 1e-6); // avoid atom overlap const double r2 = d * d; @@ -258,9 +293,8 @@ double ESolver_LJ::LJ_energy(const double& d, const int& i, const int& j) const return lj_c12(i, j) / (r6 * r6) - lj_c6(i, j) / r6; } -ModuleBase::Vector3 ESolver_LJ::LJ_force(const ModuleBase::Vector3& dr, - const int& i, - const int& j) const +ModuleBase::Vector3 ESolver_LJ::LJ_force( + const ModuleBase::Vector3 &dr, const int &i, const int &j) const { const double d = dr.norm(); assert(d > 1e-6); // avoid atom overlap @@ -272,7 +306,7 @@ ModuleBase::Vector3 ESolver_LJ::LJ_force(const ModuleBase::Vector3& rcut) +void ESolver_LJ::rcut_search_radius(const int &ntype, const std::vector &rcut) { lj_rcut.create(ntype, ntype); double rcut_max = 0.0; @@ -307,10 +341,11 @@ void ESolver_LJ::rcut_search_radius(const int& ntype, const std::vector& search_radius = rcut_max + 0.01; } -void ESolver_LJ::set_c6_c12(const int& ntype, - const int& rule, - const std::vector& epsilon, - const std::vector& sigma) +void ESolver_LJ::set_c6_c12( + const int &ntype, + const int &rule, + const std::vector &epsilon, + const std::vector &sigma) { lj_c6.create(ntype, ntype); lj_c12.create(ntype, ntype); @@ -318,12 +353,14 @@ void ESolver_LJ::set_c6_c12(const int& ntype, std::vector lj_epsilon = epsilon; std::vector lj_sigma = sigma; - std::transform(begin(lj_epsilon), end(lj_epsilon), begin(lj_epsilon), [](double x) { - return x / ModuleBase::Ry_to_eV; - }); - std::transform(begin(lj_sigma), end(lj_sigma), begin(lj_sigma), [](double x) { - return x * ModuleBase::ANGSTROM_AU; - }); + std::transform( + begin(lj_epsilon), + end(lj_epsilon), + begin(lj_epsilon), [](double x) { return x / ModuleBase::Ry_to_eV; }); + std::transform( + begin(lj_sigma), + end(lj_sigma), + begin(lj_sigma), [](double x) { return x * ModuleBase::ANGSTROM_AU; }); if (lj_epsilon.size() != lj_sigma.size()) { @@ -385,7 +422,7 @@ void ESolver_LJ::set_c6_c12(const int& ntype, } } -void ESolver_LJ::cal_en_shift(const int& ntype, const bool& is_shift) +void ESolver_LJ::cal_en_shift(const int &ntype, const bool &is_shift) { en_shift.create(ntype, ntype); diff --git a/source/source_esolver/esolver_lj.h b/source/source_esolver/esolver_lj.h index 8f8ca3056b..b76e225da5 100644 --- a/source/source_esolver/esolver_lj.h +++ b/source/source_esolver/esolver_lj.h @@ -16,24 +16,21 @@ namespace ModuleESolver class ESolver_LJ : public ESolver { public: - ESolver_LJ() - { - classname = "ESolver_LJ"; - } + ESolver_LJ() { classname = "ESolver_LJ"; } - void before_all_runners(BaseCell& cell, const Input_para& inp) override; + void before_all_runners(BaseCell &cell, const Input_para &inp) override; - void runner(BaseCell& cell, const int istep) override; + void runner(BaseCell &cell, const int istep) override; double cal_energy() override; - void cal_force(BaseCell& cell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &cell, ModuleBase::matrix &force) override; - void cal_stress(BaseCell& cell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &cell, ModuleBase::matrix &stress) override; - void after_all_runners(BaseCell& cell) override; + void after_all_runners(BaseCell &cell) override; - void others(BaseCell& cell, const int istep) override; + void others(BaseCell &cell, const int istep) override; //==================================================================== // Test seam. @@ -48,65 +45,50 @@ class ESolver_LJ : public ESolver //==================================================================== /// @brief neighbour search radius derived from the largest cutoff - double get_search_radius() const - { - return search_radius; - } + double get_search_radius() const { return search_radius; } /// @brief per-type-pair cutoff radii - const ModuleBase::matrix& get_lj_rcut() const - { - return lj_rcut; - } + const ModuleBase::matrix &get_lj_rcut() const { return lj_rcut; } /// @brief per-type-pair c6 coefficients - const ModuleBase::matrix& get_lj_c6() const - { - return lj_c6; - } + const ModuleBase::matrix &get_lj_c6() const { return lj_c6; } /// @brief per-type-pair c12 coefficients - const ModuleBase::matrix& get_lj_c12() const - { - return lj_c12; - } + const ModuleBase::matrix &get_lj_c12() const { return lj_c12; } /// @brief per-type-pair energy shift at the cutoff - const ModuleBase::matrix& get_en_shift() const - { - return en_shift; - } + const ModuleBase::matrix &get_en_shift() const { return en_shift; } /// @brief computed lattice virials - const ModuleBase::matrix& get_lj_virial() const - { - return lj_virial; - } + const ModuleBase::matrix &get_lj_virial() const { return lj_virial; } - void rcut_search_radius_for_testing(const int& ntype, const std::vector& rcut) + void rcut_search_radius_for_testing(const int &ntype, const std::vector &rcut) { rcut_search_radius(ntype, rcut); } - void set_c6_c12_for_testing(const int& ntype, - const int& rule, - const std::vector& epsilon, - const std::vector& sigma) - { - set_c6_c12(ntype, rule, epsilon, sigma); - } - void cal_en_shift_for_testing(const int& ntype, const bool& is_shift) + void set_c6_c12_for_testing( + const int &ntype, + const int &rule, + const std::vector &epsilon, + const std::vector &sigma) { - cal_en_shift(ntype, is_shift); + set_c6_c12( + ntype, + rule, + epsilon, + sigma); } + void cal_en_shift_for_testing(const int &ntype, const bool &is_shift) { cal_en_shift(ntype, is_shift); } private: - double LJ_energy(const double& d, const int& i, const int& j) const; + double LJ_energy(const double &d, const int &i, const int &j) const; - ModuleBase::Vector3 LJ_force(const ModuleBase::Vector3& dr, const int& i, const int& j) const; + ModuleBase::Vector3 LJ_force(const ModuleBase::Vector3 &dr, const int &i, const int &j) const; - void rcut_search_radius(const int& ntype, const std::vector& rcut); + void rcut_search_radius(const int &ntype, const std::vector &rcut); - void set_c6_c12(const int& ntype, - const int& rule, - const std::vector& epsilon, - const std::vector& sigma); + void set_c6_c12( + const int &ntype, + const int &rule, + const std::vector &epsilon, + const std::vector &sigma); - void cal_en_shift(const int& ntype, const bool& is_shift); + void cal_en_shift(const int &ntype, const bool &is_shift); //--------------temporary---------------------------- double search_radius = -1.0; diff --git a/source/source_esolver/esolver_lr_cfg.cpp b/source/source_esolver/esolver_lr_cfg.cpp index 2e07da6792..f194a3e7b2 100644 --- a/source/source_esolver/esolver_lr_cfg.cpp +++ b/source/source_esolver/esolver_lr_cfg.cpp @@ -1,19 +1,19 @@ #include "source_lcao/module_lr/kernel_pots.h" // Resolve LR dimensions, validate solver options, and initialize kernel potentials. #include "esolver_lr_lcao_tddft.h" +#include "source_io/module_parameter/parameter.h" +#include "source_io/module_wf/read_wfc_nao.h" #include "source_lcao/module_lr/init_helpers.h" -#include "source_lcao/module_lr/utils/lr_util.h" #include "source_lcao/module_lr/utils/lr_io.h" -#include "source_io/module_wf/read_wfc_nao.h" -#include "source_io/module_parameter/parameter.h" +#include "source_lcao/module_lr/utils/lr_util.h" + #include #include #include using namespace LR; -template -void ModuleESolver::ESolver_LR::set_dimension() +template void ModuleESolver::ESolver_LR::set_dimension() { this->nspin = this->inp_->nspin; this->nstates = this->inp_->lr_nstates; @@ -24,16 +24,22 @@ void ModuleESolver::ESolver_LR::set_dimension() this->nupdown = static_cast(std::lround(this->inp_->nupdown)); if (this->ks_) { - this->nupdown = LR_Util::spin_population_difference(this->ks_->pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); + this->nupdown = LR_Util::spin_population_difference( + this->ks_->pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); } - else if (this->inp_->ri_hartree_benchmark != "aims" - && this->inp_->ri_hartree_benchmark != "aims-librpa") + else if (this->inp_->ri_hartree_benchmark != "aims" && this->inp_->ri_hartree_benchmark != "aims-librpa") { std::vector populations; const bool gamma_only = std::is_same::value; const bool binary = this->inp_->init_wfc_file_format == "binary"; - if (!ModuleIO::read_wfc_nao_spin_populations(this->in_dir, this->kv.get_nkstot(), this->nspin, gamma_only, binary, - this->my_rank_, populations)) + if (!ModuleIO::read_wfc_nao_spin_populations( + this->in_dir, + this->kv.get_nkstot(), + this->nspin, + gamma_only, + binary, + this->my_rank_, + populations)) { ModuleBase::WARNING_QUIT("ESolver_LR", "read complete KS occupations failed"); } @@ -42,8 +48,8 @@ void ModuleESolver::ESolver_LR::set_dimension() } // read_pseudo/ParamUpdater has already resolved nelec and applied nelec_delta. this->nocc_max = LR_Util::cal_nocc(this->inp_->nelec, this->nspin, this->nupdown); - if (this->inp_->ri_hartree_benchmark == "aims" || this->inp_->ri_hartree_benchmark == "aims-librpa" - && !this->inp_->aims_nbasis.empty()) + if (this->inp_->ri_hartree_benchmark == "aims" || + this->inp_->ri_hartree_benchmark == "aims-librpa" && !this->inp_->aims_nbasis.empty()) { // Total basis size: sum the per-atom basis size times the atom count for each type. int total_nbasis = 0; @@ -57,13 +63,18 @@ void ModuleESolver::ESolver_LR::set_dimension() { this->ucell_->atoms[it].nw = this->inp_->aims_nbasis[it]; } - const_cast(this->ucell_)->set_iat2iwt(1); // update iat2iwt for aims_nbasis 25-05-23 + const_cast(this->ucell_)->set_iat2iwt(1); // update iat2iwt for aims_nbasis 25-05-23 int nbands_file = 0; int nk_file = 0; int nspin_file = 0; int nocc_file = 0; - LR_IO::parse_band_out_file(this->inp_->rpa_outdir, nbands_file, nk_file, nspin_file, nocc_file); + LR_IO::parse_band_out_file( + this->inp_->rpa_outdir, + nbands_file, + nk_file, + nspin_file, + nocc_file); std::cout << "nocc from band_out: " << nocc_file << std::endl; ks_nbands = nbands_file; this->nocc_max = nocc_file; @@ -71,7 +82,7 @@ void ModuleESolver::ESolver_LR::set_dimension() // calculate the number of occupied and unoccupied states // which determines the basis size of the excited states this->nocc_in = LR_Util::cal_nocc_window(this->inp_->nocc, this->nocc_max); - this->nvirt_in = ks_nbands - this->nocc_max; //nbands-nocc + this->nvirt_in = ks_nbands - this->nocc_max; // nbands-nocc if (this->inp_->nvirt > this->nvirt_in) { this->ofs_running_ << "ESolver_LR: input nvirt is too large to cover by nbands, set nvirt = nbands - nocc = " @@ -85,9 +96,11 @@ void ModuleESolver::ESolver_LR::set_dimension() this->nk = this->inp_->nspin == 2 ? this->kv.get_nks() / 2 : this->kv.get_nks(); this->nocc.resize(nspin, nocc_in); this->nvirt.resize(nspin, nvirt_in); - if (this->nstates <= 0) { + if (this->nstates <= 0) + { this->nstates = nk * nocc_in * nvirt_in; - this->ofs_running_ << "ESolver_LR: lr_nstates <= 0, set nstates = nk * nocc * nvirt = " << this->nstates << std::endl; + this->ofs_running_ << "ESolver_LR: lr_nstates <= 0, set nstates = nk * nocc * nvirt = " << this->nstates + << std::endl; } for (int is = 0; is < nspin; ++is) { @@ -106,62 +119,76 @@ void ModuleESolver::ESolver_LR::set_dimension() this->ofs_running_ << "number of excited states to be solved: " << this->nstates << std::endl; } -template -void ModuleESolver::ESolver_LR::reset_dim_spin2() +template void ModuleESolver::ESolver_LR::reset_dim_spin2() { - if (nspin != 2) - { - return; - } - if (nupdown != 0) + if (nspin != 2) + { + return; + } + if (nupdown != 0) { this->openshell = true; const int minority_spin = nupdown > 0 ? 1 : 0; const int polarization = std::abs(nupdown); nocc[minority_spin] -= polarization; nvirt[minority_spin] += polarization; - npairs = { nocc[0] * nvirt[0], nocc[1] * nvirt[1] }; + npairs = {nocc[0] * nvirt[0], nocc[1] * nvirt[1]}; std::cout << "** Solve the spin-up and spin-down states separately for open-shell system. **" << std::endl; } - for (int is : {0, 1}) - { - if (npairs[is] <= 0) - { - throw std::invalid_argument(std::string("ESolver_LR: npairs (nocc*nvirt) <= 0 for spin") + std::string(is == 0 ? "up" : "down")); - } - } + for (int is : {0, 1}) + { + if (npairs[is] <= 0) + { + throw std::invalid_argument( + std::string("ESolver_LR: npairs (nocc*nvirt) <= 0 for spin") + std::string(is == 0 ? "up" : "down")); + } + } - if (nstates > (npairs[0] + npairs[1]) * nk) - { - throw std::invalid_argument("ESolver_LR: nstates > nocc*nvirt*nk"); - } - if (this->inp_->lr_unrestricted) - { - this->openshell = true; - } + if (nstates > (npairs[0] + npairs[1]) * nk) + { + throw std::invalid_argument("ESolver_LR: nstates > nocc*nvirt*nk"); + } + if (this->inp_->lr_unrestricted) + { + this->openshell = true; + } if (!this->openshell) - { - std::cout << " ** Assuming degenerate spin-up and spin-down states **" << std::endl; - } + { + std::cout << " ** Assuming degenerate spin-up and spin-down states **" << std::endl; + } } -template -void ModuleESolver::ESolver_LR::init_pot(const Charge& chg_gs) +template void ModuleESolver::ESolver_LR::init_pot(const Charge &chg_gs) { this->pot.assign(nspin, nullptr); if (this->inp_->ri_hartree_benchmark != "none") { return; } - const auto& grid = pgrid(); - auto prepared = LR::prepare_lr_potentials(*this->inp_, xc_kernel, *this->pw_rho, - *this->ucell_, chg_gs, grid, nspin, openshell); + const auto &grid = pgrid(); + auto prepared = LR::prepare_lr_potentials( + *this->inp_, + xc_kernel, + *this->pw_rho, + *this->ucell_, + chg_gs, + grid, + nspin, + openshell); this->pot = std::move(prepared.pot); if (this->inp_->cal_force) { this->init_pot_groundstate(chg_gs); - this->pot_hxc_gs = LR::prepare_gs_potential(*this->inp_, xc_kernel, *this->pw_rho, - *this->ucell_, chg_gs, grid, nspin, openshell, prepared); + this->pot_hxc_gs = LR::prepare_gs_potential( + *this->inp_, + xc_kernel, + *this->pw_rho, + *this->ucell_, + chg_gs, + grid, + nspin, + openshell, + prepared); } } diff --git a/source/source_esolver/esolver_lr_grad.cpp b/source/source_esolver/esolver_lr_grad.cpp index 9149c00e7c..d0c8a64ef3 100644 --- a/source/source_esolver/esolver_lr_grad.cpp +++ b/source/source_esolver/esolver_lr_grad.cpp @@ -1,78 +1,103 @@ +#include "source_base/parallel_reduce.h" #include "source_esolver/esolver_lr_lcao_tddft.h" -#include "source_lcao/module_lr/zeq_solver.h" +#include "source_estate/module_dm/dm_from_psi.h" +#include "source_io/module_output/output_log.h" #include "source_lcao/module_lr/cal_edm.h" -#include "source_lcao/module_lr/lr_force.h" +#include "source_lcao/module_lr/grad_degen.h" #include "source_lcao/module_lr/gradient_inputs.h" #include "source_lcao/module_lr/gradient_output.h" #include "source_lcao/module_lr/lr_amp.h" -#include "source_lcao/module_lr/grad_degen.h" -#include "source_base/parallel_reduce.h" +#include "source_lcao/module_lr/lr_force.h" +#include "source_lcao/module_lr/zeq_solver.h" + #include #include -#include "source_estate/module_dm/dm_from_psi.h" -#include "source_io/module_output/output_log.h" using namespace LR; - ///========================= excited-state geometry relaxation ========================= -template -void ModuleESolver::ESolver_LR::init_pot_groundstate(const Charge& chg_gs) +template void ModuleESolver::ESolver_LR::init_pot_groundstate(const Charge &chg_gs) { ModuleBase::TITLE("ESolver_LR", "init_pot_gs"); std::vector pot_register; if (this->inp_->vl_in_h) { if (!this->ks_) - { // on the `ks-lr` path `sfac()`/`vloc()` alias the ground-state solver's, which + { // on the `ks-lr` path `sfac()`/`vloc()` alias the ground-state solver's, which // `ESolver_FP::before_scf` already refreshed for the current geometry //! 11) calculate the structure factor // the has_float_data flag below is read the same way core ABACUS reads it at the // analogous call site (source_esolver/esolver_fp.cpp's `this->sf.setup(...)`), so this // mirrors the established convention rather than introducing a new global dependency. - this->sfac().setup(&(*this->ucell_), pgrid(), this->pw_rhod, PARAM.globalv.has_float_data); + this->sfac().setup( + &(*this->ucell_), + pgrid(), + this->pw_rhod, + PARAM.globalv.has_float_data); this->vloc().init_vloc((*this->ucell_), this->pw_rho); } pot_register.push_back("local"); } - if(this->inp_->vh_in_h) + if (this->inp_->vh_in_h) { pot_register.push_back("hartree"); } pot_register.push_back("xc"); // initialize the ground state potential - this->pot_gs = LR_Util::make_unique(this->pw_rhod, this->pw_rho, - &(*this->ucell_), &this->vloc().vloc, &this->sfac(), &this->solvent, - &this->etxc_gs, &this->vtxc_gs); + this->pot_gs = LR_Util::make_unique( + this->pw_rhod, + this->pw_rho, + &(*this->ucell_), + &this->vloc().vloc, + &this->sfac(), + &this->solvent, + &this->etxc_gs, + &this->vtxc_gs); this->pot_gs.get()->pot_register(pot_register); - XC_Functional::set_xc_type((*this->ucell_).atoms[0].ncpp.xc_func); // set XC type of the ground state - this->pot_gs->init_pot(&chg_gs); // call update_from_charge inside + XC_Functional::set_xc_type((*this->ucell_).atoms[0].ncpp.xc_func); // set XC type of the ground state + this->pot_gs->init_pot(&chg_gs); // call update_from_charge inside if (LR_Util::has_local_xc(this->xc_kernel)) { - XC_Functional::set_xc_type(this->xc_kernel); // recover the excited state xc kernel type + XC_Functional::set_xc_type(this->xc_kernel); // recover the excited state xc kernel type } if (this->inp_->test_force) { - this->pot_gs_hartree = LR_Util::make_unique(this->pw_rhod, this->pw_rho, - &(*this->ucell_), &this->vloc().vloc, &this->sfac(), &this->solvent, - &this->etxc_gs, &this->vtxc_gs); - this->pot_gs_hartree->pot_register({ "hartree" }); - this->pot_gs_hartree->init_pot(&chg_gs); // call update_from_charge inside + this->pot_gs_hartree = LR_Util::make_unique( + this->pw_rhod, + this->pw_rho, + &(*this->ucell_), + &this->vloc().vloc, + &this->sfac(), + &this->solvent, + &this->etxc_gs, + &this->vtxc_gs); + this->pot_gs_hartree->pot_register({"hartree"}); + this->pot_gs_hartree->init_pot(&chg_gs); // call update_from_charge inside } } -template +template ct::Tensor ModuleESolver::ESolver_LR::pad_X_to_z_(const int ispin, const int istate_begin, const int nst) const { - return LR::pad_amplitudes(this->X, this->openshell, this->paraX_, this->paraX_z_, - this->nocc, this->nvirt, this->nk, this->nloc_per_state, this->nloc_per_state_z_, - ispin, istate_begin, nst); + return LR::pad_amplitudes( + this->X, + this->openshell, + this->paraX_, + this->paraX_z_, + this->nocc, + this->nvirt, + this->nk, + this->nloc_per_state, + this->nloc_per_state_z_, + ispin, + istate_begin, + nst); } -template -ct::Tensor ModuleESolver::ESolver_LR::solve_zvector_eqation(const int ispin, const int nst, const ct::Tensor& Xz) +template +ct::Tensor ModuleESolver::ESolver_LR::solve_zvector_eqation(const int ispin, const int nst, const ct::Tensor &Xz) { ModuleBase::TITLE("ESolver_LR", "cal_force"); ModuleBase::timer::start("ESolver_LR", "solve_zvector_eqation"); @@ -84,19 +109,27 @@ ct::Tensor ModuleESolver::ESolver_LR::solve_zvector_eqation(const int isp // condition the Z-vector enforces holds in EVERY occupied-virtual rotation. The padded // entries are zero, so every X-derived quantity (D^X, T) is unchanged; only the space Z is // solved in grows. Both the closed- and the open-shell path go through here. - ct::Tensor Z = LR_Util::newTensor({ nst, this->nloc_per_state_z_ }); + ct::Tensor Z = LR_Util::newTensor({nst, this->nloc_per_state_z_}); // construct and solve the Z-vector equation const LR::GradientInputs inputs = this->gradient_inputs_(); - const T* const x_data = Xz.template data(); - T* const z_data = Z.template data(); + const T *const x_data = Xz.template data(); + T *const z_data = Z.template data(); std::weak_ptr pot_weak = inputs.pot[ispin]; - Z_vector_equation(inputs, x_data, z_data, nst, pot_weak, - this->spin_types[ispin], this->in_dir, this->openshell, this->inp_->lr_grad_solver); + Z_vector_equation( + inputs, + x_data, + z_data, + nst, + pot_weak, + this->spin_types[ispin], + this->in_dir, + this->openshell, + this->inp_->lr_grad_solver); ModuleBase::timer::end("ESolver_LR", "solve_zvector_eqation"); return Z; } -template +template std::vector ModuleESolver::ESolver_LR::cal_force(const int ispin, const int istate_only) { if (this->inp_->test_force && ispin == 0) @@ -121,27 +154,55 @@ std::vector ModuleESolver::ESolver_LR::cal_force(cons { omega[i] = this->pelec->ekb.c[ispin * this->nstates + ist_begin + i]; } - return this->cal_force_Xz(ispin, Xz, omega, ist_begin); + return this->cal_force_Xz( + ispin, + Xz, + omega, + ist_begin); } -template -LR::GradientInputs ModuleESolver::ESolver_LR::gradient_inputs_() const +template LR::GradientInputs ModuleESolver::ESolver_LR::gradient_inputs_() const { - return { *this->ucell_, this->kv, this->gd(), this->orb_cutoff_, this->paraMat_, - this->paraC_z_, this->paraX_z_, *this->psi_ks_z_, this->eig_ks_z_, this->nocc, - this->nvirt_z_, this->nspin, this->nk, this->nbasis, this->nloc_per_state_z_, - this->xc_kernel, this->inp_->dft_functional, this->inp_->ks_solver, - this->inp_->test_force, this->excited_relax_, this->out_dir, this->my_rank_, - this->spin_types, this->pot, this->pot_hxc_gs, this->ofs_running_ + return {*this->ucell_, + this->kv, + this->gd(), + this->orb_cutoff_, + this->paraMat_, + this->paraC_z_, + this->paraX_z_, + *this->psi_ks_z_, + this->eig_ks_z_, + this->nocc, + this->nvirt_z_, + this->nspin, + this->nk, + this->nbasis, + this->nloc_per_state_z_, + this->xc_kernel, + this->inp_->dft_functional, + this->inp_->ks_solver, + this->inp_->test_force, + this->excited_relax_, + this->out_dir, + this->my_rank_, + this->spin_types, + this->pot, + this->pot_hxc_gs, + this->ofs_running_ #ifdef __EXX - , this->exx_lri, this->exx_info.info_global.hybrid_alpha + , + this->exx_lri, + this->exx_info.info_global.hybrid_alpha #endif }; } -template -std::vector ModuleESolver::ESolver_LR::cal_force_Xz(const int ispin, - const ct::Tensor& Xz, const std::vector& omega, const int label_begin) +template +std::vector ModuleESolver::ESolver_LR::cal_force_Xz( + const int ispin, + const ct::Tensor &Xz, + const std::vector &omega, + const int label_begin) { ModuleBase::timer::start("ESolver_LR", "cal_force_Xz"); const int nst = static_cast(omega.size()); @@ -149,21 +210,44 @@ std::vector ModuleESolver::ESolver_LR::cal_force_Xz(c const ct::Tensor Z = this->solve_zvector_eqation(channel, nst, Xz); const auto dm_gs = this->cal_dm_gs(); const LR::GradientInputs inputs = this->gradient_inputs_(); - const LR::ForceSettings force_settings{this->nspin, this->inp_->test_force, - this->inp_->vl_in_h, this->inp_->vh_in_h, this->inp_->dft_functional}; - LR_Force force_terms(*this->ucell_, this->kv.kvec_d, this->paraMat_, - *this->pw_rhod, *this->pw_rho, this->vloc(), this->sfac(), this->gd(), this->tcb(), force_settings, this->ofs_running_ + const LR::ForceSettings force_settings{this->nspin, + this->inp_->test_force, + this->inp_->vl_in_h, + this->inp_->vh_in_h, + this->inp_->dft_functional}; + LR_Force force_terms( + *this->ucell_, + this->kv.kvec_d, + this->paraMat_, + *this->pw_rhod, + *this->pw_rho, + this->vloc(), + this->sfac(), + this->gd(), + this->tcb(), + force_settings, + this->ofs_running_ #ifdef __EXX - , inputs.exx_lri, inputs.hybrid_alpha + , + inputs.exx_lri, + inputs.hybrid_alpha #endif ); - const auto forces = LR::evaluate_closed_shell_force(inputs, force_terms, dm_gs, Xz, Z, omega, label_begin, ispin); + const auto forces = LR::evaluate_closed_shell_force( + inputs, + force_terms, + dm_gs, + Xz, + Z, + omega, + label_begin, + ispin); ModuleBase::timer::end("ESolver_LR", "cal_force_Xz"); return forces; } -template -void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispin, std::ofstream& ofs) +template +void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispin, std::ofstream &ofs) { const std::vector forces = this->cal_force(ispin); if (this->inp_->lr_degen_thr <= 0.0) @@ -172,12 +256,11 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi } // Rebuilt from scratch for this channel: a relaxation calls this once per ionic step, and a // stale multiplet from the previous geometry must not survive into the next one. - this->multiplet_lvc_.erase(std::remove_if(this->multiplet_lvc_.begin(), - this->multiplet_lvc_.end(), - [ispin](const MultipletLVC& m) { - return m.ispin == ispin; - }), - this->multiplet_lvc_.end()); + this->multiplet_lvc_.erase( + std::remove_if( + this->multiplet_lvc_.begin(), this->multiplet_lvc_.end(), + [ispin](const MultipletLVC &m) { return m.ispin == ispin; }), + this->multiplet_lvc_.end()); // The per-state gradients above are the diagonal of the degenerate-subspace gradient matrix in // whatever basis the eigensolver returned, so inside a multiplet only their trace means // anything. `lr_degen_thr` asks for the off-diagonal part too, which is the rest of the @@ -188,16 +271,15 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi { omega[ist] = this->pelec->ekb.c[ekb_off + ist]; } - const std::vector> groups - = LR::group_degenerate_states(omega, this->inp_->lr_degen_thr); - for (const std::vector& group : groups) + const std::vector> groups = LR::group_degenerate_states(omega, this->inp_->lr_degen_thr); + for (const std::vector &group : groups) { if (group.size() < 2) { continue; } std::vector diag; - for (const int ist: group) + for (const int ist : group) { diag.push_back(forces[ist]); } @@ -215,15 +297,21 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi } lvc.omega0 = sum / static_cast(group.size()); lvc.omega_spread = hi - lo; - lvc.g = this->cal_grad_matrix_degenerate(ispin, group, diag, ofs); + lvc.g = this->cal_grad_matrix_degenerate( + ispin, + group, + diag, + ofs); this->multiplet_lvc_.push_back(lvc); } } -template -std::vector> -ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, - const std::vector& group, const std::vector& diag, std::ofstream& ofs) +template +std::vector> ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate( + const int ispin, + const std::vector &group, + const std::vector &diag, + std::ofstream &ofs) { ModuleBase::TITLE("ESolver_LR", "cal_grad_matrix_degenerate"); ModuleBase::timer::start("ESolver_LR", "cal_grad_matrix_degenerate"); @@ -251,8 +339,8 @@ ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, { for (int l = k; l < d; ++l) { - const T* const xk = Xz.template data() + static_cast(k) * nloc_g; - const T* const xl = Xz.template data() + static_cast(l) * nloc_g; + const T *const xk = Xz.template data() + static_cast(k) * nloc_g; + const T *const xl = Xz.template data() + static_cast(l) * nloc_g; T loc = static_cast(0); for (int i = 0; i < nloc_g; ++i) { @@ -274,9 +362,8 @@ ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, omega_sum += omega; } const double omega_mean = omega_sum / static_cast(d); - ofs << " Degenerate multiplet of " << d << " states, Omega = " << omega_mean - << " Ry, spread = " << omega_spread << " Ry, max | - delta_kl| = " << max_ovlp_err - << std::endl; + ofs << " Degenerate multiplet of " << d << " states, Omega = " << omega_mean << " Ry, spread = " << omega_spread + << " Ry, max | - delta_kl| = " << max_ovlp_err << std::endl; // Dimensionless diagnostic tolerance for the orthonormality needed by X_plus. // This warning does not change the multiplet or the computed gradient. const double orthonormality_warn_tol = 1e-6; @@ -285,13 +372,12 @@ ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, ofs << " WARNING: this multiplet's eigenvectors are not orthonormal to" << " tolerance " << orthonormality_warn_tol << " (dimensionless overlap error); (X_k+X_l)/sqrt(2) may not be normalized" - << " and the assembled gradient matrix may consequently be inaccurate." - << std::endl; + << " and the assembled gradient matrix may consequently be inaccurate." << std::endl; } // 3. the $d(d-1)/2$ combinations $X_+=(X_k+X_l)/\sqrt2$, all in one Z-vector solve const int npair = static_cast(pairs.size()); - ct::Tensor Xp = LR_Util::newTensor({ npair, nloc_g }); + ct::Tensor Xp = LR_Util::newTensor({npair, nloc_g}); Xp.zero(); for (int ip = 0; ip < npair; ++ip) { @@ -303,18 +389,24 @@ ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, } const std::vector omega_pair(npair, omega_mean); const std::vector plus = this->openshell - ? this->cal_force_openshell_Xz(Xp, omega_pair, group[0]) - : this->cal_force_Xz(ispin, Xp, omega_pair, group[0]); + ? this->cal_force_openshell_Xz(Xp, omega_pair, group[0]) + : this->cal_force_Xz( + ispin, + Xp, + omega_pair, + group[0]); // 4. $G_{kl}=\mathcal F[X_+]-\tfrac12(G_{kk}+G_{ll})$ - const std::vector> g - = LR::assemble_grad_matrix(diag, plus, pairs); - print_grad_matrix(g, group, (*this->ucell_), ofs); + const std::vector> g = LR::assemble_grad_matrix(diag, plus, pairs); + print_grad_matrix( + g, + group, (*this->ucell_), + ofs); ModuleBase::timer::end("ESolver_LR", "cal_grad_matrix_degenerate"); return g; } -template +template std::vector ModuleESolver::ESolver_LR::cal_force_openshell(const int istate_only) { ModuleBase::TITLE("ESolver_LR", "cal_force_openshell"); @@ -338,9 +430,9 @@ std::vector ModuleESolver::ESolver_LR::cal_force_open return this->cal_force_openshell_Xz(Xz, omega_, ist_begin_); } -template +template std::vector ModuleESolver::ESolver_LR::cal_force_openshell_Xz( - const ct::Tensor& Xz, const std::vector& omega, const int label_begin) + const ct::Tensor &Xz, const std::vector &omega, const int label_begin) { ModuleBase::timer::start("ESolver_LR", "cal_force_openshell_Xz"); const int nst = static_cast(omega.size()); @@ -348,23 +440,48 @@ std::vector ModuleESolver::ESolver_LR::cal_force_open const ct::Tensor Z = this->solve_zvector_eqation(channel, nst, Xz); const auto dm_gs = this->cal_dm_gs(); const LR::GradientInputs inputs = this->gradient_inputs_(); - const LR::ForceSettings force_settings{this->nspin, this->inp_->test_force, - this->inp_->vl_in_h, this->inp_->vh_in_h, this->inp_->dft_functional}; - LR_Force force_terms(*this->ucell_, this->kv.kvec_d, this->paraMat_, - *this->pw_rhod, *this->pw_rho, this->vloc(), this->sfac(), this->gd(), this->tcb(), force_settings, this->ofs_running_ + const LR::ForceSettings force_settings{this->nspin, + this->inp_->test_force, + this->inp_->vl_in_h, + this->inp_->vh_in_h, + this->inp_->dft_functional}; + LR_Force force_terms( + *this->ucell_, + this->kv.kvec_d, + this->paraMat_, + *this->pw_rhod, + *this->pw_rho, + this->vloc(), + this->sfac(), + this->gd(), + this->tcb(), + force_settings, + this->ofs_running_ #ifdef __EXX - , inputs.exx_lri, inputs.hybrid_alpha + , + inputs.exx_lri, + inputs.hybrid_alpha #endif ); - const auto forces = LR::evaluate_open_shell_force(inputs, force_terms, dm_gs, Xz, Z, omega, label_begin); + const auto forces = LR::evaluate_open_shell_force( + inputs, + force_terms, + dm_gs, + Xz, + Z, + omega, + label_begin); ModuleBase::timer::end("ESolver_LR", "cal_force_openshell_Xz"); return forces; } -template -module_dm::DensityMatrix ModuleESolver::ESolver_LR::cal_dm_gs() +template module_dm::DensityMatrix ModuleESolver::ESolver_LR::cal_dm_gs() { - module_dm::DensityMatrix dm_gs(&this->paraMat_, this->nspin, this->kv.kvec_d, this->nk); + module_dm::DensityMatrix dm_gs( + &this->paraMat_, + this->nspin, + this->kv.kvec_d, + this->nk); // `psi_ks_all_` is distributed per `this->ks_->pv` on the ks-lr path (it is aliased straight // from the ground-state solver's own `psi`), but per `this->paraMat_all_` on the // read-from-file path (where it was allocated with that descriptor's own sizes). Using the @@ -372,30 +489,56 @@ module_dm::DensityMatrix ModuleESolver::ESolver_LR::cal_dm_gs( // assumption -- invisible at nprocs=1, where every descriptor degenerates to one block, but // silently wrong at nprocs>1. `refresh_from_ks_`/`fill_z_window_` already make this same // distinction for their `Cpxgemr2d` source descriptor; this mirrors it. - const Parallel_Orbitals* const pv_all = this->ks_ ? &this->ks_->pv : &this->paraMat_all_; - module_dm::dm_from_psi(pv_all, this->wg_ks_all, *this->psi_ks_all_, dm_gs); // nbands is important here - LR_Util::initialize_DMR(dm_gs, this->paraMat_, (*this->ucell_), this->gd(), this->orb_cutoff_); // nbands is not important here + const Parallel_Orbitals *const pv_all = this->ks_ ? &this->ks_->pv : &this->paraMat_all_; + module_dm::dm_from_psi( + pv_all, + this->wg_ks_all, + *this->psi_ks_all_, + dm_gs); // nbands is important here + LR_Util::initialize_DMR( + dm_gs, + this->paraMat_, (*this->ucell_), + this->gd(), + this->orb_cutoff_); // nbands is not important here dm_gs.cal_dmr(-1); return dm_gs; } -template -void ModuleESolver::ESolver_LR::test_force() +template void ModuleESolver::ESolver_LR::test_force() { - const LR::ForceSettings force_settings{this->nspin, this->inp_->test_force, - this->inp_->vl_in_h, this->inp_->vh_in_h, this->inp_->dft_functional}; - LR_Force lr_force((*this->ucell_), this->kv.kvec_d, this->paraMat_, *this->pw_rhod, *this->pw_rho, - this->vloc(), this->sfac(), this->gd(), this->tcb(), force_settings, this->ofs_running_ + const LR::ForceSettings force_settings{this->nspin, + this->inp_->test_force, + this->inp_->vl_in_h, + this->inp_->vh_in_h, + this->inp_->dft_functional}; + LR_Force lr_force( + (*this->ucell_), + this->kv.kvec_d, + this->paraMat_, + *this->pw_rhod, + *this->pw_rho, + this->vloc(), + this->sfac(), + this->gd(), + this->tcb(), + force_settings, + this->ofs_running_ #ifdef __EXX - , std::weak_ptr>(this->exx_lri), this->exx_info.info_global.hybrid_alpha + , + std::weak_ptr>(this->exx_lri), + this->exx_info.info_global.hybrid_alpha #endif ); - const module_dm::DensityMatrix& dm_gs = this->cal_dm_gs(); + const module_dm::DensityMatrix &dm_gs = this->cal_dm_gs(); // LR_Util::print_DMR(dm_gs, "DM(R) of ground state"); ///========================== test 1: reproduce the force of ground state ========================= // energy density matrix of the ground state - module_dm::DensityMatrix edm_gs(&this->paraMat_, this->nspin, this->kv.kvec_d, this->nk); //DX + module_dm::DensityMatrix edm_gs( + &this->paraMat_, + this->nspin, + this->kv.kvec_d, + this->nk); // DX ModuleBase::matrix wg_ekb_ks_all(nspin, this->inp_->nbands); const int occupation_count = nspin * this->inp_->nbands; for (int index = 0; index < occupation_count; ++index) @@ -404,23 +547,42 @@ void ModuleESolver::ESolver_LR::test_force() } // see `cal_dm_gs()`: `psi_ks_all_` is distributed per `this->ks_->pv` on the ks-lr path, // not `this->paraMat_all_`. - const Parallel_Orbitals* const pv_all_edm = this->ks_ ? &this->ks_->pv : &this->paraMat_all_; - module_dm::dm_from_psi(pv_all_edm, wg_ekb_ks_all, *this->psi_ks_all_, edm_gs); - LR_Util::initialize_DMR(edm_gs, this->paraMat_, (*this->ucell_), this->gd(), this->orb_cutoff_); + const Parallel_Orbitals *const pv_all_edm = this->ks_ ? &this->ks_->pv : &this->paraMat_all_; + module_dm::dm_from_psi( + pv_all_edm, + wg_ekb_ks_all, + *this->psi_ks_all_, + edm_gs); + LR_Util::initialize_DMR( + edm_gs, + this->paraMat_, (*this->ucell_), + this->gd(), + this->orb_cutoff_); edm_gs.cal_dmr(-1); // ground-state force ModuleBase::matrix force_gs = lr_force.reproduce_force_gs(kv, dm_gs, edm_gs); - ModuleIO::print_force(this->ofs_running_, (*this->ucell_), "Ground State FORCE (eV/Angstrom)", force_gs, false); + ModuleIO::print_force( + this->ofs_running_, (*this->ucell_), + "Ground State FORCE (eV/Angstrom)", + force_gs, + false); /// ======================================= END test 1 ========================================= ///========================== test 2: reproduce the DX Hartree term ========================= ModuleBase::matrix f_hxc_potgs = lr_force.reproduce_force_gs_loc(dm_gs, *this->pot_gs_hartree); - ModuleIO::print_force(this->ofs_running_, (*this->ucell_), "GS Hartree force calculated by 'cal_pulay_fs' from potential (eV/Angstrom)", f_hxc_potgs, false); + ModuleIO::print_force( + this->ofs_running_, (*this->ucell_), + "GS Hartree force calculated by 'cal_pulay_fs' from potential (eV/Angstrom)", + f_hxc_potgs, + false); ModuleBase::matrix f_hxc_potlr = lr_force.cal_force_hxc_dmtrans(dm_gs, *this->pot[0]); - ModuleIO::print_force(this->ofs_running_, (*this->ucell_), "GS Hxc force calculated by 'LR_Force' from kernel (eV/Angstrom)", f_hxc_potlr, false); + ModuleIO::print_force( + this->ofs_running_, (*this->ucell_), + "GS Hxc force calculated by 'LR_Force' from kernel (eV/Angstrom)", + f_hxc_potlr, + false); // `cal_force_hxc_dmtrans` now includes the Pulay -> Pulay+Hellmann-Feynman factor 2 itself, // so this must match the ground-state Hartree force directly (dm_gs is already symmetric). /// ======================================= END test 2 ========================================= - } template class ModuleESolver::ESolver_LR; diff --git a/source/source_esolver/esolver_lr_init.cpp b/source/source_esolver/esolver_lr_init.cpp index a33589d495..1eed70c2ec 100644 --- a/source/source_esolver/esolver_lr_init.cpp +++ b/source/source_esolver/esolver_lr_init.cpp @@ -1,21 +1,21 @@ #include "source_lcao/module_lr/init_helpers.h" // Initialize LR from an embedded KS solver or standalone ground-state files. #include "esolver_lr_lcao_tddft.h" +#include "source_base/module_external/scalapack_connector.h" #include "source_basis/module_pw/pw_basis_big.h" -#include "source_lcao/module_lr/utils/lr_util.h" -#include "source_lcao/module_lr/utils/lr_util_print.h" +#include "source_cell/module_neighbor/sltk_atom_arrange.h" #include "source_hamilt/module_gint/gint.h" #include "source_hamilt/module_xc/xc_functional.h" -#include "source_cell/module_neighbor/sltk_atom_arrange.h" #include "source_io/module_output/print_info.h" -#include "source_base/module_external/scalapack_connector.h" #include "source_io/module_parameter/parameter.h" +#include "source_lcao/module_lr/utils/lr_util.h" +#include "source_lcao/module_lr/utils/lr_util_print.h" #ifdef __JSON #include "source_io/module_json/output_info.h" #endif #ifdef __EXX -#include "source_lcao/module_ri/exx_lri_interface.h" #include "source_hamilt/module_xc/exx_info.h" +#include "source_lcao/module_ri/exx_lri_interface.h" #endif #include @@ -23,54 +23,59 @@ namespace { - /// One `Exx_LRI` carries ONE Coulomb operator, and it may be needed for two different - /// reasons: the LR kernel (when `xc_kernel` is a hybrid) and the ground-state force (when - /// `dft_functional` is a hybrid). That operator is NOT chosen here -- `Exx_LRI` reads - /// `info_ri.coulomb_param`, which `input_conv` builds from `dft_functional` alone. So when - /// the two disagree, the kernel silently gets the ground state's screening, not its own. - /// - /// This used to be decided by a local `exx_ccp_type()` returning Erfc for "hse" and bare - /// Hf otherwise, written onto `info_global.ccp_type`. With general range-separated hybrids - /// that two-way split is not even expressible ($\alpha/r+\beta\,\mathrm{erfc}(\mu r)/r$ - /// is both at once), and the write was in any case dead for the RI path: only `Exx_LRI` - /// runs here, and it never looks at `ccp_type`. - void warn_if_kernel_differs_from_gs(const std::string& xc_kernel, const std::string& dft_functional, - std::ofstream& ofs_running) +/// One `Exx_LRI` carries ONE Coulomb operator, and it may be needed for two different +/// reasons: the LR kernel (when `xc_kernel` is a hybrid) and the ground-state force (when +/// `dft_functional` is a hybrid). That operator is NOT chosen here -- `Exx_LRI` reads +/// `info_ri.coulomb_param`, which `input_conv` builds from `dft_functional` alone. So when +/// the two disagree, the kernel silently gets the ground state's screening, not its own. +/// +/// This used to be decided by a local `exx_ccp_type()` returning Erfc for "hse" and bare +/// Hf otherwise, written onto `info_global.ccp_type`. With general range-separated hybrids +/// that two-way split is not even expressible ($\alpha/r+\beta\,\mathrm{erfc}(\mu r)/r$ +/// is both at once), and the write was in any case dead for the RI path: only `Exx_LRI` +/// runs here, and it never looks at `ccp_type`. +void warn_if_kernel_differs_from_gs( + const std::string &xc_kernel, const std::string &dft_functional, std::ofstream &ofs_running) +{ + const bool k = LR::exx_kernel_list().count(xc_kernel) > 0; + const bool g = LR::exx_kernel_list().count(dft_functional) > 0; + if (k && xc_kernel != dft_functional) { - const bool k = LR::exx_kernel_list().count(xc_kernel) > 0; - const bool g = LR::exx_kernel_list().count(dft_functional) > 0; - if (k && xc_kernel != dft_functional) - { - ofs_running << " WARNING: xc_kernel (" << xc_kernel << ") and dft_functional (" - << dft_functional << ") are not the same functional. The Coulomb operator of" - " Exx_LRI follows dft_functional" << (g ? "" : ", which is not a hybrid at all" - " (no coulomb_param, so the LR exchange kernel vanishes)") << "; set both to the" - " same hybrid to get the kernel you asked for." << std::endl; - } + ofs_running << " WARNING: xc_kernel (" << xc_kernel << ") and dft_functional (" << dft_functional + << ") are not the same functional. The Coulomb operator of" + " Exx_LRI follows dft_functional" + << (g ? "" + : ", which is not a hybrid at all" + " (no coulomb_param, so the LR exchange kernel vanishes)") + << "; set both to the" + " same hybrid to get the kernel you asked for." + << std::endl; } } +} // namespace #endif #ifdef __EXX -template<> -void ModuleESolver::ESolver_LR::share_exx_lri(std::shared_ptr>& exx_ks) +template <> void ModuleESolver::ESolver_LR::share_exx_lri(std::shared_ptr> &exx_ks) { ModuleBase::TITLE("ESolver_LR", "share_exx_lri"); this->exx_lri = exx_ks->make_lr_workspace(*this->ucell_, this->kv); } -template<> -void ModuleESolver::ESolver_LR>::share_exx_lri(std::shared_ptr>>& exx_ks) +template <> +void ModuleESolver::ESolver_LR>::share_exx_lri( + std::shared_ptr>> &exx_ks) { ModuleBase::TITLE("ESolver_LR", "share_exx_lri"); this->exx_lri = exx_ks->make_lr_workspace(*this->ucell_, this->kv); } -template<> -void ModuleESolver::ESolver_LR>::share_exx_lri(std::shared_ptr>& exx_ks) +template <> +void ModuleESolver::ESolver_LR>::share_exx_lri(std::shared_ptr> &exx_ks) { - throw std::runtime_error("ESolver_LR>::share_exx_lri: cannot share double to std::complex"); + throw std::runtime_error( + "ESolver_LR>::share_exx_lri: cannot share double to std::complex"); } -template<> -void ModuleESolver::ESolver_LR::share_exx_lri(std::shared_ptr>>& exx_ks) +template <> +void ModuleESolver::ESolver_LR::share_exx_lri(std::shared_ptr>> &exx_ks) { throw std::runtime_error("ESolver_LR::share_exx_lri: cannot share std::complex to double"); } @@ -79,10 +84,10 @@ void ModuleESolver::ESolver_LR::share_exx_lri(std::shared_ptr -void ModuleESolver::ESolver_LR::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ModuleESolver::ESolver_LR::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); this->ucell_ = &ucell; this->inp_ = &inp; if (inp.esolver_type == "ks-lr") @@ -105,8 +110,7 @@ void ModuleESolver::ESolver_LR::before_all_runners(BaseCell& basecell, co } } -template -void ModuleESolver::ESolver_LR::bind_ground_state_aliases_() +template void ModuleESolver::ESolver_LR::bind_ground_state_aliases_() { if (this->ks_) { @@ -138,21 +142,21 @@ void ModuleESolver::ESolver_LR::bind_ground_state_aliases_() } template -void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, const Input_para& inp) +void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell &ucell, const Input_para &inp) { ModuleBase::TITLE("ESolver_LR", "ESolver_LR(KS)"); - ModuleESolver::ESolver_KS_LCAO& ks_sol = *this->ks_; + ModuleESolver::ESolver_KS_LCAO &ks_sol = *this->ks_; this->bind_ground_state_aliases_(); - if (this->inp_->lr_solver == "spectrum") - { - throw std::invalid_argument("when lr_solver==spectrum, esolver_type must be `lr` to skip KS calculation."); - } + if (this->inp_->lr_solver == "spectrum") + { + throw std::invalid_argument("when lr_solver==spectrum, esolver_type must be `lr` to skip KS calculation."); + } // xc kernel this->xc_kernel = LR_Util::tolower(inp.xc_kernel); - //kv - this->kv = ks_sol.kv; // copy: cheap, and the KS solver keeps using its own + // kv + this->kv = ks_sol.kv; // copy: cheap, and the KS solver keeps using its own LR::check_lr_parameters(*this->inp_, this->xc_kernel, this->nspin); @@ -160,17 +164,27 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons // KS and LR must use the same AO distribution, including its BLACS grid. const int ks_block_size = ks_sol.pv.get_block_size(); - LR_Util::setup_2d_division(this->paraMat_, ks_block_size, this->nbasis, this->nbasis + LR_Util::setup_2d_division( + this->paraMat_, + ks_block_size, + this->nbasis, + this->nbasis #ifdef __MPI - , ks_sol.pv.blacs_ctxt + , + ks_sol.pv.blacs_ctxt #endif ); this->set_parallel_orbitals_band(this->paraMat_, this->nbands); if (this->inp_->cal_force) { - LR_Util::setup_2d_division(this->paraMat_all_, ks_block_size, this->nbasis, this->nbasis + LR_Util::setup_2d_division( + this->paraMat_all_, + ks_block_size, + this->nbasis, + this->nbasis #ifdef __MPI - , ks_sol.pv.blacs_ctxt + , + ks_sol.pv.blacs_ctxt #endif ); this->set_parallel_orbitals_band(this->paraMat_all_, this->inp_->nbands); @@ -180,21 +194,32 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons this->paraMat_.atom_begin_col = ks_sol.pv.atom_begin_col; this->paraMat_.iat2iwt_ = ucell.get_iat2iwt(); - LR_Util::setup_2d_division(this->paraC_, ks_block_size, this->nbasis, this->nbands + LR_Util::setup_2d_division( + this->paraC_, + ks_block_size, + this->nbasis, + this->nbands #ifdef __MPI - , this->paraMat_.blacs_ctxt + , + this->paraMat_.blacs_ctxt #endif ); // allocate psi_ks and eig_ks in the [nocc, nvirt] window #ifdef __MPI - this->psi_ks.reset(new psi::Psi(this->kv.get_nks(), + this->psi_ks.reset(new psi::Psi( + this->kv.get_nks(), this->paraC_.get_col_size(), this->paraC_.get_row_size(), this->kv.ngk, true)); #else - this->psi_ks.reset(new psi::Psi(this->kv.get_nks(), this->nbands, this->nbasis, this->kv.ngk, true)); + this->psi_ks.reset(new psi::Psi( + this->kv.get_nks(), + this->nbands, + this->nbasis, + this->kv.ngk, + true)); #endif this->eig_ks.create(this->kv.get_nks(), this->nbands); this->pelec = new elecstate::ElecStateLCAO(); @@ -212,14 +237,14 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons // derives from dft_functional alone -- so whenever the ground-state solver has one of the // right type its geometry tensors are already up to date. Share those tensors in a // separate LR electronic workspace, skipping a `cal_exx_ions` per ionic step. - const bool share = (ks_sol.exx_nao.exd && std::is_same::value) - || (ks_sol.exx_nao.exc && std::is_same>::value); + const bool share = (ks_sol.exx_nao.exd && std::is_same::value) || + (ks_sol.exx_nao.exc && std::is_same>::value); warn_if_kernel_differs_from_gs(xc_kernel, dft_functional, this->ofs_running_); if (share) { this->exx_owned_ = false; - } // `refresh_from_ks_` refreshes the geometry snapshot - else // construct C, V from scratch + } // `refresh_from_ks_` refreshes the geometry snapshot + else // construct C, V from scratch { // `input_conv` already filled `info_ri.coulomb_param` from INPUT. exx_info.sync_from_global(); @@ -228,8 +253,12 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons exx_info.info_opt_abfs.files_abfs = ucell.abfs_orbital_files; exx_info.info_opt_abfs.files_jles = ucell.jle_orbital_files; this->exx_lri = std::make_shared>(exx_info.info_ri); - this->exx_lri->init(MPI_COMM_WORLD, ucell, this->kv, ks_sol.orb_); - this->exx_owned_ = true; // the position-dependent `cal_exx_ions` is left to `refresh_from_ks_` + this->exx_lri->init( + MPI_COMM_WORLD, + ucell, + this->kv, + ks_sol.orb_); + this->exx_owned_ = true; // the position-dependent `cal_exx_ions` is left to `refresh_from_ks_` } } #endif @@ -238,11 +267,10 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons this->ks_initialized_ = true; } -template -void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell& ucell) +template void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell &ucell) { ModuleBase::TITLE("ESolver_LR", "refresh_from_ks_"); - ModuleESolver::ESolver_KS_LCAO& ks_sol = *this->ks_; + ModuleESolver::ESolver_KS_LCAO &ks_sol = *this->ks_; // The ground-state solver owns `psi` and reuses it across ionic steps, so it cannot be stolen. // `eig_ks_all` / `wg_ks_all` are nspin x nbands matrices -- a few kB, copied rather than aliased // so that they survive the KS solver overwriting `pelec` on the next step. @@ -252,23 +280,33 @@ void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell& ucell) const int max_occupied_bands = *std::max_element(nocc.begin(), nocc.end()); const int start_band = this->nocc_max - max_occupied_bands; - for (int ik = 0;ik < this->kv.get_nks();++ik) + for (int ik = 0; ik < this->kv.get_nks(); ++ik) { // copy the KS orbitals in the [nocc, nvirt] window #ifdef __MPI this->psi_ks_all_->fix_k(ik); this->psi_ks->fix_k(ik); const int first_band = start_band + 1; - Cpxgemr2d(this->nbasis, this->nbands, this->psi_ks_all_->get_pointer(), 1, first_band, ks_sol.pv.desc_wfc, - this->psi_ks->get_pointer(), 1, 1, this->paraC_.desc, this->paraC_.blacs_ctxt); + Cpxgemr2d( + this->nbasis, + this->nbands, + this->psi_ks_all_->get_pointer(), + 1, + first_band, + ks_sol.pv.desc_wfc, + this->psi_ks->get_pointer(), + 1, + 1, + this->paraC_.desc, + this->paraC_.blacs_ctxt); #else // serial: each band is `nbasis` contiguous coefficients, so the window is a plain // band-by-band copy (this loop used to compute the two pointers and copy nothing, // leaving `psi_ks` uninitialized in every non-MPI build) - for (int ib = 0;ib < this->nbands;++ib) + for (int ib = 0; ib < this->nbands; ++ib) { - const auto* start = &(*this->psi_ks_all_)(ik, start_band + ib, 0); - auto* to = &(*this->psi_ks)(ik, ib, 0); + const auto *start = &(*this->psi_ks_all_)(ik, start_band + ib, 0); + auto *to = &(*this->psi_ks)(ik, ib, 0); std::copy(start, start + this->nbasis, to); } #endif @@ -281,28 +319,30 @@ void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell& ucell) if (nspin == 2) { - const int nupdown_now = LR_Util::spin_population_difference(ks_sol.pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); + const int nupdown_now = + LR_Util::spin_population_difference(ks_sol.pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); if (!this->ks_initialized_) { this->nupdown = nupdown_now; - reset_dim_spin2(); // shifts nocc/nvirt between the spin channels: must run exactly once + reset_dim_spin2(); // shifts nocc/nvirt between the spin channels: must run exactly once } else if (nupdown_now != this->nupdown) { - ModuleBase::WARNING_QUIT("ESolver_LR::refresh_from_ks_", + ModuleBase::WARNING_QUIT( + "ESolver_LR::refresh_from_ks_", "the ground-state spin population changed between ionic steps, but nocc/nvirt and" " the distributions built from them were fixed at the first step."); } } // `gint_info_` stays owned by the KS solver: its `before_scf` rebuilds and re-publishes it - //init potential and calculate kernels using ground state charge + // init potential and calculate kernels using ground state charge init_pot(*ks_sol.pelec->charge); #ifdef __EXX if (exx_kernel_list().count(xc_kernel) || (this->inp_->cal_force && gs_is_hybrid(this->inp_->dft_functional))) { if (this->exx_owned_) - { // Cs/Vs follow the atoms, so they are rebuilt for every geometry + { // Cs/Vs follow the atoms, so they are rebuilt for every geometry this->exx_lri->cal_exx_ions(ucell, this->inp_->out_ri_cv); } else if (ks_sol.exx_nao.exd) @@ -327,9 +367,8 @@ void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell& ucell) #endif } - template -void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell, const Input_para& inp) +void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell &ucell, const Input_para &inp) { ModuleBase::TITLE("ESolver_LR", "ESolver_LR(from scratch)"); this->bind_ground_state_aliases_(); @@ -345,17 +384,40 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell if (ModuleSymmetry::Symmetry::symm_flag == 1) { const int cal_symm_repr[2] = {this->inp_->cal_symm_repr[0], this->inp_->cal_symm_repr[1]}; - ucell.symm.analy_sys(ucell.lat, ucell.atoms, - ucell.nat, ucell.ntype, ucell.iat2it, ucell.iat2ia, ucell.itia2iat, - this->ofs_running_, - this->inp_->symmetry_prec, this->inp_->nspin, this->inp_->calculation, cal_symm_repr); + ucell.symm.analy_sys( + ucell.lat, + ucell.atoms, + ucell.nat, + ucell.ntype, + ucell.iat2it, + ucell.iat2ia, + ucell.itia2iat, + this->ofs_running_, + this->inp_->symmetry_prec, + this->inp_->nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(this->ofs_running_, "SYMMETRY"); } const bool use_ibz = false; const bool gamma_only_local = PARAM.globalv.gamma_only_local; const double kspacing[3] = {this->inp_->kspacing[0], this->inp_->kspacing[1], this->inp_->kspacing[2]}; const double koffset[3] = {this->inp_->koffset[0], this->inp_->koffset[1], this->inp_->koffset[2]}; - this->kv.set(ucell, ucell.symm, this->inp_->kpoint_file, this->inp_->nspin, ucell.G, ucell.latvec, this->ofs_running_, this->ofs_warning_, use_ibz, this->out_dir, gamma_only_local, kspacing, this->inp_->kmesh_type, koffset); + this->kv.set( + ucell, + ucell.symm, + this->inp_->kpoint_file, + this->inp_->nspin, + ucell.G, + ucell.latvec, + this->ofs_running_, + this->ofs_warning_, + use_ibz, + this->out_dir, + gamma_only_local, + kspacing, + this->inp_->kmesh_type, + koffset); ModuleBase::GlobalFunc::DONE(this->ofs_running_, "INIT K-POINTS"); ModuleIO::print_parameters(ucell, this->kv, inp); @@ -365,11 +427,22 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell two_center_bundle_own_.build_orb(ucell.ntype, ucell.orbital_fn.data(), inp.orbital_dir); LCAO_Orbitals orb; - two_center_bundle_own_.to_LCAO_Orbitals(orb, inp.lcao_ecut, inp.lcao_dk, inp.lcao_dr, inp.lcao_rmax, - inp.out_element_info, inp.cal_force); + two_center_bundle_own_.to_LCAO_Orbitals( + orb, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + inp.out_element_info, + inp.cal_force); orb_cutoff_ = orb.cutoffs(); // Standalone LR neighbor search needs projector metadata for every optical gauge. - LR::setup_nonlocal_info(orb, ucell, *this->inp_, this->my_rank_, this->ofs_running_); + LR::setup_nonlocal_info( + orb, + ucell, + *this->inp_, + this->my_rank_, + this->ofs_running_); const bool need_force_tables = this->inp_->cal_force || this->inp_->calculation == "relax"; const bool need_velocity_tables = LR_Util::tolower(this->inp_->abs_gauge) == "velocity"; if (need_force_tables || need_velocity_tables) @@ -379,25 +452,33 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell this->set_dimension(); // setup 2d-block distribution for AO-matrix and KS wfc - LR_Util::setup_2d_division(this->paraMat_, 1, this->nbasis, this->nbasis); + LR_Util::setup_2d_division( + this->paraMat_, + 1, + this->nbasis, + this->nbasis); this->set_parallel_orbitals_band(this->paraMat_, this->nbands); if (this->inp_->cal_force) { - LR_Util::setup_2d_division(this->paraMat_all_, 1, this->nbasis, this->nbasis); + LR_Util::setup_2d_division( + this->paraMat_all_, + 1, + this->nbasis, + this->nbasis); this->set_parallel_orbitals_band(this->paraMat_all_, this->inp_->nbands); } // read the ground state info // now ModuleIO::read_wfc_nao needs `Parallel_Orbitals` and can only read all the bands // it need improvement to read only the bands needed - this->psi_ks.reset(new psi::Psi(this->kv.get_nks(), - this->paraMat_.ncol_bands, - this->paraMat_.get_row_size(), - this->kv.ngk, - true)); + this->psi_ks.reset(new psi::Psi( + this->kv.get_nks(), + this->paraMat_.ncol_bands, + this->paraMat_.get_row_size(), + this->kv.ngk, + true)); this->read_ks_wfc(); - if (nspin == 2) { // Complete file populations were read before selecting the occupied window. @@ -410,18 +491,24 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell this->fill_z_window_(nullptr); #endif - LR_Util::setup_2d_division(this->paraC_, 1, this->nbasis, this->nbands + LR_Util::setup_2d_division( + this->paraC_, + 1, + this->nbasis, + this->nbands #ifdef __MPI - , paraMat_.blacs_ctxt + , + paraMat_.blacs_ctxt #endif ); // clear ks info, new elecstate for excition - delete this->pelec; // the ElecStateLCAO allocated above, only needed while reading the KS data + delete this->pelec; // the ElecStateLCAO allocated above, only needed while reading the KS data this->pelec = new elecstate::ElecState(); // read the ground state charge density and calculate xc kernel - pgrid().init(this->pw_rho->nx, + pgrid().init( + this->pw_rho->nx, this->pw_rho->ny, this->pw_rho->nz, this->pw_rho->nplane, @@ -438,19 +525,20 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell // search adjacent atoms and init Gint double search_radius = -1.0; - search_radius = atom_arrange::set_sr_NL(this->ofs_running_, + search_radius = atom_arrange::set_sr_NL( + this->ofs_running_, this->inp_->out_level, orb.get_rcutmax_Phi(), ucell.infoNL->get_rcutmax_Beta(), PARAM.globalv.gamma_only_local); - atom_arrange::search(PARAM.globalv.search_pbc, - this->ofs_running_, - this->gd(), - *this->ucell_, - search_radius, - this->inp_->test_atom_input); - gint_info_.reset( - new ModuleGint::GintInfo( + atom_arrange::search( + PARAM.globalv.search_pbc, + this->ofs_running_, + this->gd(), + *this->ucell_, + search_radius, + this->inp_->test_atom_input); + gint_info_.reset(new ModuleGint::GintInfo( this->pw_big->nbx, this->pw_big->nby, this->pw_big->nbz, @@ -477,8 +565,8 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell // 1. EXX xc_kernel // 2. cal_force with ground state with EXX functional #ifdef __EXX - if (((exx_kernel_list().count(xc_kernel)) && this->inp_->lr_solver != "spectrum") - || (this->inp_->cal_force && gs_is_hybrid(this->inp_->dft_functional))) + if (((exx_kernel_list().count(xc_kernel)) && this->inp_->lr_solver != "spectrum") || + (this->inp_->cal_force && gs_is_hybrid(this->inp_->dft_functional))) { warn_if_kernel_differs_from_gs(xc_kernel, LR_Util::tolower(this->inp_->dft_functional), this->ofs_running_); // `input_conv` already filled `info_ri.coulomb_param` from INPUT. @@ -488,12 +576,16 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell exx_info.info_opt_abfs.files_abfs = ucell.abfs_orbital_files; exx_info.info_opt_abfs.files_jles = ucell.jle_orbital_files; this->exx_lri = std::make_shared>(exx_info.info_ri); - this->exx_lri->init(MPI_COMM_WORLD, ucell,this->kv, orb); - this->exx_lri->cal_exx_ions(ucell,this->inp_->out_ri_cv); + this->exx_lri->init( + MPI_COMM_WORLD, + ucell, + this->kv, + orb); + this->exx_lri->cal_exx_ions(ucell, this->inp_->out_ri_cv); } // else #endif - // ModuleBase::Ylm::set_coefficients() is deprecated + // ModuleBase::Ylm::set_coefficients() is deprecated } template class ModuleESolver::ESolver_LR; diff --git a/source/source_esolver/esolver_lr_lcao_bse.cpp b/source/source_esolver/esolver_lr_lcao_bse.cpp index be778ecdf2..07439711fc 100644 --- a/source/source_esolver/esolver_lr_lcao_bse.cpp +++ b/source/source_esolver/esolver_lr_lcao_bse.cpp @@ -1,30 +1,32 @@ -#include "source_lcao/module_lr/init_helpers.h" #include "esolver_lr_lcao_bse.h" -#include + #include "source_basis/module_pw/pw_basis_big.h" #include "source_cell/module_neighbor/sltk_atom_arrange.h" -#include "source_io/module_parameter/parameter.h" -#include "source_io/module_output/print_info.h" #include "source_hamilt/module_gint/gint.h" +#include "source_io/module_output/print_info.h" +#include "source_io/module_parameter/parameter.h" #include "source_lcao/module_bse/hamilt_bse.h" +#include "source_lcao/module_lr/init_helpers.h" #include "source_lcao/module_lr/lr_spectrum.h" #include "source_lcao/module_lr/utils/exciton_plotter.h" #include "source_lcao/module_lr/utils/lr_io.h" -#include "source_lcao/module_lr/utils/lr_util_print.h" #include "source_lcao/module_lr/utils/lr_util.hpp" +#include "source_lcao/module_lr/utils/lr_util_print.h" + +#include namespace ModuleESolver { template -void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_BSE::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_BSE", "before_all_runners"); ModuleBase::timer::start("ESolver_BSE", "before_all_runners"); - this->bind_ground_state_aliases_(); // BSE always owns its grid/orbital objects (no `ks_`) + this->bind_ground_state_aliases_(); // BSE always owns its grid/orbital objects (no `ks_`) this->ucell_ = &ucell; // xc kernel this->xc_kernel = LR_Util::tolower(inp.xc_kernel); @@ -33,8 +35,13 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para ModuleESolver::ESolver_FP::before_all_runners(basecell, inp); this->pelec = new elecstate::ElecStateLCAO(); - this->kRlist = LR_IO::RI_kRlist(*this->ucell_, &this->kv, this->nspin, - this->rpa_dir, this->out_dir, inp.bse_use_fine_kgrid); + this->kRlist = LR_IO::RI_kRlist( + *this->ucell_, + &this->kv, + this->nspin, + this->rpa_dir, + this->out_dir, + inp.bse_use_fine_kgrid); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "Set K-POINTS and R-list for RI"); ModuleIO::print_parameters(ucell, this->kv, inp); @@ -43,11 +50,22 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para /// read orbitals and build the interpolation table this->two_center_bundle_own_.build_orb(ucell.ntype, ucell.orbital_fn.data(), inp.orbital_dir); - this->two_center_bundle_own_.to_LCAO_Orbitals(this->orb_, inp.lcao_ecut, inp.lcao_dk, inp.lcao_dr, inp.lcao_rmax, - inp.out_element_info, inp.cal_force); + this->two_center_bundle_own_.to_LCAO_Orbitals( + this->orb_, + inp.lcao_ecut, + inp.lcao_dk, + inp.lcao_dr, + inp.lcao_rmax, + inp.out_element_info, + inp.cal_force); this->orb_cutoff_ = this->orb_.cutoffs(); // Neighbor search needs nonlocal-projector metadata even without optical output. - LR::setup_nonlocal_info(this->orb_, ucell, *this->inp_, this->my_rank_, this->ofs_running_); + LR::setup_nonlocal_info( + this->orb_, + ucell, + *this->inp_, + this->my_rank_, + this->ofs_running_); if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { LR::setup_2center_table(this->two_center_bundle_own_, ucell, *this->inp_); @@ -55,7 +73,11 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para this->set_dimension(); // setup 2d-block distribution for AO-matrix and KS wfc - LR_Util::setup_2d_division(this->paraMat_, 1, this->nbasis, this->nbasis); + LR_Util::setup_2d_division( + this->paraMat_, + 1, + this->nbasis, + this->nbasis); #ifdef __MPI this->paraMat_.set_desc_wfc_Eij(this->nbasis, this->nbands, this->paraMat_.get_row_size()); int err = this->paraMat_.set_nloc_wfc_Eij(this->nbands, GlobalV::ofs_running, GlobalV::ofs_warning); @@ -65,80 +87,92 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para this->paraMat_.ncol_bands = this->nbands; #endif - this->psi_ks.reset(new psi::Psi(this->kv.get_nks(), - this->paraMat_.ncol_bands, - this->paraMat_.get_row_size(), - this->kv.ngk, - true)); - this->psi_ks_global = new psi::Psi(this->kv.get_nks(), - this->nbands, - this->nbasis, - this->kv.ngk, - true); + this->psi_ks.reset(new psi::Psi( + this->kv.get_nks(), + this->paraMat_.ncol_bands, + this->paraMat_.get_row_size(), + this->kv.ngk, + true)); + this->psi_ks_global = new psi::Psi( + this->kv.get_nks(), + this->nbands, + this->nbasis, + this->kv.ngk, + true); this->read_ks_wfc(); // NOTE: openshell is not implemented in BSE if (this->nspin == 2) { - this->nupdown = LR_Util::spin_population_difference(this->pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); + this->nupdown = + LR_Util::spin_population_difference(this->pelec->wg, this->kv.para_k.kpar, this->kv.para_k.rank_in_pool); this->reset_dim_spin2(); } - LR_Util::setup_2d_division(this->paraC_, this->paraMat_.get_block_size(), this->nbasis, this->nbands + LR_Util::setup_2d_division( + this->paraC_, + this->paraMat_.get_block_size(), + this->nbasis, + this->nbands #ifdef __MPI - , this->paraMat_.blacs_ctxt + , + this->paraMat_.blacs_ctxt #endif - ); + ); - this->pgrid().init(this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz, - this->pw_rho->nplane, - this->pw_rho->nrxx, - this->pw_big->nbz, - this->pw_big->bz, - GlobalV::NPROC); + this->pgrid().init( + this->pw_rho->nx, + this->pw_rho->ny, + this->pw_rho->nz, + this->pw_rho->nplane, + this->pw_rho->nrxx, + this->pw_big->nbz, + this->pw_big->bz, + GlobalV::NPROC); // search adjacent atoms and init Gint double search_radius = -1.0; - search_radius = atom_arrange::set_sr_NL(GlobalV::ofs_running, - inp.out_level, - this->orb_.get_rcutmax_Phi(), - ucell.infoNL->get_rcutmax_Beta(), - PARAM.globalv.gamma_only_local); - atom_arrange::search(PARAM.globalv.search_pbc, - GlobalV::ofs_running, - this->gd(), - *this->ucell_, - search_radius, - inp.test_atom_input); - - this->gint_info_.reset(new ModuleGint::GintInfo( - this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbz, - this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz, - 0, - 0, - this->pw_big->nbzp_start, - this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbzp, - this->orb_.Phi, - ucell, - this->gd(), - inp.nspin, - PARAM.globalv.gamma_only_local, - PARAM.globalv.domag, - inp.device == "gpu", - inp.nstream)); - ModuleGint::Gint::set_gint_info(this->gint_info_.get()); + search_radius = atom_arrange::set_sr_NL( + GlobalV::ofs_running, + inp.out_level, + this->orb_.get_rcutmax_Phi(), + ucell.infoNL->get_rcutmax_Beta(), + PARAM.globalv.gamma_only_local); + atom_arrange::search( + PARAM.globalv.search_pbc, + GlobalV::ofs_running, + this->gd(), + *this->ucell_, + search_radius, + inp.test_atom_input); + + this->gint_info_.reset(new ModuleGint::GintInfo( + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbz, + this->pw_rho->nx, + this->pw_rho->ny, + this->pw_rho->nz, + 0, + 0, + this->pw_big->nbzp_start, + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbzp, + this->orb_.Phi, + ucell, + this->gd(), + inp.nspin, + PARAM.globalv.gamma_only_local, + PARAM.globalv.domag, + inp.device == "gpu", + inp.nstream)); + ModuleGint::Gint::set_gint_info(this->gint_info_.get()); this->pot.resize(this->nspin, nullptr); if (this->inp_->lr_solver != "spectrum" && this->inp_->lr_solver != "plot") { - this->mo_lri = LR_Util::make_unique>(*this->ucell_, + this->mo_lri = LR_Util::make_unique>( + *this->ucell_, this->nk, this->kRlist, this->nocc[0], @@ -161,25 +195,24 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para ModuleBase::timer::end("ESolver_BSE", "before_all_runners"); } -template -void ESolver_BSE::runner(BaseCell& basecell, const int istep) +template void ESolver_BSE::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_BSE", "runner"); ModuleBase::timer::start("ESolver_BSE", "runner"); - //allocate 2-particle state and setup 2d division + // allocate 2-particle state and setup 2d division this->allocate_eigen_infos(); - auto efile_out = [&](const std::string& label)->std::string { - return this->out_dir + "Excitation_Energy_" + label + ".dat";}; - auto vfile_out = [&](const std::string& label)->std::string { - return this->out_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(GlobalV::MY_RANK+1) + ".dat";}; - auto efile_in = [&](const std::string& label)->std::string { - return this->in_dir + "Excitation_Energy_" + label + ".dat";}; - auto vfile_in = [&](const std::string& label)->std::string { - return this->in_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(GlobalV::MY_RANK+1) + ".dat";}; + auto efile_out = [&](const std::string &label) -> std::string + { return this->out_dir + "Excitation_Energy_" + label + ".dat"; }; + auto vfile_out = [&](const std::string &label) -> std::string + { return this->out_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(GlobalV::MY_RANK + 1) + ".dat"; }; + auto efile_in = [&](const std::string &label) -> std::string + { return this->in_dir + "Excitation_Energy_" + label + ".dat"; }; + auto vfile_in = [&](const std::string &label) -> std::string + { return this->in_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(GlobalV::MY_RANK + 1) + ".dat"; }; if (this->inp_->lr_solver == "elpa") { @@ -192,48 +225,91 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) std::cout << "Calculating Casida/BSE matrix directly." << std::endl; assert(this->xc_kernel == "bse"); this->lri_init(); - BSE::HamiltBSE bse_matrix(this->nspin, this->nbasis, this->nocc, this->nvirt, *this->ucell_, - this->orb_cutoff_, this->gd(), *this->psi_ks, *this->psi_ks_global, this->eig_gw, - *this->mo_lri, - this->pot[0], this->kv, this->paraX_, this->paraC_, this->paraMat_, - this->inp_->bse_spin_types, - this->inp_->bse_tda, - this->inp_->bse_ri_hartree, - this->inp_->bse_mem_save, - this->inp_->bse_continue, - this->inp_->out_bse_ab, - this->out_dir, - this->in_dir, - GlobalV::MY_RANK, - GlobalV::NPROC, - this->inp_->ri_hartree_benchmark); - - auto write_tda_states = [&](const std::string& label, - const Real* e, - const T* v, - const int& dim, - const int& nst, - const int& prec = 8) -> void { + BSE::HamiltBSE bse_matrix( + this->nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->ucell_, + this->orb_cutoff_, + this->gd(), + *this->psi_ks, + *this->psi_ks_global, + this->eig_gw, + *this->mo_lri, + this->pot[0], + this->kv, + this->paraX_, + this->paraC_, + this->paraMat_, + this->inp_->bse_spin_types, + this->inp_->bse_tda, + this->inp_->bse_ri_hartree, + this->inp_->bse_mem_save, + this->inp_->bse_continue, + this->inp_->out_bse_ab, + this->out_dir, + this->in_dir, + GlobalV::MY_RANK, + GlobalV::NPROC, + this->inp_->ri_hartree_benchmark); + + auto write_tda_states = [&](const std::string &label, + const Real *e, + const T *v, + const int &dim, + const int &nst, + const int &prec = 8) -> void + { if (GlobalV::MY_RANK == 0) { - assert(nst == LR_Util::write_value(efile_out(label), prec, e, nst)); + assert( + nst == LR_Util::write_value( + efile_out(label), + prec, + e, + nst)); } - assert(nst * dim == LR_Util::write_value(vfile_out(label), prec, v, nst, dim)); + assert( + nst * dim == LR_Util::write_value( + vfile_out(label), + prec, + v, + nst, + dim)); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "write tda states " + label); }; - auto write_full_states = [&](const std::string& label, - const Real* e, - const T* X, - const T* Y, - const int& dim, - const int& nst, - const int& prec = 8) -> void { + auto write_full_states = [&](const std::string &label, + const Real *e, + const T *X, + const T *Y, + const int &dim, + const int &nst, + const int &prec = 8) -> void + { if (GlobalV::MY_RANK == 0) { - assert(nst == LR_Util::write_value(efile_out("full_"+label), prec, e, nst)); + assert( + nst == LR_Util::write_value( + efile_out("full_" + label), + prec, + e, + nst)); } - assert(nst * dim == LR_Util::write_value(vfile_out("full_X_"+label), prec, X, nst, dim)); - assert(nst * dim == LR_Util::write_value(vfile_out("full_Y_"+label), prec, Y, nst, dim)); + assert( + nst * dim == LR_Util::write_value( + vfile_out("full_X_" + label), + prec, + X, + nst, + dim)); + assert( + nst * dim == LR_Util::write_value( + vfile_out("full_Y_" + label), + prec, + Y, + nst, + dim)); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "write full states " + label); }; @@ -241,10 +317,11 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) { for (int is = 0; is < this->inp_->bse_spin_types.size(); ++is) { - bse_matrix.tda_solver(is, - this->nstates, - &this->tda_ene[is * this->nstates], - this->X[is].template data()); + bse_matrix.tda_solver( + is, + this->nstates, + &this->tda_ene[is * this->nstates], + this->X[is].template data()); std::cout << "eigenvalues: (Ry)" << std::endl; int write_nstates = std::min(this->nstates, 20); @@ -260,11 +337,12 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) if (this->inp_->out_wfc_lr) { - write_tda_states(this->inp_->bse_spin_types[is], - &this->tda_ene[is * this->nstates], - this->X[is].template data(), - this->nloc_per_state, - this->nstates); + write_tda_states( + this->inp_->bse_spin_types[is], + &this->tda_ene[is * this->nstates], + this->X[is].template data(), + this->nloc_per_state, + this->nstates); } malloc_trim(0); } @@ -273,11 +351,12 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) { for (int is = 0; is < this->inp_->bse_spin_types.size(); ++is) { - bse_matrix.full_solver(is, - this->nstates, - &this->full_ene[is * this->nstates], - this->full_X[is].template data(), - this->full_Y[is].template data()); + bse_matrix.full_solver( + is, + this->nstates, + &this->full_ene[is * this->nstates], + this->full_X[is].template data(), + this->full_Y[is].template data()); std::cout << "eigenvalues: (Ry)" << std::endl; int write_nstates = std::min(this->nstates, 20); @@ -292,12 +371,13 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) if (this->inp_->out_wfc_lr) { - write_full_states(this->inp_->bse_spin_types[is], - &this->full_ene[is * this->nstates], - this->full_X[is].template data(), - this->full_Y[is].template data(), - this->nloc_per_state, - this->nstates); + write_full_states( + this->inp_->bse_spin_types[is], + &this->full_ene[is * this->nstates], + this->full_X[is].template data(), + this->full_Y[is].template data(), + this->nloc_per_state, + this->nstates); } malloc_trim(0); } @@ -307,64 +387,104 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) else if (this->inp_->lr_solver == "spectrum" || this->inp_->lr_solver == "plot") { std::cout << "Reading BSE excitation states from file." << std::endl; - auto read_tda_states = [&](const std::string& label, Real* e, T* v, const int& dim, const int& nst)->void + auto read_tda_states = [&](const std::string &label, + Real *e, + T *v, + const int &dim, + const int &nst) -> void { - if (GlobalV::MY_RANK == 0) { + if (GlobalV::MY_RANK == 0) + { assert(nst == LR_Util::read_value(efile_in(label), e, nst)); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + efile_in(label)); } #ifdef __MPI - MPI_Bcast(e, nst, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast( + e, + nst, + MPI_DOUBLE, + 0, + MPI_COMM_WORLD); #endif - assert(nst * dim == LR_Util::read_value(vfile_in(label), v, nst, dim)); + assert( + nst * dim == LR_Util::read_value( + vfile_in(label), + v, + nst, + dim)); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + vfile_in(label)); }; - auto read_full_states = [&](const std::string& label, Real* e, T* X, T* Y, const int& dim, const int& nst)->void + auto read_full_states = [&](const std::string &label, + Real *e, + T *X, + T *Y, + const int &dim, + const int &nst) -> void { - if (GlobalV::MY_RANK == 0) { - assert(nst == LR_Util::read_value(efile_in("full_"+label), e, nst)); - ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + efile_in("full_"+label)); + if (GlobalV::MY_RANK == 0) + { + assert(nst == LR_Util::read_value(efile_in("full_" + label), e, nst)); + ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + efile_in("full_" + label)); } #ifdef __MPI - MPI_Bcast(e, nst, MPI_DOUBLE, 0, MPI_COMM_WORLD); + MPI_Bcast( + e, + nst, + MPI_DOUBLE, + 0, + MPI_COMM_WORLD); #endif - assert(nst * dim == LR_Util::read_value(vfile_in("full_X_"+label), X, nst, dim)); - ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + vfile_in("full_X_"+label)); - assert(nst * dim == LR_Util::read_value(vfile_in("full_Y_"+label), Y, nst, dim)); - ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + vfile_in("full_Y_"+label)); + assert( + nst * dim == LR_Util::read_value( + vfile_in("full_X_" + label), + X, + nst, + dim)); + ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + vfile_in("full_X_" + label)); + assert( + nst * dim == LR_Util::read_value( + vfile_in("full_Y_" + label), + Y, + nst, + dim)); + ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "finish reading " + vfile_in("full_Y_" + label)); }; if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "tda") { for (int is = 0; is < this->inp_->bse_spin_types.size(); ++is) { - read_tda_states(this->inp_->bse_spin_types[is], - &this->tda_ene[is * this->nstates], - this->X[is].template data(), - this->nloc_per_state, - this->nstates); + read_tda_states( + this->inp_->bse_spin_types[is], + &this->tda_ene[is * this->nstates], + this->X[is].template data(), + this->nloc_per_state, + this->nstates); } } if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "full") { for (int is = 0; is < this->inp_->bse_spin_types.size(); ++is) { - read_full_states(this->inp_->bse_spin_types[is], - &this->full_ene[is * this->nstates], - this->full_X[is].template data(), - this->full_Y[is].template data(), - this->nloc_per_state, - this->nstates); + read_full_states( + this->inp_->bse_spin_types[is], + &this->full_ene[is * this->nstates], + this->full_X[is].template data(), + this->full_Y[is].template data(), + this->nloc_per_state, + this->nstates); // check whether |X|^2 - |Y|^2 = 1 - for (int i = 0; i < this->nstates; ++i) + for (int i = 0; i < this->nstates; ++i) { double norm_xy = 0.0; - for (int j = 0; j < this->nloc_per_state; ++j) { - norm_xy += std::norm(this->full_X[is].template data()[i * this->nloc_per_state + j]) - - std::norm(this->full_Y[is].template data()[i * this->nloc_per_state + j]); + for (int j = 0; j < this->nloc_per_state; ++j) + { + norm_xy += std::norm(this->full_X[is].template data()[i * this->nloc_per_state + j]) - + std::norm(this->full_Y[is].template data()[i * this->nloc_per_state + j]); } Parallel_Reduce::reduce_all(norm_xy); - if (std::abs(norm_xy - 1.0) > 1e-6){ + if (std::abs(norm_xy - 1.0) > 1e-6) + { std::cout << "| CHECK WARNING: for full excitation " << i << ", |X|^2 - |Y|^2 = " << std::setprecision(10) << norm_xy << std::endl; } @@ -380,16 +500,15 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) return; } -template -void ESolver_BSE::after_all_runners(BaseCell& basecell) +template void ESolver_BSE::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_BSE", "after_all_runners"); ModuleBase::timer::start("ESolver_BSE", "after_all_runners"); - const std::string& output_dir = this->out_dir; - const std::set benchmarks = {"abacus-librpa", "abacus", "none" }; + const std::string &output_dir = this->out_dir; + const std::set benchmarks = {"abacus-librpa", "abacus", "none"}; if (benchmarks.find(this->inp_->ri_hartree_benchmark) == benchmarks.end()) { return; @@ -400,13 +519,27 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) for (int is = 0; is < this->X.size(); ++is) { std::cout << "plot BSE exciton wavefunction for state: " << this->inp_->plot_istate - << ", spin type: " << this->inp_->bse_spin_types[is] << std::endl; - LR_Util::ExcitonPlotter eplot(this->nspin, this->nbasis, this->nocc, this->nvirt, *this->psi_ks, - *this->ucell_, this->kv, this->gd(), this->orb_cutoff_, this->pgrid(), *this->pw_rho, - this->paraX_, this->paraC_, this->paraMat_, - output_dir, - &this->tda_ene[is * this->nstates], this->X[is].template data(), - false/*openshell*/, &this->orb_); + << ", spin type: " << this->inp_->bse_spin_types[is] << std::endl; + LR_Util::ExcitonPlotter eplot( + this->nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->psi_ks, + *this->ucell_, + this->kv, + this->gd(), + this->orb_cutoff_, + this->pgrid(), + *this->pw_rho, + this->paraX_, + this->paraC_, + this->paraMat_, + output_dir, + &this->tda_ene[is * this->nstates], + this->X[is].template data(), + false /*openshell*/, + &this->orb_); const std::string plot_type = LR_Util::tolower(this->inp_->exciton_plot_type); const std::string plot_format = LR_Util::tolower(this->inp_->exciton_plot_format); const bool write_slice = (plot_format == "slice" || plot_format == "both"); @@ -422,8 +555,7 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) if (plot_format != "slice") { ModuleBase::WARNING_QUIT( - "ESolver_BSE", - "conditional exciton density only supports exciton_plot_format = slice"); + "ESolver_BSE", "conditional exciton density only supports exciton_plot_format = slice"); } if (this->inp_->exciton_fixed_coordinate.size() != 6) { @@ -432,21 +564,25 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) "exciton_fixed_coordinate must contain six values: hole x y z followed by electron x y z"); } const std::array r_h_fix = {this->inp_->exciton_fixed_coordinate[0], - this->inp_->exciton_fixed_coordinate[1], - this->inp_->exciton_fixed_coordinate[2]}; + this->inp_->exciton_fixed_coordinate[1], this->inp_->exciton_fixed_coordinate[2]}; const std::array r_e_fix = {this->inp_->exciton_fixed_coordinate[3], - this->inp_->exciton_fixed_coordinate[4], - this->inp_->exciton_fixed_coordinate[5]}; - eplot.plot_cond_slice(this->inp_->plot_istate, r_h_fix, + this->inp_->exciton_fixed_coordinate[4], this->inp_->exciton_fixed_coordinate[5]}; + eplot.plot_cond_slice( + this->inp_->plot_istate, + r_h_fix, this->inp_->exciton_slice_plane, this->inp_->exciton_slice_pos, this->inp_->exciton_slice_npoints, - this->inp_->exciton_slice_range, "elec"); - eplot.plot_cond_slice(this->inp_->plot_istate, r_e_fix, + this->inp_->exciton_slice_range, + "elec"); + eplot.plot_cond_slice( + this->inp_->plot_istate, + r_e_fix, this->inp_->exciton_slice_plane, this->inp_->exciton_slice_pos, this->inp_->exciton_slice_npoints, - this->inp_->exciton_slice_range, "hole"); + this->inp_->exciton_slice_range, + "hole"); } else if (plot_type == "average") { @@ -459,12 +595,16 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) } if (write_slice) { - eplot.plot_average_slice(this->inp_->plot_istate, "hole", + eplot.plot_average_slice( + this->inp_->plot_istate, + "hole", this->inp_->exciton_slice_plane, this->inp_->exciton_slice_pos, this->inp_->exciton_slice_npoints, this->inp_->exciton_slice_range); - eplot.plot_average_slice(this->inp_->plot_istate, "elec", + eplot.plot_average_slice( + this->inp_->plot_istate, + "elec", this->inp_->exciton_slice_plane, this->inp_->exciton_slice_pos, this->inp_->exciton_slice_npoints, @@ -486,57 +626,93 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) { for (int is = 0; is < this->X.size(); ++is) { - const double* const energies = &this->tda_ene[is * this->nstates]; + const double *const energies = &this->tda_ene[is * this->nstates]; const std::string channel = this->inp_->bse_spin_types[is] + "_tda"; - LR_Util::print_excitation_energies(this->ofs_running_, energies, this->nstates, channel); + LR_Util::print_excitation_energies( + this->ofs_running_, + energies, + this->nstates, + channel); } } if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "full") { for (int is = 0; is < this->full_X.size(); ++is) { - const double* const energies = &this->full_ene[is * this->nstates]; + const double *const energies = &this->full_ene[is * this->nstates]; const std::string channel = this->inp_->bse_spin_types[is] + "_full"; - LR_Util::print_excitation_energies(this->ofs_running_, energies, this->nstates, channel); + LR_Util::print_excitation_energies( + this->ofs_running_, + energies, + this->nstates, + channel); } } } else { std::cout << "Calculating BSE optical absorption spectrum." << std::endl; - if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity" ) + if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { const int nspin_tmp = this->inp_->nspin == 2 ? 2 : 1; - this->velocity_mo = LR_Util::cal_velocity_mo(*this->ucell_, this->gd(), this->tcb(), - this->paraMat_, this->paraC_, this->kv, *this->psi_ks, - this->nk, nspin_tmp, this->nbasis, this->nocc, this->nvirt); + this->velocity_mo = LR_Util::cal_velocity_mo( + *this->ucell_, + this->gd(), + this->tcb(), + this->paraMat_, + this->paraC_, + this->kv, + *this->psi_ks, + this->nk, + nspin_tmp, + this->nbasis, + this->nocc, + this->nvirt); } if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "tda") { for (int is = 0; is < this->X.size(); ++is) { - LR::LR_Spectrum spectrum(this->nspin, this->nbasis, this->nocc, this->nvirt, *this->pw_rho, *this->psi_ks, - *this->ucell_, this->kv, this->gd(), this->orb_cutoff_, this->tcb(), - this->paraX_, this->paraC_, this->paraMat_, - &this->tda_ene[is * this->nstates], this->eig_ks.c, - this->X[is].template data(), this->nstates, false/*openshell*/, - LR_Util::tolower(this->inp_->abs_gauge), GlobalV::MY_RANK, output_dir); + LR::LR_Spectrum spectrum( + this->nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->pw_rho, + *this->psi_ks, + *this->ucell_, + this->kv, + this->gd(), + this->orb_cutoff_, + this->tcb(), + this->paraX_, + this->paraC_, + this->paraMat_, + &this->tda_ene[is * this->nstates], + this->eig_ks.c, + this->X[is].template data(), + this->nstates, + false /*openshell*/, + LR_Util::tolower(this->inp_->abs_gauge), + GlobalV::MY_RANK, + output_dir); if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { spectrum.set_vmo(this->velocity_mo.data()); } spectrum.cal_spectrum(); - spectrum.transition_analysis(this->inp_->bse_spin_types[is]+"_tda"); - if (this->inp_->bse_spin_types[is] != "triplet") // triplets has no transition dipole and no contribution to the spectrum + spectrum.transition_analysis(this->inp_->bse_spin_types[is] + "_tda"); + if (this->inp_->bse_spin_types[is] != + "triplet") // triplets has no transition dipole and no contribution to the spectrum { - spectrum.write_transition_dipole(output_dir + - "trans_dipole_" + this->inp_->bse_spin_types[is] + "_tda.dat"); + spectrum.write_transition_dipole( + output_dir + "trans_dipole_" + this->inp_->bse_spin_types[is] + "_tda.dat"); // ============================== for test ============================== if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") - { //// TEST the formula v/omega rather than v/(e_a-e_i) - // spectrum.test_transition_dipoles_velocity_omega(); - // spectrum.write_transition_dipole(out_dir + - // "trans_dipole_" + spin_types[is] + "_vomega_tda.dat"); + { //// TEST the formula v/omega rather than v/(e_a-e_i) + // spectrum.test_transition_dipoles_velocity_omega(); + // spectrum.write_transition_dipole(out_dir + + // "trans_dipole_" + spin_types[is] + "_vomega_tda.dat"); } // ============================== for test ============================== } @@ -544,14 +720,31 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) } if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "full") { - for (int is = 0;is < this->full_X.size();++is) + for (int is = 0; is < this->full_X.size(); ++is) { - LR::LR_Spectrum spectrum(this->nspin, this->nbasis, this->nocc, this->nvirt, *this->pw_rho, *this->psi_ks, - *this->ucell_, this->kv, this->gd(), this->orb_cutoff_, this->tcb(), - this->paraX_, this->paraC_, this->paraMat_, - &this->full_ene[is * this->nstates], this->eig_ks.c, - this->full_X[is].template data(), this->nstates, false/*openshell*/, - LR_Util::tolower(this->inp_->abs_gauge), GlobalV::MY_RANK, output_dir); + LR::LR_Spectrum spectrum( + this->nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->pw_rho, + *this->psi_ks, + *this->ucell_, + this->kv, + this->gd(), + this->orb_cutoff_, + this->tcb(), + this->paraX_, + this->paraC_, + this->paraMat_, + &this->full_ene[is * this->nstates], + this->eig_ks.c, + this->full_X[is].template data(), + this->nstates, + false /*openshell*/, + LR_Util::tolower(this->inp_->abs_gauge), + GlobalV::MY_RANK, + output_dir); if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { spectrum.set_vmo(this->velocity_mo.data()); @@ -559,11 +752,12 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) spectrum.set_Y(this->full_Y[is].template data()); spectrum.set_full(true); spectrum.cal_spectrum(); - spectrum.transition_analysis(this->inp_->bse_spin_types[is]+"_full"); - if (this->inp_->bse_spin_types[is] != "triplet") // triplets has no transition dipole and no contribution to the spectrum + spectrum.transition_analysis(this->inp_->bse_spin_types[is] + "_full"); + if (this->inp_->bse_spin_types[is] != + "triplet") // triplets has no transition dipole and no contribution to the spectrum { - spectrum.write_transition_dipole(output_dir + - "trans_dipole_" + this->inp_->bse_spin_types[is] + "_full.dat"); + spectrum.write_transition_dipole( + output_dir + "trans_dipole_" + this->inp_->bse_spin_types[is] + "_full.dat"); } } } @@ -573,9 +767,8 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) ModuleBase::timer::end("ESolver_BSE", "after_all_runners"); } -template -void ESolver_BSE::ipa_solver() -{// if ipa, assign X as identity matrix directly +template void ESolver_BSE::ipa_solver() +{ // if ipa, assign X as identity matrix directly ModuleBase::TITLE("ESolver_BSE", "ipa_solver"); ModuleBase::timer::start("ESolver_BSE", "ipa_solver"); std::cout << "Independent particle approximation is used, assign X as identity matrix directly." << std::endl; @@ -596,9 +789,7 @@ void ESolver_BSE::ipa_solver() std::vector indices(ev.size()); std::iota(indices.begin(), indices.end(), 0); // [0, 1, 2, ..., size-1] - std::sort(indices.begin(), indices.end(), [&](int lhs, int rhs) { - return ev[lhs] < ev[rhs]; - }); + std::sort(indices.begin(), indices.end(), [&](int lhs, int rhs) { return ev[lhs] < ev[rhs]; }); std::sort(ev.begin(), ev.end()); std::copy_n(ev.data(), this->nstates, this->tda_ene.data()); #ifdef _OPENMP @@ -613,15 +804,17 @@ void ESolver_BSE::ipa_solver() int a = sorted_index % this->nvirt[0]; int col_loc = this->paraX_[0].global2local_col(i); int row_loc = this->paraX_[0].global2local_row(a); - if (col_loc == -1 || row_loc == -1) continue; + if (col_loc == -1 || row_loc == -1) + { + continue; + } this->X[0].template data()[loffset_X + col_loc * this->paraX_[0].get_row_size() + row_loc] = 1.0; } ModuleBase::timer::end("ESolver_BSE", "ipa_solver"); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "IPA solver"); } -template -void ESolver_BSE::lri_init() +template void ESolver_BSE::lri_init() { ModuleBase::TITLE("ESolver_BSE", "LRI init"); using TA = int; @@ -633,32 +826,35 @@ void ESolver_BSE::lri_init() std::map>> Ws_in; // if (GlobalV::MY_RANK == 0) // comment to read from all processes to avoid communication // { - Cs_in = LRI_CV_Tools::read_Cs_ao_all(this->rpa_dir); - if (this->inp_->ri_hartree_benchmark == "aims-librpa" ) - { - Vs_in = LR_IO::read_coulomb_mat_general_k(this->rpa_dir, Cs_in, this->kRlist); - } - else if (this->inp_->ri_hartree_benchmark == "none" || this->inp_->ri_hartree_benchmark == "abacus-librpa" ) - { - Vs_in = LR_IO::read_coulomb_mat_k(this->rpa_dir, Cs_in, this->kRlist); - } - Ws_in = LR_IO::read_Ws(Vs_in, this->kRlist.Rlist); - // if (GlobalV::MY_RANK == 0) - // { - // LR_IO::write_lri_R_max_norm(Vs_in, *this->ucell_, this->out_dir + "V_R_max_norm.dat"); - // LR_IO::write_lri_R_max_norm(Ws_in, *this->ucell_, this->out_dir + "W_R_max_norm.dat"); - // } + Cs_in = LRI_CV_Tools::read_Cs_ao_all(this->rpa_dir); + if (this->inp_->ri_hartree_benchmark == "aims-librpa") + { + Vs_in = LR_IO::read_coulomb_mat_general_k(this->rpa_dir, Cs_in, this->kRlist); + } + else if (this->inp_->ri_hartree_benchmark == "none" || this->inp_->ri_hartree_benchmark == "abacus-librpa") + { + Vs_in = LR_IO::read_coulomb_mat_k(this->rpa_dir, Cs_in, this->kRlist); + } + Ws_in = LR_IO::read_Ws(Vs_in, this->kRlist.Rlist); + // if (GlobalV::MY_RANK == 0) + // { + // LR_IO::write_lri_R_max_norm(Vs_in, *this->ucell_, this->out_dir + "V_R_max_norm.dat"); + // LR_IO::write_lri_R_max_norm(Ws_in, *this->ucell_, this->out_dir + "W_R_max_norm.dat"); + // } // } #ifdef __MPI MPI_Barrier(MPI_COMM_WORLD); #endif - this->mo_lri->init(Cs_in, Vs_in, Ws_in, this->exx_info.info_ri); + this->mo_lri->init( + Cs_in, + Vs_in, + Ws_in, + this->exx_info.info_ri); malloc_trim(0); ModuleBase::TITLE("ESolver_BSE", "Finish LRI init"); } -template -void ESolver_BSE::read_ks_wfc() +template void ESolver_BSE::read_ks_wfc() { assert(this->psi_ks != nullptr); this->pelec->ekb.create(this->kv.get_nks(), this->nbands); @@ -671,58 +867,109 @@ void ESolver_BSE::read_ks_wfc() int nspin_file = 0; int nocc_file = 0; int nspin_tmp = this->inp_->nspin == 2 ? 2 : 1; - LR_IO::parse_band_out_file(this->rpa_dir, nbands_file, nk_file, nspin_file, nocc_file); - if (nk_file != this->nk) { - ModuleBase::WARNING_QUIT("ESolver_BSE", "Inconsistence: The nk in `band_out` is " + std::to_string(nk_file) - + ", while BSE::nk is " + std::to_string(this->nk)); + LR_IO::parse_band_out_file( + this->rpa_dir, + nbands_file, + nk_file, + nspin_file, + nocc_file); + if (nk_file != this->nk) + { + ModuleBase::WARNING_QUIT( + "ESolver_BSE", "Inconsistence: The nk in `band_out` is " + std::to_string(nk_file) + ", while BSE::nk is " + + std::to_string(this->nk)); } std::vector eig_gw_info; if (this->inp_->bse_use_fine_kgrid) { - eig_gw_info = LR_IO::read_energy_qp_from_band_files(this->kv, this->nocc[0], this->nvirt[0], ncore, - this->rpa_dir, this->nk, nspin_tmp, nspin_file); - LR_IO::read_librpa_eigenvectors_from_band_files(*this->psi_ks, *this->psi_ks_global, - this->rpa_dir, ncore, nbands_file, nspin_tmp, nspin_file, GlobalV::MY_RANK, this->paraMat_); + eig_gw_info = LR_IO::read_energy_qp_from_band_files( + this->kv, + this->nocc[0], + this->nvirt[0], + ncore, + this->rpa_dir, + this->nk, + nspin_tmp, + nspin_file); + LR_IO::read_librpa_eigenvectors_from_band_files( + *this->psi_ks, + *this->psi_ks_global, + this->rpa_dir, + ncore, + nbands_file, + nspin_tmp, + nspin_file, + GlobalV::MY_RANK, + this->paraMat_); } else { - eig_gw_info = LR_IO::read_energy_qp(this->nocc[0], this->nvirt[0], - this->rpa_dir, ncore, this->nk, nspin_tmp, nspin_file); - LR_IO::read_librpa_eigenvectors(*this->psi_ks, *this->psi_ks_global, - this->rpa_dir, ncore, nbands_file, nspin_tmp, nspin_file, GlobalV::MY_RANK, this->paraMat_); + eig_gw_info = LR_IO::read_energy_qp( + this->nocc[0], + this->nvirt[0], + this->rpa_dir, + ncore, + this->nk, + nspin_tmp, + nspin_file); + LR_IO::read_librpa_eigenvectors( + *this->psi_ks, + *this->psi_ks_global, + this->rpa_dir, + ncore, + nbands_file, + nspin_tmp, + nspin_file, + GlobalV::MY_RANK, + this->paraMat_); } int cbm_k(0), vbm_k(0), direct_k(0); - for (int iks = 0; iks < this->kv.get_nks(); ++iks) { - for (int ib = 0; ib < this->nbands; ++ib) { - this->pelec->wg(iks, ib) = eig_gw_info[iks * this->nbands *3 + ib * 3 + 0]; - this->pelec->ekb(iks, ib) = eig_gw_info[iks * this->nbands *3 + ib * 3 + 1]; - this->eig_gw(iks, ib) = eig_gw_info[iks * this->nbands *3 + ib * 3 + 2]; + for (int iks = 0; iks < this->kv.get_nks(); ++iks) + { + for (int ib = 0; ib < this->nbands; ++ib) + { + this->pelec->wg(iks, ib) = eig_gw_info[iks * this->nbands * 3 + ib * 3 + 0]; + this->pelec->ekb(iks, ib) = eig_gw_info[iks * this->nbands * 3 + ib * 3 + 1]; + this->eig_gw(iks, ib) = eig_gw_info[iks * this->nbands * 3 + ib * 3 + 2]; } double cbm = this->eig_gw(iks, this->nocc[0]); - for (int ib = this->nocc[0]; ib < this->nbands; ++ib) { // in case of non-ordered bands + for (int ib = this->nocc[0]; ib < this->nbands; ++ib) + { // in case of non-ordered bands double e = this->eig_gw(iks, ib); - if (e < cbm) cbm = e; + if (e < cbm) + { + cbm = e; + } } - double vbm = this->eig_gw(iks, this->nocc[0]-1); - for (int ib = 0; ib < this->nocc[0]-1; ++ib) { + double vbm = this->eig_gw(iks, this->nocc[0] - 1); + for (int ib = 0; ib < this->nocc[0] - 1; ++ib) + { double e = this->eig_gw(iks, ib); - if (e > vbm) vbm = e; + if (e > vbm) + { + vbm = e; + } } - if (iks == 0) { + if (iks == 0) + { this->cbm_energy = cbm; this->vbm_energy = vbm; this->direct_gap = cbm - vbm; } - else { - if (this->cbm_energy > cbm) { + else + { + if (this->cbm_energy > cbm) + { this->cbm_energy = cbm; cbm_k = iks; } - if (this->vbm_energy < vbm) { + if (this->vbm_energy < vbm) + { this->vbm_energy = vbm; vbm_k = iks; } - if (this->direct_gap > cbm - vbm) { + if (this->direct_gap > cbm - vbm) + { this->direct_gap = cbm - vbm; direct_k = iks; } @@ -736,71 +983,98 @@ void ESolver_BSE::read_ks_wfc() this->eig_ks = std::move(this->pelec->ekb); } -template -void ESolver_BSE::init_pot(const Charge& chg_gs) +template void ESolver_BSE::init_pot(const Charge &chg_gs) { using ST = LR::PotHxcLR::SpinType; switch (this->nspin) { - case 1: case 2: + case 1: + case 2: { - const auto& grid = this->pgrid(); - const auto kernel = LR::build_xc_kernel(this->xc_kernel, *this->pw_rho, *this->ucell_, - chg_gs, grid, this->nspin, false, LR::KernelXC::NoGxc, this->inp_->lr_init_xc_kernel); + const auto &grid = this->pgrid(); + const auto kernel = LR::build_xc_kernel( + this->xc_kernel, + *this->pw_rho, + *this->ucell_, + chg_gs, + grid, + this->nspin, + false, + LR::KernelXC::NoGxc, + this->inp_->lr_init_xc_kernel); // BSE multiplies its bare Coulomb matrix by the singlet factor in HamiltBSE. // S1_gs has weight one; S1 would apply that factor a second time on the grid path. - this->pot[0] = std::make_shared(kernel, *this->pw_rho, *this->ucell_, - chg_gs.nrxx, this->nspin, ST::S1_gs); + this->pot[0] = std::make_shared( + kernel, + *this->pw_rho, + *this->ucell_, + chg_gs.nrxx, + this->nspin, + ST::S1_gs); break; } // case 2: - // this->pot[0] = std::make_shared(xc_kernel, *this->pw_rho, ucell, chg_gs, pgrid(), openshell ? ST::S2_updown : ST::S2_singlet, this->inp_->lr_init_xc_kernel); - // this->pot[1] = std::make_shared(xc_kernel, *this->pw_rho, ucell, chg_gs, pgrid(), openshell ? ST::S2_updown : ST::S2_triplet, this->inp_->lr_init_xc_kernel); - // break; + // this->pot[0] = std::make_shared(xc_kernel, *this->pw_rho, ucell, chg_gs, pgrid(), openshell ? + // ST::S2_updown : ST::S2_singlet, this->inp_->lr_init_xc_kernel); this->pot[1] = + // std::make_shared(xc_kernel, *this->pw_rho, ucell, chg_gs, pgrid(), openshell ? ST::S2_updown : + // ST::S2_triplet, this->inp_->lr_init_xc_kernel); break; default: throw std::invalid_argument("ESolver_BSE: nspin must be 1 or 2"); } } -template -void ESolver_BSE::allocate_eigen_infos() +template void ESolver_BSE::allocate_eigen_infos() { ModuleBase::TITLE("ESolver_BSE", "allocate_eigen_infos"); for (int is = 0; is < this->nspin; ++is) { Parallel_2D px; - LR_Util::setup_2d_division(px, /*nb2d=*/1, this->nvirt[is], this->nocc[is] + LR_Util::setup_2d_division( + px, + /*nb2d=*/1, + this->nvirt[is], + this->nocc[is] #ifdef __MPI - , this->paraC_.blacs_ctxt + , + this->paraC_.blacs_ctxt #endif ); this->paraX_.emplace_back(std::move(px)); } - this->nloc_per_state = this->nk - * (this->openshell ? this->paraX_[0].get_local_size() + this->paraX_[1].get_local_size() - : this->paraX_[0].get_local_size()); + this->nloc_per_state = + this->nk * (this->openshell ? this->paraX_[0].get_local_size() + this->paraX_[1].get_local_size() + : this->paraX_[0].get_local_size()); int n_spin_types = this->inp_->bse_spin_types.size(); - if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "tda") { - BSE_Util::print_mem_estimate("TDA BSE eigen states", - n_spin_types * static_cast(this->nstates) - * (1 + this->nloc_per_state), - sizeof(T)); + if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "tda") + { + BSE_Util::print_mem_estimate( + "TDA BSE eigen states", n_spin_types * static_cast(this->nstates) * (1 + this->nloc_per_state), + sizeof(T)); this->tda_ene.resize(n_spin_types * this->nstates); - this->X.resize(n_spin_types, LR_Util::newTensor({ this->nstates, this->nloc_per_state })); - for (auto& x : this->X) { x.zero(); } + this->X.resize(n_spin_types, LR_Util::newTensor({this->nstates, this->nloc_per_state})); + for (auto &x : this->X) + { + x.zero(); + } } - if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "full") { - BSE_Util::print_mem_estimate("full BSE eigen states", - n_spin_types * static_cast(this->nstates) - * (1 + 2 * this->nloc_per_state), - sizeof(T)); + if (this->inp_->bse_tda == "both" || this->inp_->bse_tda == "full") + { + BSE_Util::print_mem_estimate( + "full BSE eigen states", + n_spin_types * static_cast(this->nstates) * (1 + 2 * this->nloc_per_state), sizeof(T)); this->full_ene.resize(n_spin_types * this->nstates); - this->full_X.resize(n_spin_types, LR_Util::newTensor({ this->nstates, this->nloc_per_state })); - this->full_Y.resize(n_spin_types, LR_Util::newTensor({ this->nstates, this->nloc_per_state })); - for (auto& x : this->full_X) { x.zero(); } - for (auto& y : this->full_Y) { y.zero(); } + this->full_X.resize(n_spin_types, LR_Util::newTensor({this->nstates, this->nloc_per_state})); + this->full_Y.resize(n_spin_types, LR_Util::newTensor({this->nstates, this->nloc_per_state})); + for (auto &x : this->full_X) + { + x.zero(); + } + for (auto &y : this->full_Y) + { + y.zero(); + } } } diff --git a/source/source_esolver/esolver_lr_lcao_bse.h b/source/source_esolver/esolver_lr_lcao_bse.h index 50aa82db1d..e66fdf42b5 100644 --- a/source/source_esolver/esolver_lr_lcao_bse.h +++ b/source/source_esolver/esolver_lr_lcao_bse.h @@ -6,54 +6,64 @@ namespace ModuleESolver { - template using Real = typename GetTypeReal::type; +template using Real = typename GetTypeReal::type; - template - class ESolver_BSE : public ESolver_LR { - public: - ESolver_BSE(const Input_para& inp, const std::string& in_dir, const std::string& out_dir, const LRRuntime& runtime) - : ESolver_LR(inp, in_dir, out_dir, runtime), rpa_dir(inp.rpa_outdir) - { - } +template class ESolver_BSE : public ESolver_LR +{ + public: + ESolver_BSE( + const Input_para &inp, + const std::string &in_dir, + const std::string &out_dir, + const LRRuntime &runtime) + : ESolver_LR( + inp, + in_dir, + out_dir, + runtime), + rpa_dir(inp.rpa_outdir) + { + } - ~ESolver_BSE() override { - //delete this->psi_ks; // already deleted in ESolver_LR - delete this->psi_ks_global; - } + ~ESolver_BSE() override + { + // delete this->psi_ks; // already deleted in ESolver_LR + delete this->psi_ks_global; + } - const std::string rpa_dir; - LR_IO::RI_kRlist kRlist; - psi::Psi* psi_ks_global; ///< global version of psi_ks - ModuleBase::matrix eig_gw; ///< GW energy - double cbm_energy, vbm_energy; //conduction band minimum and valence band maximum - double direct_gap; - std::vector tda_ene, full_ene; // in Rydberg + const std::string rpa_dir; + LR_IO::RI_kRlist kRlist; + psi::Psi *psi_ks_global; ///< global version of psi_ks + ModuleBase::matrix eig_gw; ///< GW energy + double cbm_energy, vbm_energy; // conduction band minimum and valence band maximum + double direct_gap; + std::vector tda_ene, full_ene; // in Rydberg - /// @brief [nspin_types][{nstates, nk* (locc* lvirt}] - std::vector full_X, full_Y; + /// @brief [nspin_types][{nstates, nk* (locc* lvirt}] + std::vector full_X, full_Y; - std::unique_ptr> mo_lri; + std::unique_ptr> mo_lri; - virtual void before_all_runners(BaseCell& basecell, const Input_para& inp) override; - virtual void runner(BaseCell& basecell, int istep) override; - virtual void after_all_runners(BaseCell& basecell) override; + virtual void before_all_runners(BaseCell &basecell, const Input_para &inp) override; + virtual void runner(BaseCell &basecell, int istep) override; + virtual void after_all_runners(BaseCell &basecell) override; - void lri_init(); + void lri_init(); - /// @brief solve IPA without construct and diagonalize matrix - void ipa_solver(); + /// @brief solve IPA without construct and diagonalize matrix + void ipa_solver(); - /// @brief read in the ground state wave function, gw band energy and occupation - virtual void read_ks_wfc() override; + /// @brief read in the ground state wave function, gw band energy and occupation + virtual void read_ks_wfc() override; - /// @brief init Hartree potential for BSE, - /// @attention here we don't multiply 2 for singlet or 0 for triplet, we will do it in HamiltBSE - virtual void init_pot(const Charge& chg_gs) override; + /// @brief init Hartree potential for BSE, + /// @attention here we don't multiply 2 for singlet or 0 for triplet, we will do it in HamiltBSE + virtual void init_pot(const Charge &chg_gs) override; - /// @brief X for tda and also Y for full BSE excitation - void allocate_eigen_infos(); - }; + /// @brief X for tda and also Y for full BSE excitation + void allocate_eigen_infos(); +}; -} +} // namespace ModuleESolver #endif // ABACUS_SOURCE_ESOLVER_ESOLVER_LR_LCAO_BSE_H diff --git a/source/source_esolver/esolver_lr_lcao_tddft.cpp b/source/source_esolver/esolver_lr_lcao_tddft.cpp index 9442787572..c7328f4588 100644 --- a/source/source_esolver/esolver_lr_lcao_tddft.cpp +++ b/source/source_esolver/esolver_lr_lcao_tddft.cpp @@ -1,38 +1,41 @@ // LR execution flow and final spectrum/density output. #include "esolver_lr_lcao_tddft.h" -#include "source_lcao/module_lr/utils/lr_io.h" -#include "source_lcao/module_lr/utils/lr_util_print.h" -#include "source_lcao/module_lr/utils/lr_util.h" + +#include "source_hamilt/module_xc/xc_functional.h" #include "source_lcao/module_lr/hamilt_ulr.h" #include "source_lcao/module_lr/hsolver_lrtd.h" -#include "source_lcao/module_lr/lr_spectrum.h" #include "source_lcao/module_lr/lr_density.h" -#include "source_lcao/module_lr/ri_benchmark/ri_benchmark.h" +#include "source_lcao/module_lr/lr_spectrum.h" #include "source_lcao/module_lr/operator_casida/operator_lr_diag.h" +#include "source_lcao/module_lr/ri_benchmark/ri_benchmark.h" +#include "source_lcao/module_lr/utils/lr_io.h" +#include "source_lcao/module_lr/utils/lr_util.h" +#include "source_lcao/module_lr/utils/lr_util_print.h" #include "source_lcao/module_lr/zeq_solver.h" -#include "source_hamilt/module_xc/xc_functional.h" + #include #include using namespace LR; template -ModuleESolver::ESolver_LR::ESolver_LR(const Input_para& inp, - const std::string& in_dir, - const std::string& out_dir, const LRRuntime& runtime) - : in_dir(in_dir), out_dir(out_dir), ofs_running_(runtime.running_log), - ofs_warning_(runtime.warning_log), my_rank_(runtime.rank) +ModuleESolver::ESolver_LR::ESolver_LR( + const Input_para &inp, + const std::string &in_dir, + const std::string &out_dir, + const LRRuntime &runtime) + : in_dir(in_dir), out_dir(out_dir), ofs_running_(runtime.running_log), ofs_warning_(runtime.warning_log), + my_rank_(runtime.rank) { #ifdef __EXX init_exx_info(this->exx_info, inp); #endif } -template -void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int istep) +template void ModuleESolver::ESolver_LR::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_LR", "runner"); ModuleBase::timer::start("ESolver_LR", "runner"); @@ -48,14 +51,13 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste if (this->inp_->calculation == "relax" && !this->conv_esolver) { ModuleBase::WARNING_QUIT( - "ESolver_LR", - "Excited-state relaxation requires a converged ground-state SCF; ionic step rejected"); + "ESolver_LR", "Excited-state relaxation requires a converged ground-state SCF; ionic step rejected"); } this->etot_gs_ = this->ks_->cal_energy(); if (!this->ks_initialized_) { this->initialize_from_ks_(ucell, *this->inp_); - this->setup_relax_target_(); // needs the final dimensions, i.e. `openshell` + this->setup_relax_target_(); // needs the final dimensions, i.e. `openshell` } else { @@ -63,43 +65,55 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste } } - //allocate 2-particle state and setup 2d division + // allocate 2-particle state and setup 2d division this->setup_eigenvectors_X(); this->pelec->ekb.create(nspin, this->nstates); // set once here rather than inside the solver branches: the open-shell `spectrum` branch used // to leave it empty, and both `after_all_runners` and the gradient index it - this->spin_types = this->openshell ? std::vector({ "updown" }) - : std::vector({ "singlet", "triplet" }); + this->spin_types = + this->openshell ? std::vector({"updown"}) : std::vector({"singlet", "triplet"}); // a relaxation writes these once per ionic step; without the suffix every step would overwrite // the last, and the trajectory would be impossible to inspect afterwards const std::string step_suffix = this->excited_relax_ ? "_step" + std::to_string(istep) : ""; - auto efile_out = [this, &step_suffix](const std::string& label) -> std::string { - return this->out_dir + "Excitation_Energy_" + label + step_suffix + ".dat"; - }; - auto vfile_out = [this, &step_suffix](const std::string& label) -> std::string { - return this->out_dir + "Excitation_Amplitude_" + label + step_suffix + "_" + std::to_string(this->my_rank_ + 1) - + ".dat"; + auto efile_out = [this, &step_suffix](const std::string &label) -> std::string + { return this->out_dir + "Excitation_Energy_" + label + step_suffix + ".dat"; }; + auto vfile_out = [this, &step_suffix](const std::string &label) -> std::string + { + return this->out_dir + "Excitation_Amplitude_" + label + step_suffix + "_" + + std::to_string(this->my_rank_ + 1) + ".dat"; }; if (this->inp_->lr_solver == "elpa") { ModuleBase::WARNING_QUIT("ESolver_LR", "ESolver_LR doesn't support elpa now."); - } else if (this->inp_->lr_solver != "spectrum") { - auto write_states = [this, &efile_out, &vfile_out](const std::string& label, - const Real* e, - const T* v, - const int& dim, - const int& nst, - const int& prec = 8) -> void { + auto write_states = [this, &efile_out, &vfile_out]( + const std::string &label, + const Real *e, + const T *v, + const int &dim, + const int &nst, + const int &prec = 8) -> void + { if (this->my_rank_ == 0) { - assert(nst == LR_Util::write_value(efile_out(label), prec, e, nst)); + assert( + nst == LR_Util::write_value( + efile_out(label), + prec, + e, + nst)); } - assert(nst * dim == LR_Util::write_value(vfile_out(label), prec, v, nst, dim)); + assert( + nst * dim == LR_Util::write_value( + vfile_out(label), + prec, + v, + nst, + dim)); }; std::vector precondition(this->inp_->lr_solver == "lapack" ? 0 : nloc_per_state, 1.0); // allocate and initialize A matrix and density matrix @@ -107,111 +121,200 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste { for (int is : {0, 1}) { - if (this->inp_->lr_solver != "lapack") { + if (this->inp_->lr_solver != "lapack") + { const int offset_is = is * this->paraX_[0].get_local_size(); - OperatorLRDiag pre_op(this->eig_ks.c + is * nk * (nocc[0] + nvirt[0]), this->paraX_[is], this->nk, this->nocc[is], this->nvirt[is], false); - pre_op.act(1, offset_is, 1, precondition.data() + offset_is, precondition.data() + offset_is); + OperatorLRDiag pre_op( + this->eig_ks.c + is * nk * (nocc[0] + nvirt[0]), + this->paraX_[is], + this->nk, + this->nocc[is], + this->nvirt[is], + false); + pre_op.act( + 1, + offset_is, + 1, + precondition.data() + offset_is, + precondition.data() + offset_is); } } std::cout << "Solving spin-conserving excitation for open-shell system." << std::endl; - HamiltULR hulr(xc_kernel, - nspin, - this->nbasis, - this->nocc, - this->nvirt, - *this->ucell_, - orb_cutoff_, - this->gd(), - *this->psi_ks, - this->eig_ks, + HamiltULR hulr( + xc_kernel, + nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->ucell_, + orb_cutoff_, + this->gd(), + *this->psi_ks, + this->eig_ks, #ifdef __EXX - this->exx_lri, - this->exx_info.info_global.hybrid_alpha, + this->exx_lri, + this->exx_info.info_global.hybrid_alpha, #endif - this->pot, - this->kv, - this->paraX_, - this->paraC_, - this->paraMat_); - LR::HSolver::solve(hulr, this->X[0].template data(), nloc_per_state, nstates, - this->nk, this->nocc, this->nvirt, this->paraX_, - this->pelec->ekb.c, this->inp_->lr_solver, - this->inp_->lr_thr, precondition, true); - if (this->inp_->out_wfc_lr) { write_states("openshell", this->pelec->ekb.c, this->X[0].template data(), nloc_per_state, nstates); } + this->pot, + this->kv, + this->paraX_, + this->paraC_, + this->paraMat_); + LR::HSolver::solve( + hulr, + this->X[0].template data(), + nloc_per_state, + nstates, + this->nk, + this->nocc, + this->nvirt, + this->paraX_, + this->pelec->ekb.c, + this->inp_->lr_solver, + this->inp_->lr_thr, + precondition, + true); + if (this->inp_->out_wfc_lr) + { + write_states( + "openshell", + this->pelec->ekb.c, + this->X[0].template data(), + nloc_per_state, + nstates); + } } else { - if (this->inp_->lr_solver != "lapack") { - OperatorLRDiag pre_op(this->eig_ks.c, this->paraX_[0], this->nk, this->nocc[0], this->nvirt[0], false); - pre_op.act(1, nloc_per_state, 1, precondition.data(), precondition.data()); + if (this->inp_->lr_solver != "lapack") + { + OperatorLRDiag pre_op( + this->eig_ks.c, + this->paraX_[0], + this->nk, + this->nocc[0], + this->nvirt[0], + false); + pre_op.act( + 1, + nloc_per_state, + 1, + precondition.data(), + precondition.data()); } - const std::vector& spin_types = this->spin_types; - for (int is = 0;is < nspin;++is) + const std::vector &spin_types = this->spin_types; + for (int is = 0; is < nspin; ++is) { std::cout << " Calculating " << spin_types[is] << " excitations" << std::endl; - HamiltLR hlr(xc_kernel, - nspin, - this->nbasis, - this->nocc, - this->nvirt, - *this->ucell_, - orb_cutoff_, - this->gd(), - *this->psi_ks, - this->eig_ks, + HamiltLR hlr( + xc_kernel, + nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->ucell_, + orb_cutoff_, + this->gd(), + *this->psi_ks, + this->eig_ks, #ifdef __EXX - this->exx_lri, - this->exx_info.info_global.hybrid_alpha, + this->exx_lri, + this->exx_info.info_global.hybrid_alpha, #endif - this->pot[is], - this->kv, - this->paraX_, - this->paraC_, - this->paraMat_, - spin_types[is], - this->in_dir, - this->out_dir, - this->inp_->ri_hartree_benchmark, - (this->inp_->ri_hartree_benchmark == "aims" ? this->inp_->aims_nbasis : std::vector({}))); - LR::HSolver::solve(hlr, this->X[is].template data(), nloc_per_state, nstates, - this->nk, this->nocc, this->nvirt, this->paraX_, - this->pelec->ekb.c + is * nstates, - this->inp_->lr_solver, - this->inp_->lr_thr, - precondition, true); - if (this->inp_->out_wfc_lr) { write_states(spin_types[is], this->pelec->ekb.c + is * nstates, this->X[is].template data(), nloc_per_state, nstates); } + this->pot[is], + this->kv, + this->paraX_, + this->paraC_, + this->paraMat_, + spin_types[is], + this->in_dir, + this->out_dir, + this->inp_->ri_hartree_benchmark, + (this->inp_->ri_hartree_benchmark == "aims" ? this->inp_->aims_nbasis : std::vector({}))); + LR::HSolver::solve( + hlr, + this->X[is].template data(), + nloc_per_state, + nstates, + this->nk, + this->nocc, + this->nvirt, + this->paraX_, + this->pelec->ekb.c + is * nstates, + this->inp_->lr_solver, + this->inp_->lr_thr, + precondition, + true); + if (this->inp_->out_wfc_lr) + { + write_states( + spin_types[is], + this->pelec->ekb.c + is * nstates, + this->X[is].template data(), + nloc_per_state, + nstates); + } } } } - else // lr_solver == "spectrum", read the eigenvalues + else // lr_solver == "spectrum", read the eigenvalues { - auto efile_in = [&](const std::string& label)->std::string {return this->in_dir + "Excitation_Energy_" + label + ".dat";}; - auto vfile_in = [this](const std::string& label) -> std::string { - return this->in_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(this->my_rank_ + 1) + ".dat"; - }; + auto efile_in = [&](const std::string &label) -> std::string + { return this->in_dir + "Excitation_Energy_" + label + ".dat"; }; + auto vfile_in = [this](const std::string &label) -> std::string + { return this->in_dir + "Excitation_Amplitude_" + label + "_" + std::to_string(this->my_rank_ + 1) + ".dat"; }; - auto read_states = [&](const std::string& label, Real* e, T* v, const int& dim, const int& nst)->void + auto read_states = [&](const std::string &label, + Real *e, + T *v, + const int &dim, + const int &nst) -> void + { + if (this->my_rank_ == 0) { - if (this->my_rank_ == 0) { - assert(nst == LR_Util::read_value(efile_in(label), e, nst)); - std::cout <<"Rank "<< this->my_rank_ << ": finish reading " << efile_in(label) << std::endl; - } + assert(nst == LR_Util::read_value(efile_in(label), e, nst)); + std::cout << "Rank " << this->my_rank_ << ": finish reading " << efile_in(label) << std::endl; + } #ifdef __MPI -// in velocity gauge, the eigenvalues may be used to calculate the transition dipole, so we'd better broadcast them - MPI_Bcast(e, nst, MPI_DOUBLE, 0, MPI_COMM_WORLD); + // in velocity gauge, the eigenvalues may be used to calculate the transition dipole, so we'd better + // broadcast them + MPI_Bcast( + e, + nst, + MPI_DOUBLE, + 0, + MPI_COMM_WORLD); #endif - assert(nst * dim == LR_Util::read_value(vfile_in(label), v, nst, dim)); - std::cout <<"Rank "<< this->my_rank_ << ": finish reading " << vfile_in(label) << std::endl; - }; + assert( + nst * dim == LR_Util::read_value( + vfile_in(label), + v, + nst, + dim)); + std::cout << "Rank " << this->my_rank_ << ": finish reading " << vfile_in(label) << std::endl; + }; std::cout << "reading the excitation states from file: \n"; if (openshell) { - read_states("openshell", this->pelec->ekb.c, this->X[0].template data(), nloc_per_state, nstates); + read_states( + "openshell", + this->pelec->ekb.c, + this->X[0].template data(), + nloc_per_state, + nstates); } else { - const std::vector& spin_types = this->spin_types; - for (int is = 0;is < nspin;++is) { read_states(spin_types[is], this->pelec->ekb.c + is * nstates, this->X[is].template data(), nloc_per_state, nstates); } + const std::vector &spin_types = this->spin_types; + for (int is = 0; is < nspin; ++is) + { + read_states( + spin_types[is], + this->pelec->ekb.c + is * nstates, + this->X[is].template data(), + nloc_per_state, + nstates); + } } } if (this->excited_relax_) @@ -229,7 +332,8 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste // it the relaxation only reports a force, and whether E_gs + Omega actually goes down -- // the thing being minimised -- cannot be read off the log at all. const double omega = this->target_omega_(); - auto max_abs = [](const ModuleBase::matrix& m) -> double { + auto max_abs = [](const ModuleBase::matrix &m) -> double + { double v = 0.0; for (int i = 0; i < m.nr * m.nc; ++i) { @@ -237,111 +341,174 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste } return v; }; - this->ofs_running_ << std::setprecision(8) << std::fixed - << " EXCITED-STATE RELAX step " << istep - << ": E_gs = " << this->etot_gs_ * ModuleBase::Ry_to_eV - << " eV, Omega = " << omega * ModuleBase::Ry_to_eV - << " eV, E_exc = " << (this->etot_gs_ + omega) * ModuleBase::Ry_to_eV << " eV" - << std::setprecision(6) - << " | |F_gs|max = " << max_abs(this->force_gs_) * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A - << ", |F_Omega|max = " << max_abs(this->lr_force_) * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A - << " eV/Angstrom" << std::defaultfloat << std::endl; + this->ofs_running_ << std::setprecision(8) << std::fixed << " EXCITED-STATE RELAX step " << istep + << ": E_gs = " << this->etot_gs_ * ModuleBase::Ry_to_eV + << " eV, Omega = " << omega * ModuleBase::Ry_to_eV + << " eV, E_exc = " << (this->etot_gs_ + omega) * ModuleBase::Ry_to_eV << " eV" + << std::setprecision(6) << " | |F_gs|max = " + << max_abs(this->force_gs_) * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A + << ", |F_Omega|max = " + << max_abs(this->lr_force_) * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A << " eV/Angstrom" + << std::defaultfloat << std::endl; } ModuleBase::timer::end("ESolver_LR", "runner"); return; } -template -void ModuleESolver::ESolver_LR::after_all_runners(BaseCell& basecell) +template void ModuleESolver::ESolver_LR::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_LR", "after_all_runners"); - if (this->inp_->ri_hartree_benchmark != "none") { return; } //no need to calculate the spectrum in the benchmark routine + if (this->inp_->ri_hartree_benchmark != "none") + { + return; + } // no need to calculate the spectrum in the benchmark routine // cal electron-hole density if (this->inp_->out_chg[0]) { - LR_Density lr_density(*this->ucell_, kv, gd(), *psi_ks, orb_cutoff_, pgrid(), - nspin, nocc, nvirt, nbasis, - paraX_, paraC_, paraMat_, openshell, this->inp_->out_chg[1], this->out_dir); + LR_Density lr_density( + *this->ucell_, + kv, + gd(), + *psi_ks, + orb_cutoff_, + pgrid(), + nspin, + nocc, + nvirt, + nbasis, + paraX_, + paraC_, + paraMat_, + openshell, + this->inp_->out_chg[1], + this->out_dir); if (openshell) { - for (int is = 0;is < this->nspin;++is) + for (int is = 0; is < this->nspin; ++is) { - const T* const amplitudes = this->X[0].template data(); - lr_density.output_eh_density_all_states(amplitudes, is, nstates, this->ofs_running_); + const T *const amplitudes = this->X[0].template data(); + lr_density.output_eh_density_all_states( + amplitudes, + is, + nstates, + this->ofs_running_); } } else { - for (int is = 0;is < this->X.size();++is) + for (int is = 0; is < this->X.size(); ++is) { - const T* const amplitudes = this->X[is].template data(); - lr_density.output_eh_density_all_states(amplitudes, is, nstates, this->ofs_running_); + const T *const amplitudes = this->X[is].template data(); + lr_density.output_eh_density_all_states( + amplitudes, + is, + nstates, + this->ofs_running_); } } } const std::string gauge = LR_Util::tolower(this->inp_->abs_gauge); const bool calculate_spectrum = gauge != "none"; - //cal spectrum - if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity" ) + // cal spectrum + if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { const int nspin_tmp = this->inp_->nspin == 2 ? 2 : 1; - this->velocity_mo = LR_Util::cal_velocity_mo(*this->ucell_, this->gd(), this->tcb(), - this->paraMat_, this->paraC_, this->kv, *this->psi_ks, - this->nk, nspin_tmp, this->nbasis, this->nocc, this->nvirt); + this->velocity_mo = LR_Util::cal_velocity_mo( + *this->ucell_, + this->gd(), + this->tcb(), + this->paraMat_, + this->paraC_, + this->kv, + *this->psi_ks, + this->nk, + nspin_tmp, + this->nbasis, + this->nocc, + this->nvirt); } std::vector freq; if (calculate_spectrum) { freq.resize(100); - std::vector abs_wavelen_range({ 20, 200 });//default range - if (this->inp_->abs_wavelen_range.size() >= 2 && std::abs(this->inp_->abs_wavelen_range[1] - this->inp_->abs_wavelen_range[0]) > 0.02) + std::vector abs_wavelen_range({20, 200}); // default range + if (this->inp_->abs_wavelen_range.size() >= 2 && + std::abs(this->inp_->abs_wavelen_range[1] - this->inp_->abs_wavelen_range[0]) > 0.02) { abs_wavelen_range = this->inp_->abs_wavelen_range; } double lambda_diff = std::abs(abs_wavelen_range[1] - abs_wavelen_range[0]); double lambda_min = std::min(abs_wavelen_range[1], abs_wavelen_range[0]); - for (int i = 0;i < freq.size();++i) { freq[i] = 91.126664 / (lambda_min + 0.01 * static_cast(i + 1) * lambda_diff); } + for (int i = 0; i < freq.size(); ++i) + { + freq[i] = 91.126664 / (lambda_min + 0.01 * static_cast(i + 1) * lambda_diff); + } } - // auto spin_types = (nspin == 2 && !openshell) ? std::vector({ "singlet", "triplet" }) : std::vector({ "updown" }); - // for (int is = 0;is < this->X.size() - 1;++is) - for (int is = 0;is < this->X.size();++is) + // auto spin_types = (nspin == 2 && !openshell) ? std::vector({ "singlet", "triplet" }) : + // std::vector({ "updown" }); for (int is = 0;is < this->X.size() - 1;++is) + for (int is = 0; is < this->X.size(); ++is) { if (!calculate_spectrum) { - const double* const energies = &this->pelec->ekb.c[is * nstates]; - LR_Util::print_excitation_energies(this->ofs_running_, energies, nstates, spin_types[is]); + const double *const energies = &this->pelec->ekb.c[is * nstates]; + LR_Util::print_excitation_energies( + this->ofs_running_, + energies, + nstates, + spin_types[is]); } else { - LR_Spectrum spectrum(nspin, this->nbasis, this->nocc, this->nvirt, *this->pw_rho, *this->psi_ks, - *this->ucell_, this->kv, this->gd(), this->orb_cutoff_, this->tcb(), - this->paraX_, this->paraC_, this->paraMat_, - &this->pelec->ekb.c[is * nstates], this->eig_ks.c, this->X[is].template data(), nstates, openshell, - LR_Util::tolower(this->inp_->abs_gauge), this->my_rank_, this->out_dir); - if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity" ) {spectrum.set_vmo(this->velocity_mo.data());} + LR_Spectrum spectrum( + nspin, + this->nbasis, + this->nocc, + this->nvirt, + *this->pw_rho, + *this->psi_ks, + *this->ucell_, + this->kv, + this->gd(), + this->orb_cutoff_, + this->tcb(), + this->paraX_, + this->paraC_, + this->paraMat_, + &this->pelec->ekb.c[is * nstates], + this->eig_ks.c, + this->X[is].template data(), + nstates, + openshell, + LR_Util::tolower(this->inp_->abs_gauge), + this->my_rank_, + this->out_dir); + if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") + { + spectrum.set_vmo(this->velocity_mo.data()); + } spectrum.cal_spectrum(); - spectrum.transition_analysis(spin_types[is]+"_tda"); - if (spin_types[is] != "triplet") // triplets has no transition dipole and no contribution to the spectrum + spectrum.transition_analysis(spin_types[is] + "_tda"); + if (spin_types[is] != "triplet") // triplets has no transition dipole and no contribution to the spectrum { spectrum.optical_absorption_method1(freq, this->inp_->abs_broadening); - spectrum.write_transition_dipole(this->out_dir + - "trans_dipole_" + spin_types[is] + "_tda.dat"); - // =============================================== for test ==================================================== - // spectrum.optical_absorption_method2(freq, this->inp_->abs_broadening); - // if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") - // { // TEST the formula v/omega rather than v/(e_a-e_i) + spectrum.write_transition_dipole(this->out_dir + "trans_dipole_" + spin_types[is] + "_tda.dat"); + // =============================================== for test + // ==================================================== spectrum.optical_absorption_method2(freq, + // this->inp_->abs_broadening); if (LR_Util::tolower(this->inp_->abs_gauge) == "velocity") { // TEST + // the formula v/omega rather than v/(e_a-e_i) // spectrum.test_transition_dipoles_velocity_omega(); // spectrum.write_transition_dipole(this->out_dir + // "trans_dipole_" + spin_types[is] + "_vomega_tda.dat"); // } - // =============================================== for test ==================================================== + // =============================================== for test + // ==================================================== } } if (this->inp_->cal_force && !this->excited_relax_) diff --git a/source/source_esolver/esolver_lr_lcao_tddft.h b/source/source_esolver/esolver_lr_lcao_tddft.h index 77a2adbc75..6836d99990 100644 --- a/source/source_esolver/esolver_lr_lcao_tddft.h +++ b/source/source_esolver/esolver_lr_lcao_tddft.h @@ -1,388 +1,375 @@ #ifndef ABACUS_SOURCE_ESOLVER_ESOLVER_LR_LCAO_TDDFT_H #define ABACUS_SOURCE_ESOLVER_ESOLVER_LR_LCAO_TDDFT_H -#include "source_esolver/esolver_fp.h" -#include "source_io/module_parameter/input_parameter.h" #include "source_cell/unitcell.h" -#include "source_hamilt/hamilt.h" +#include "source_esolver/esolver_fp.h" +#include "source_esolver/esolver_ks_lcao.h" //for the move constructor #include "source_estate/elecstate.h" -#include "source_hamilt/hamilt.h" #include "source_estate/elecstate_lcao.h" - -#include //future tensor -#include -#include - -#include "source_esolver/esolver_ks_lcao.h" //for the move constructor #include "source_estate/module_dm/density_matrix.h" -#include "source_lcao/module_lr/potentials/pot_hxc_lrtd.h" +#include "source_estate/module_pot/potential_new.h" +#include "source_hamilt/hamilt.h" +#include "source_hamilt/module_gint/gint_info.h" +#include "source_io/module_parameter/input_parameter.h" #include "source_lcao/module_lr/hamilt_casida.h" +#include "source_lcao/module_lr/potentials/pot_hxc_lrtd.h" #include "source_lcao/module_lr/state_track.h" -#include "source_hamilt/module_gint/gint_info.h" -#include "source_estate/module_pot/potential_new.h" + +#include +#include +#include //future tensor #ifdef __EXX // #include -#include "source_lcao/module_ri/exx_lri.h" #include "source_hamilt/module_xc/exx_info.h" // for Exx_Info value member +#include "source_lcao/module_ri/exx_lri.h" #endif namespace LR { -template -struct GradientInputs; +template struct GradientInputs; } namespace ModuleESolver { - struct LRRuntime - { - std::ofstream& running_log; - std::ofstream& warning_log; - int rank; - }; +struct LRRuntime +{ + std::ofstream &running_log; + std::ofstream &warning_log; + int rank; +}; - ///Excited State Solver: Linear Response TDDFT (Tamm Dancoff Approximation) - template - class ESolver_LR : public ModuleESolver::ESolver_FP +/// Excited State Solver: Linear Response TDDFT (Tamm Dancoff Approximation) +template class ESolver_LR : public ModuleESolver::ESolver_FP +{ + public: + ESolver_LR( + const Input_para &inp, + const std::string &in_dir, + const std::string &out_dir, + const LRRuntime &runtime); + ~ESolver_LR() {} + + /// input: input, call, basis(LCAO), psi(ground state), elecstate + // initialize sth. independent of the ground state + virtual void before_all_runners(BaseCell &basecell, const Input_para &inp) override; + virtual void runner(BaseCell &basecell, int istep) override; + virtual void after_all_runners(BaseCell &basecell) override; + + /// Total energy of the excited state being relaxed: E_gs + Omega. Zero outside a + /// relaxation, where nothing consumes it and the old behaviour is kept. + virtual double cal_energy() override; + /// Force on the atoms in the relaxed excited state, F = -d(E_gs + Omega)/dR (Ry/Bohr). + virtual void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; + /// Not implemented: there is no excited-state stress. `cell-relax` is rejected at input. + virtual void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; + + protected: + const std::string in_dir; + const std::string out_dir; + const UnitCell *ucell_ = nullptr; + std::vector orb_cutoff_; + + /// cached aliases, read once here instead of at every log/print call site below + std::ofstream &ofs_running_; + std::ofstream &ofs_warning_; + const int my_rank_; + + /// @brief the ground-state solver, kept alive across ionic steps (esolver_type = "ks-lr"). + /// Null on the `lr` path, where the ground state comes from files instead. + std::unique_ptr> ks_; + + // Geometry-dependent objects that the ground-state solver already builds for the current + // structure. They are aliased rather than rebuilt: `ESolver_KS_LCAO::before_scf` refreshes + // its own copies every ionic step, so recomputing them here would be both wasted work and + // a chance for the two to disagree. On the `lr` path the pointers are bound to this + // object's own members below, which `initialize_from_unitcell_` fills from file. + Grid_Driver gd_own_; ///< only used when `ks_` is null + TwoCenterBundle two_center_bundle_own_; ///< only used when `ks_` is null + Grid_Driver *gd_ptr_ = nullptr; + const TwoCenterBundle *tcb_ptr_ = nullptr; + Parallel_Grid *pgrid_ptr_ = nullptr; + Structure_Factor *sf_ptr_ = nullptr; + pseudopot_cell_vl *locpp_ptr_ = nullptr; + + Grid_Driver &gd() const { return *this->gd_ptr_; } + const TwoCenterBundle &tcb() const { return *this->tcb_ptr_; } + Parallel_Grid &pgrid() const { return *this->pgrid_ptr_; } + Structure_Factor &sfac() const { return *this->sf_ptr_; } + pseudopot_cell_vl &vloc() const { return *this->locpp_ptr_; } + /// bind the aliases above; `ks_` must already be set (or null for the `lr` path) + void bind_ground_state_aliases_(); + + // not to use ElecState because 2-particle state is quite different from 1-particle state. + // implement a independent one (ExcitedState) to pack physical properties if needed. + // put the components of ElecState here: + std::vector> pot; + + // ground state info + + /// @brief ground state wave function + std::unique_ptr> psi_ks; ///< KS orbitals used in the [nocc+nvirt] window + /// @brief all KS orbitals. On the `ks-lr` path this aliases the ground-state solver's + /// `psi` (nk x nbands x nbasis -- far too big to copy every ionic step, and only read + /// here); on the `lr` path it points at `psi_ks_all_own_`, filled from file. + psi::Psi *psi_ks_all_ = nullptr; + std::unique_ptr> psi_ks_all_own_; + + /// @brief ground state bands, read from the file, or moved from ESolver_FP::pelec.ekb + ModuleBase::matrix eig_ks; ///< ground state eigenvalues in the [nocc+nvirt] window + ModuleBase::matrix + eig_ks_all; ///< all eigenvalues of ground state, read from the file, or moved from ESolver_FP::pelec.ekb + ModuleBase::matrix wg_ks; /// occupation numbers of ground state in the [nocc+nvirt] window + ModuleBase::matrix wg_ks_all; /// occupation number of all bands of ground state + + // @brief only needed for force calculation + std::unique_ptr pot_gs; + std::unique_ptr pot_gs_hartree; /// ground-state Hartree potential, only used for test_force + double etxc_gs = 0.; + double vtxc_gs = 0.; + + std::shared_ptr + pot_hxc_gs; /// used in lr-grad, in the ground-state Hxc gradient term coming from dF/dC + + /// @brief Excited state wavefunction (locc, lvirt are local size of nocc and nvirt in each process) + /// size of X: [neq][{nstate, nloc_per_state}], namely: + /// - [nspin][{nstates, nk* (locc* lvirt}] for close- shell, + /// - [1][{nstates, nk * (locc[0] * lvirt[0]) + nk * (locc[1] * lvirt[1])}] for open-shell + std::vector X; + int nloc_per_state = 1; + + std::vector nocc; ///< number of occupied orbitals for each spin used in the calculation + int nocc_in = 1; ///< nocc read from input (adjusted by nelec): max(spin-up, spindown) + int nocc_max = 1; ///< full occupied count in the largest spin channel + std::vector nvirt; ///< number of virtual orbitals for each spin used in the calculation + int nvirt_in = 1; ///< nvirt read from input (adjusted by nelec): min(spin-up, spindown) + int nbands = 2; + int nbasis = 2; + /// n_occ*nvirt, the basis size of electron-hole pair representation + std::vector npairs; + /// how many 2-particle states to be solved + int nstates = 1; + int nspin = 1; + int nk = 1; + int nupdown = 0; + bool openshell = false; + std::string xc_kernel; + + void initialize_from_unitcell_(UnitCell &ucell, const Input_para &inp); + /// one-time setup from the ground-state solver; ends by calling `refresh_from_ks_` + void initialize_from_ks_(UnitCell &ucell, const Input_para &inp); + /// re-read everything that depends on the atomic positions, once per ionic step + void refresh_from_ks_(UnitCell &ucell); + bool ks_initialized_ = false; ///< whether `initialize_from_ks_` has already run + bool exx_owned_ = false; ///< `exx_lri` was built here (so its Cs/Vs are ours to refresh) + + // ---------- geometry relaxation on an excited state ---------- + /// resolve and validate `lr_target_state` / `lr_target_spin`; call once the dimensions + /// (and therefore `openshell`) are final + void setup_relax_target_(); + bool excited_relax_ = false; ///< driving `calculation = relax` from an excited state + int target_is_ = 0; ///< spin block of the relaxed state in `X` and `pelec->ekb` + double etot_gs_ = 0.0; ///< ground-state total energy of the current step (Ry) + ModuleBase::matrix force_gs_; ///< ground-state force of the current step (Ry/Bohr, F = -dE/dR) + /// The LR part of the excited-state force, -d(Omega)/dR (Ry/Bohr). + ModuleBase::matrix lr_force_; + /// The state currently being followed, as an index into `X` / `pelec->ekb`. + /// Seeded from `lr_target_state` on the first ionic step, then re-chosen at every + /// later step by cross-geometry group overlap, then the single/JT reference. + /// Following a fixed INDEX instead is what makes a relaxation fail near a + /// degeneracy: the index always names the n-th lowest root, so as soon as two + /// surfaces cross, "the target" jumps to a different diabatic state and the force + /// is discontinuous. CG assumes a conservative field and cannot recover from that. + int target_state_ = -1; + /// Previous ionic step's amplitude for the followed state (local part), the + /// reference the overlap is taken against. Empty on the first step. + std::vector target_X_prev_; + LR::RootBasis target_basis_prev_; + /// Match the old subspace to current energy groups and refresh the single/group references. + /// `ofs` receives the note when the followed root changes index, and the warning when + /// no current root resembles the previous one. + void follow_target_state_(std::ofstream &ofs); + + /// index of the relaxed state inside `pelec->ekb` + int target_ekb_offset_() const { - public: - ESolver_LR(const Input_para& inp, const std::string& in_dir, const std::string& out_dir, const LRRuntime& runtime); - ~ESolver_LR() {} - - ///input: input, call, basis(LCAO), psi(ground state), elecstate - // initialize sth. independent of the ground state - virtual void before_all_runners(BaseCell& basecell, const Input_para& inp) override; - virtual void runner(BaseCell& basecell, int istep) override; - virtual void after_all_runners(BaseCell& basecell) override; - - /// Total energy of the excited state being relaxed: E_gs + Omega. Zero outside a - /// relaxation, where nothing consumes it and the old behaviour is kept. - virtual double cal_energy() override; - /// Force on the atoms in the relaxed excited state, F = -d(E_gs + Omega)/dR (Ry/Bohr). - virtual void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; - /// Not implemented: there is no excited-state stress. `cell-relax` is rejected at input. - virtual void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; - - protected: - const std::string in_dir; - const std::string out_dir; - const UnitCell* ucell_ = nullptr; - std::vector orb_cutoff_; - - /// cached aliases, read once here instead of at every log/print call site below - std::ofstream& ofs_running_; - std::ofstream& ofs_warning_; - const int my_rank_; - - /// @brief the ground-state solver, kept alive across ionic steps (esolver_type = "ks-lr"). - /// Null on the `lr` path, where the ground state comes from files instead. - std::unique_ptr> ks_; - - // Geometry-dependent objects that the ground-state solver already builds for the current - // structure. They are aliased rather than rebuilt: `ESolver_KS_LCAO::before_scf` refreshes - // its own copies every ionic step, so recomputing them here would be both wasted work and - // a chance for the two to disagree. On the `lr` path the pointers are bound to this - // object's own members below, which `initialize_from_unitcell_` fills from file. - Grid_Driver gd_own_; ///< only used when `ks_` is null - TwoCenterBundle two_center_bundle_own_; ///< only used when `ks_` is null - Grid_Driver* gd_ptr_ = nullptr; - const TwoCenterBundle* tcb_ptr_ = nullptr; - Parallel_Grid* pgrid_ptr_ = nullptr; - Structure_Factor* sf_ptr_ = nullptr; - pseudopot_cell_vl* locpp_ptr_ = nullptr; - - Grid_Driver& gd() const - { - return *this->gd_ptr_; - } - const TwoCenterBundle& tcb() const - { - return *this->tcb_ptr_; - } - Parallel_Grid& pgrid() const - { - return *this->pgrid_ptr_; - } - Structure_Factor& sfac() const - { - return *this->sf_ptr_; - } - pseudopot_cell_vl& vloc() const - { - return *this->locpp_ptr_; - } - /// bind the aliases above; `ks_` must already be set (or null for the `lr` path) - void bind_ground_state_aliases_(); - - // not to use ElecState because 2-particle state is quite different from 1-particle state. - // implement a independent one (ExcitedState) to pack physical properties if needed. - // put the components of ElecState here: - std::vector> pot; - - // ground state info - - /// @brief ground state wave function - std::unique_ptr> psi_ks; ///< KS orbitals used in the [nocc+nvirt] window - /// @brief all KS orbitals. On the `ks-lr` path this aliases the ground-state solver's - /// `psi` (nk x nbands x nbasis -- far too big to copy every ionic step, and only read - /// here); on the `lr` path it points at `psi_ks_all_own_`, filled from file. - psi::Psi* psi_ks_all_ = nullptr; - std::unique_ptr> psi_ks_all_own_; - - /// @brief ground state bands, read from the file, or moved from ESolver_FP::pelec.ekb - ModuleBase::matrix eig_ks;///< ground state eigenvalues in the [nocc+nvirt] window - ModuleBase::matrix eig_ks_all; ///< all eigenvalues of ground state, read from the file, or moved from ESolver_FP::pelec.ekb - ModuleBase::matrix wg_ks; /// occupation numbers of ground state in the [nocc+nvirt] window - ModuleBase::matrix wg_ks_all; /// occupation number of all bands of ground state - - - // @brief only needed for force calculation - std::unique_ptr pot_gs; - std::unique_ptr pot_gs_hartree; /// ground-state Hartree potential, only used for test_force - double etxc_gs = 0.; - double vtxc_gs = 0.; - - std::shared_ptr pot_hxc_gs; /// used in lr-grad, in the ground-state Hxc gradient term coming from dF/dC - - /// @brief Excited state wavefunction (locc, lvirt are local size of nocc and nvirt in each process) - /// size of X: [neq][{nstate, nloc_per_state}], namely: - /// - [nspin][{nstates, nk* (locc* lvirt}] for close- shell, - /// - [1][{nstates, nk * (locc[0] * lvirt[0]) + nk * (locc[1] * lvirt[1])}] for open-shell - std::vector X; - int nloc_per_state = 1; - - std::vector nocc; ///< number of occupied orbitals for each spin used in the calculation - int nocc_in = 1; ///< nocc read from input (adjusted by nelec): max(spin-up, spindown) - int nocc_max = 1; ///< full occupied count in the largest spin channel - std::vector nvirt; ///< number of virtual orbitals for each spin used in the calculation - int nvirt_in = 1; ///< nvirt read from input (adjusted by nelec): min(spin-up, spindown) - int nbands = 2; - int nbasis = 2; - /// n_occ*nvirt, the basis size of electron-hole pair representation - std::vector npairs; - /// how many 2-particle states to be solved - int nstates = 1; - int nspin = 1; - int nk = 1; - int nupdown = 0; - bool openshell = false; - std::string xc_kernel; - - void initialize_from_unitcell_(UnitCell& ucell, const Input_para& inp); - /// one-time setup from the ground-state solver; ends by calling `refresh_from_ks_` - void initialize_from_ks_(UnitCell& ucell, const Input_para& inp); - /// re-read everything that depends on the atomic positions, once per ionic step - void refresh_from_ks_(UnitCell& ucell); - bool ks_initialized_ = false; ///< whether `initialize_from_ks_` has already run - bool exx_owned_ = false; ///< `exx_lri` was built here (so its Cs/Vs are ours to refresh) - - // ---------- geometry relaxation on an excited state ---------- - /// resolve and validate `lr_target_state` / `lr_target_spin`; call once the dimensions - /// (and therefore `openshell`) are final - void setup_relax_target_(); - bool excited_relax_ = false; ///< driving `calculation = relax` from an excited state - int target_is_ = 0; ///< spin block of the relaxed state in `X` and `pelec->ekb` - double etot_gs_ = 0.0; ///< ground-state total energy of the current step (Ry) - ModuleBase::matrix force_gs_; ///< ground-state force of the current step (Ry/Bohr, F = -dE/dR) - /// The LR part of the excited-state force, -d(Omega)/dR (Ry/Bohr). - ModuleBase::matrix lr_force_; - /// The state currently being followed, as an index into `X` / `pelec->ekb`. - /// Seeded from `lr_target_state` on the first ionic step, then re-chosen at every - /// later step by cross-geometry group overlap, then the single/JT reference. - /// Following a fixed INDEX instead is what makes a relaxation fail near a - /// degeneracy: the index always names the n-th lowest root, so as soon as two - /// surfaces cross, "the target" jumps to a different diabatic state and the force - /// is discontinuous. CG assumes a conservative field and cannot recover from that. - int target_state_ = -1; - /// Previous ionic step's amplitude for the followed state (local part), the - /// reference the overlap is taken against. Empty on the first step. - std::vector target_X_prev_; - LR::RootBasis target_basis_prev_; - /// Match the old subspace to current energy groups and refresh the single/group references. - /// `ofs` receives the note when the followed root changes index, and the warning when - /// no current root resembles the previous one. - void follow_target_state_(std::ofstream& ofs); - - /// index of the relaxed state inside `pelec->ekb` - int target_ekb_offset_() const - { return this->openshell ? this->target_state_ - : this->target_is_ * this->nstates + this->target_state_; } - - std::vector spin_types; - - std::unique_ptr gint_info_ = nullptr; - void set_gint(); - - /// @brief variables for parallel distribution of KS orbitals - Parallel_2D paraC_; - /// @brief variables for parallel distribution of excited states - std::vector paraX_; - - // ---------------- the Z-vector (CPSCF) window ---------------- - // The Z-vector equation enforces the Brillouin condition in EVERY occupied-virtual - // rotation, so it must not be confined to the `nvirt` window X lives in. - // It should be the whole AO virtual space. - // - // These mirror `psi_ks` / `eig_ks` / `paraC_` / `paraX_` / `nvirt` / `nloc_per_state` - // but span every virtual band the ground state produced (the input `nbands`), so the - // window is widened by raising *nbands*, not `nvirt`. X keeps its own window, so Omega - // -- and with it any finite-difference reference -- is untouched. - std::unique_ptr> psi_ks_z_; - ModuleBase::matrix eig_ks_z_; - Parallel_2D paraC_z_; - std::vector paraX_z_; - std::vector nvirt_z_; - int nbands_z_ = 0; - int nloc_per_state_z_ = 0; - /// (re)build the Z window from `psi_ks_all_` / `eig_ks_all`. `desc_src` describes the - /// source wavefunction's 2D layout; unused (and may be null) in a serial build. - void fill_z_window_(const int* desc_src); - /// Widen `nst` X blocks starting at `istate_begin` from the X window into the Z window, - /// zero-filling the virtual rows X does not have. - ct::Tensor pad_X_to_z_(const int ispin, const int istate_begin, const int nst) const; - /// @brief variables for parallel distribution of matrix in AO representation - Parallel_Orbitals paraMat_; - Parallel_Orbitals paraMat_all_; // for the parallelized size of the KS orbitals - - - LCAO_Orbitals orb_; ///< numerical atomic orbital data for single-point evaluation - std::vector> velocity_mo; ///< store the velocity matrix elements in MO basis - - /// @brief allocate and set the inital value of X - void setup_eigenvectors_X(); - void set_X_initial_guess(); - - /// @brief read in the ground state wave function, band energy and occupation - virtual void read_ks_wfc(); - /// @brief read in the ground state charge density - void read_ks_chg(Charge& chg); - - virtual void init_pot(const Charge& chg_gs); - - /// @brief check the legality of the input parameters - /// @brief set nocc, nvirt, nbasis, npairs and nstates - void set_dimension(); - /// reset nocc, nvirt, npairs after read ground-state wavefunction when nspin=2 - void reset_dim_spin2(); - - /// setup Parallel_Orbitals info. beyond Parallel_2D - void set_parallel_orbitals_band(Parallel_Orbitals& p, const int nbands_in); - - ///========================== for gradient calculation ========================= - void init_pot_groundstate(const Charge& chg_gs); - /// Solve the Z-vector equation for `nst` independent blocks of `Xz`. - ct::Tensor solve_zvector_eqation(const int ispin, const int nst, const ct::Tensor& Xz); - /// Excited-state gradients d(Omega)/dR, one matrix per state solved. `istate_only >= 0` - /// restricts it to that one state: geometry relaxation follows a single state, and the - /// Z-vector solve dominates the cost. -1 does all `nstates`. - std::vector cal_force(const int ispin, const int istate_only = -1); - /// open-shell (spin-unrestricted) excited-state force: X holds [up | down] and every - /// density matrix has two independent channels - std::vector cal_force_openshell(const int istate_only = -1); - /// @brief Gradients for excitation vectors supplied by the caller, already widened into - /// the Z window -- the two functions above are thin wrappers that widen the stored - /// eigenvectors and look up their `omega`. - /// - /// The blocks of `Xz` need not be the eigenvectors the Casida diagonalizer returned. Any - /// normalized vector inside a degenerate multiplet is an eigenvector with the same - /// `omega`, so passing a linear combination is what turns the per-state gradient into the - /// full degenerate-subspace gradient matrix; see `cal_grad_matrix_degenerate` and - /// `grad_degen.h`. - /// - /// @param omega excitation energy of each block (Ry); its size sets the block count - /// @param label_begin state index the first block is reported under (labels only) - std::vector cal_force_Xz(const int ispin, const ct::Tensor& Xz, - const std::vector& omega, const int label_begin); - /// open-shell counterpart of `cal_force_Xz` - std::vector cal_force_openshell_Xz(const ct::Tensor& Xz, - const std::vector& omega, const int label_begin); - /// @brief The linear vibronic coupling (LVC) data of one degenerate multiplet. - /// - /// $H(\delta R)=\Omega_0\mathbb{1}+\sum_{A\alpha}\delta R_{A\alpha}G^{(A\alpha)}$ is the - /// complete first-order description of a degeneracy, and $G$ is its parameter set. Kept as - /// one object rather than as loose force matrices because the excited-state relaxation and - /// (later) non-adiabatic dynamics need exactly the same data: near a degeneracy the correct - /// propagation is on this coupled $d\times d$ model, not on an adiabatic gradient. - struct MultipletLVC - { - int ispin = 0; ///< which spin channel (index into `spin_types`) - std::vector states; ///< the multiplet's state indices, ascending - double omega0 = 0.0; ///< the common excitation energy (Ry) - double omega_spread = 0.0; ///< max - min over the members (Ry); 0 if exact - /// G[k][l], symmetric, each a (nat, 3) force matrix -- i.e. the 3N matrices of d x d - std::vector> g; - int dim() const - { - return static_cast(states.size()); - } - /// $\operatorname{Tr}G/d$: the one smooth, basis-independent 3N vector field the - /// multiplet has. Following it preserves the symmetric configuration. - ModuleBase::matrix average_force() const; - }; - /// LVC data of every multiplet found at this geometry, rebuilt on each call of - /// `cal_force_and_grad_matrix_`. Empty unless `lr_degen_thr > 0`. - std::vector multiplet_lvc_; - /// The multiplet `lr_target_state` belongs to, or empty when the target is non-degenerate - /// or `lr_degen_mode = state`. Refreshed every ionic step by - /// `resolve_target_multiplet_`, and it is what makes `cal_energy` and the reported gradient - /// describe the same surface. - std::vector target_group_; - /// Fill `target_group_` from the excitation energies of the current geometry. - void resolve_target_multiplet_(); - /// The excitation energy the relaxation is minimising: the target state's own, or the - /// multiplet average when `target_group_` is set. - double target_omega_() const; - /// The LR half of the force for the current geometry, following whichever surface - /// `lr_degen_mode` selects. `ofs` receives the note when that is not a single state. - ModuleBase::matrix cal_lr_force_relax_(std::ofstream& ofs); - /// @brief The force of the steepest-descending branch of the target multiplet, i.e. - /// `lr_degen_mode = jt`. - /// - /// Assembles the off-diagonal part of the gradient matrix (which `average` does not need), - /// solves the joint direction/mixing optimization in `LR::find_jt_direction`, and returns - /// that branch's own force. Once a step has split the multiplet there is no group left and - /// the ordinary single-state path takes over, so the mode is self-limiting. - /// - /// @param diag the multiplet's per-state forces, already computed - ModuleBase::matrix cal_jt_force_(const std::vector& diag, - std::ofstream& ofs); - LR::GradientInputs gradient_inputs_() const; - /// Widen a multiplet's eigenvectors into the Z window, one block each. Members need not be - /// contiguous, so they are padded one at a time. - ct::Tensor pad_group_to_z_(const int ispin, const std::vector& group) const; - /// @brief Per-state gradients of every state, plus the gradient matrix of each degenerate - /// multiplet when `lr_degen_thr` asks for it. The single-point entry point. - /// - /// Fills `multiplet_lvc_`. - void cal_force_and_grad_matrix_(const int ispin, std::ofstream& ofs); - /// @brief The gradient matrix of one degenerate multiplet, - /// $G^{(A\alpha)}_{kl}=\langle X_k|\partial A/\partial R_{A\alpha}|X_l\rangle$. - /// - /// At a degeneracy no single state has a gradient vector -- the branch slopes along a - /// displacement $u$ are the eigenvalues of $\sum_{A\alpha}u_{A\alpha}G^{(A\alpha)}$, whose - /// eigenvectors depend on $u$ -- so this whole matrix, not its diagonal, is the first-order - /// information. It is obtained from the polarization identity - /// $G_{kl}=\mathcal F[(X_k{+}X_l)/\sqrt2]-\tfrac12(G_{kk}+G_{ll})$, which needs no new - /// physics. `grad_degen.h` derives why that is exact. - /// - /// @param group state indices of the multiplet, from `LR::group_degenerate_states` - /// @param diag their per-state gradients, i.e. $G_{kk}$, already computed by `cal_force` - /// @param ofs log stream the matrix and the precondition diagnostics are written to - /// @return G[k][l], symmetric, each entry a (nat, 3) force matrix - std::vector> cal_grad_matrix_degenerate(const int ispin, - const std::vector& group, const std::vector& diag, - std::ofstream& ofs); - void test_force(); // test: reproduce the force of ground state - module_dm::DensityMatrix cal_dm_gs(); ///< ground-state density matrix + return this->openshell ? this->target_state_ : this->target_is_ * this->nstates + this->target_state_; + } + + std::vector spin_types; + + std::unique_ptr gint_info_ = nullptr; + void set_gint(); + + /// @brief variables for parallel distribution of KS orbitals + Parallel_2D paraC_; + /// @brief variables for parallel distribution of excited states + std::vector paraX_; + + // ---------------- the Z-vector (CPSCF) window ---------------- + // The Z-vector equation enforces the Brillouin condition in EVERY occupied-virtual + // rotation, so it must not be confined to the `nvirt` window X lives in. + // It should be the whole AO virtual space. + // + // These mirror `psi_ks` / `eig_ks` / `paraC_` / `paraX_` / `nvirt` / `nloc_per_state` + // but span every virtual band the ground state produced (the input `nbands`), so the + // window is widened by raising *nbands*, not `nvirt`. X keeps its own window, so Omega + // -- and with it any finite-difference reference -- is untouched. + std::unique_ptr> psi_ks_z_; + ModuleBase::matrix eig_ks_z_; + Parallel_2D paraC_z_; + std::vector paraX_z_; + std::vector nvirt_z_; + int nbands_z_ = 0; + int nloc_per_state_z_ = 0; + /// (re)build the Z window from `psi_ks_all_` / `eig_ks_all`. `desc_src` describes the + /// source wavefunction's 2D layout; unused (and may be null) in a serial build. + void fill_z_window_(const int *desc_src); + /// Widen `nst` X blocks starting at `istate_begin` from the X window into the Z window, + /// zero-filling the virtual rows X does not have. + ct::Tensor pad_X_to_z_(const int ispin, const int istate_begin, const int nst) const; + /// @brief variables for parallel distribution of matrix in AO representation + Parallel_Orbitals paraMat_; + Parallel_Orbitals paraMat_all_; // for the parallelized size of the KS orbitals + + LCAO_Orbitals orb_; ///< numerical atomic orbital data for single-point evaluation + std::vector> velocity_mo; ///< store the velocity matrix elements in MO basis + + /// @brief allocate and set the inital value of X + void setup_eigenvectors_X(); + void set_X_initial_guess(); + + /// @brief read in the ground state wave function, band energy and occupation + virtual void read_ks_wfc(); + /// @brief read in the ground state charge density + void read_ks_chg(Charge &chg); + + virtual void init_pot(const Charge &chg_gs); + + /// @brief check the legality of the input parameters + /// @brief set nocc, nvirt, nbasis, npairs and nstates + void set_dimension(); + /// reset nocc, nvirt, npairs after read ground-state wavefunction when nspin=2 + void reset_dim_spin2(); + + /// setup Parallel_Orbitals info. beyond Parallel_2D + void set_parallel_orbitals_band(Parallel_Orbitals &p, const int nbands_in); + + ///========================== for gradient calculation ========================= + void init_pot_groundstate(const Charge &chg_gs); + /// Solve the Z-vector equation for `nst` independent blocks of `Xz`. + ct::Tensor solve_zvector_eqation(const int ispin, const int nst, const ct::Tensor &Xz); + /// Excited-state gradients d(Omega)/dR, one matrix per state solved. `istate_only >= 0` + /// restricts it to that one state: geometry relaxation follows a single state, and the + /// Z-vector solve dominates the cost. -1 does all `nstates`. + std::vector cal_force(const int ispin, const int istate_only = -1); + /// open-shell (spin-unrestricted) excited-state force: X holds [up | down] and every + /// density matrix has two independent channels + std::vector cal_force_openshell(const int istate_only = -1); + /// @brief Gradients for excitation vectors supplied by the caller, already widened into + /// the Z window -- the two functions above are thin wrappers that widen the stored + /// eigenvectors and look up their `omega`. + /// + /// The blocks of `Xz` need not be the eigenvectors the Casida diagonalizer returned. Any + /// normalized vector inside a degenerate multiplet is an eigenvector with the same + /// `omega`, so passing a linear combination is what turns the per-state gradient into the + /// full degenerate-subspace gradient matrix; see `cal_grad_matrix_degenerate` and + /// `grad_degen.h`. + /// + /// @param omega excitation energy of each block (Ry); its size sets the block count + /// @param label_begin state index the first block is reported under (labels only) + std::vector cal_force_Xz( + const int ispin, + const ct::Tensor &Xz, + const std::vector &omega, + const int label_begin); + /// open-shell counterpart of `cal_force_Xz` + std::vector cal_force_openshell_Xz( + const ct::Tensor &Xz, const std::vector &omega, const int label_begin); + /// @brief The linear vibronic coupling (LVC) data of one degenerate multiplet. + /// + /// $H(\delta R)=\Omega_0\mathbb{1}+\sum_{A\alpha}\delta R_{A\alpha}G^{(A\alpha)}$ is the + /// complete first-order description of a degeneracy, and $G$ is its parameter set. Kept as + /// one object rather than as loose force matrices because the excited-state relaxation and + /// (later) non-adiabatic dynamics need exactly the same data: near a degeneracy the correct + /// propagation is on this coupled $d\times d$ model, not on an adiabatic gradient. + struct MultipletLVC + { + int ispin = 0; ///< which spin channel (index into `spin_types`) + std::vector states; ///< the multiplet's state indices, ascending + double omega0 = 0.0; ///< the common excitation energy (Ry) + double omega_spread = 0.0; ///< max - min over the members (Ry); 0 if exact + /// G[k][l], symmetric, each a (nat, 3) force matrix -- i.e. the 3N matrices of d x d + std::vector> g; + int dim() const { return static_cast(states.size()); } + /// $\operatorname{Tr}G/d$: the one smooth, basis-independent 3N vector field the + /// multiplet has. Following it preserves the symmetric configuration. + ModuleBase::matrix average_force() const; + }; + /// LVC data of every multiplet found at this geometry, rebuilt on each call of + /// `cal_force_and_grad_matrix_`. Empty unless `lr_degen_thr > 0`. + std::vector multiplet_lvc_; + /// The multiplet `lr_target_state` belongs to, or empty when the target is non-degenerate + /// or `lr_degen_mode = state`. Refreshed every ionic step by + /// `resolve_target_multiplet_`, and it is what makes `cal_energy` and the reported gradient + /// describe the same surface. + std::vector target_group_; + /// Fill `target_group_` from the excitation energies of the current geometry. + void resolve_target_multiplet_(); + /// The excitation energy the relaxation is minimising: the target state's own, or the + /// multiplet average when `target_group_` is set. + double target_omega_() const; + /// The LR half of the force for the current geometry, following whichever surface + /// `lr_degen_mode` selects. `ofs` receives the note when that is not a single state. + ModuleBase::matrix cal_lr_force_relax_(std::ofstream &ofs); + /// @brief The force of the steepest-descending branch of the target multiplet, i.e. + /// `lr_degen_mode = jt`. + /// + /// Assembles the off-diagonal part of the gradient matrix (which `average` does not need), + /// solves the joint direction/mixing optimization in `LR::find_jt_direction`, and returns + /// that branch's own force. Once a step has split the multiplet there is no group left and + /// the ordinary single-state path takes over, so the mode is self-limiting. + /// + /// @param diag the multiplet's per-state forces, already computed + ModuleBase::matrix cal_jt_force_(const std::vector &diag, std::ofstream &ofs); + LR::GradientInputs gradient_inputs_() const; + /// Widen a multiplet's eigenvectors into the Z window, one block each. Members need not be + /// contiguous, so they are padded one at a time. + ct::Tensor pad_group_to_z_(const int ispin, const std::vector &group) const; + /// @brief Per-state gradients of every state, plus the gradient matrix of each degenerate + /// multiplet when `lr_degen_thr` asks for it. The single-point entry point. + /// + /// Fills `multiplet_lvc_`. + void cal_force_and_grad_matrix_(const int ispin, std::ofstream &ofs); + /// @brief The gradient matrix of one degenerate multiplet, + /// $G^{(A\alpha)}_{kl}=\langle X_k|\partial A/\partial R_{A\alpha}|X_l\rangle$. + /// + /// At a degeneracy no single state has a gradient vector -- the branch slopes along a + /// displacement $u$ are the eigenvalues of $\sum_{A\alpha}u_{A\alpha}G^{(A\alpha)}$, whose + /// eigenvectors depend on $u$ -- so this whole matrix, not its diagonal, is the first-order + /// information. It is obtained from the polarization identity + /// $G_{kl}=\mathcal F[(X_k{+}X_l)/\sqrt2]-\tfrac12(G_{kk}+G_{ll})$, which needs no new + /// physics. `grad_degen.h` derives why that is exact. + /// + /// @param group state indices of the multiplet, from `LR::group_degenerate_states` + /// @param diag their per-state gradients, i.e. $G_{kk}$, already computed by `cal_force` + /// @param ofs log stream the matrix and the precondition diagnostics are written to + /// @return G[k][l], symmetric, each entry a (nat, 3) force matrix + std::vector> cal_grad_matrix_degenerate( + const int ispin, + const std::vector &group, + const std::vector &diag, + std::ofstream &ofs); + void test_force(); // test: reproduce the force of ground state + module_dm::DensityMatrix cal_dm_gs(); ///< ground-state density matrix #ifdef __EXX - /// Tdata of Exx_LRI is same as T, for the reason, see operator_lr_exx.h - std::shared_ptr> exx_lri = nullptr; - /// share the ground-state solver's Exx_LRI. It is shared, not stolen: the KS solver - /// keeps using it on the next ionic step. - void share_exx_lri(std::shared_ptr>&); - void share_exx_lri(std::shared_ptr>>&); - Exx_Info exx_info; + /// Tdata of Exx_LRI is same as T, for the reason, see operator_lr_exx.h + std::shared_ptr> exx_lri = nullptr; + /// share the ground-state solver's Exx_LRI. It is shared, not stolen: the KS solver + /// keeps using it on the next ionic step. + void share_exx_lri(std::shared_ptr> &); + void share_exx_lri(std::shared_ptr>> &); + Exx_Info exx_info; #endif - }; -} +}; +} // namespace ModuleESolver #endif // ABACUS_SOURCE_ESOLVER_ESOLVER_LR_LCAO_TDDFT_H diff --git a/source/source_esolver/esolver_lr_orb.cpp b/source/source_esolver/esolver_lr_orb.cpp index ff0492ddf6..c4e31b255a 100644 --- a/source/source_esolver/esolver_lr_orb.cpp +++ b/source/source_esolver/esolver_lr_orb.cpp @@ -1,16 +1,17 @@ // LR orbital distributions, excitation amplitudes, and ground-state file input. #include "esolver_lr_lcao_tddft.h" -#include "source_lcao/module_lr/utils/lr_util.h" -#include "source_lcao/module_lr/ri_benchmark/ri_benchmark.h" -#include "source_io/module_wf/read_wfc_nao.h" -#include "source_io/module_output/cube_io.h" #include "source_base/module_external/scalapack_connector.h" +#include "source_io/module_output/cube_io.h" +#include "source_io/module_wf/read_wfc_nao.h" +#include "source_lcao/module_lr/ri_benchmark/ri_benchmark.h" +#include "source_lcao/module_lr/utils/lr_util.h" + #include using namespace LR; -template -void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbitals& pmat, const int nbands_in) +template +void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbitals &pmat, const int nbands_in) { #ifdef __MPI const int leading_dimension = std::max(pmat.get_row_size(), 1); @@ -19,7 +20,12 @@ void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbit // have fewer blocks than the inherited KS process grid has columns. Parallel_2D bands; const int block_size = pmat.get_block_size(); - LR_Util::setup_2d_division(bands, block_size, this->nbasis, nbands_in, pmat.blacs_ctxt); + LR_Util::setup_2d_division( + bands, + block_size, + this->nbasis, + nbands_in, + pmat.blacs_ctxt); pmat.nbands = nbands_in; pmat.nrow_bands = bands.get_row_size(); pmat.ncol_bands = bands.get_col_size(); @@ -39,28 +45,33 @@ void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbit #endif } -template -void ModuleESolver::ESolver_LR::setup_eigenvectors_X() +template void ModuleESolver::ESolver_LR::setup_eigenvectors_X() { ModuleBase::TITLE("ESolver_LR", "setup_eigenvectors_X"); // this function is called once per `runner`, and `paraX_` is only ever appended to, // so without this reset a second ionic step would double its size this->paraX_.clear(); const int block_size = this->paraC_.get_block_size(); - for (int is = 0;is < nspin;++is) + for (int is = 0; is < nspin; ++is) { Parallel_2D px; - LR_Util::setup_2d_division(px, block_size, this->nvirt[is], this->nocc[is] + LR_Util::setup_2d_division( + px, + block_size, + this->nvirt[is], + this->nocc[is] #ifdef __MPI - , this->paraC_.blacs_ctxt + , + this->paraC_.blacs_ctxt #endif - );//nvirt - row, nocc - col + ); // nvirt - row, nocc - col this->paraX_.emplace_back(std::move(px)); } - this->nloc_per_state = nk * (openshell ? paraX_[0].get_local_size() + paraX_[1].get_local_size() : paraX_[0].get_local_size()); + this->nloc_per_state = + nk * (openshell ? paraX_[0].get_local_size() + paraX_[1].get_local_size() : paraX_[0].get_local_size()); - this->X.resize(openshell ? 1 : nspin, LR_Util::newTensor({ nstates, nloc_per_state })); - for (auto& x: X) + this->X.resize(openshell ? 1 : nspin, LR_Util::newTensor({nstates, nloc_per_state})); + for (auto &x : X) { x.zero(); } @@ -72,21 +83,20 @@ void ModuleESolver::ESolver_LR::setup_eigenvectors_X() } } -template -void ModuleESolver::ESolver_LR::set_X_initial_guess() +template void ModuleESolver::ESolver_LR::set_X_initial_guess() { // set the initial guess of X - for (int is = 0;is < this->nspin;++is) + for (int is = 0; is < this->nspin; ++is) { - const int& no = this->nocc[is]; - const int& nv = this->nvirt[is]; - const int& np = this->npairs[is]; - const Parallel_2D& px = this->paraX_[is]; + const int &no = this->nocc[is]; + const int &nv = this->nvirt[is]; + const int &np = this->npairs[is]; + const Parallel_2D &px = this->paraX_[is]; // if (E_{lumo}-E_{homo-1} < E_{lumo+1}-E{homo}), mode = 0, else 1(smaller first) - bool ix_mode = false; //default - if (this->eig_ks.nc > no + 1 && no >= 2 - && eig_ks(is, no) - eig_ks(is, no - 2) - 1e-5 > eig_ks(is, no + 1) - eig_ks(is, no - 1)) + bool ix_mode = false; // default + if (this->eig_ks.nc > no + 1 && no >= 2 && + eig_ks(is, no) - eig_ks(is, no - 2) - 1e-5 > eig_ks(is, no + 1) - eig_ks(is, no - 1)) { ix_mode = true; } @@ -113,34 +123,40 @@ void ModuleESolver::ESolver_LR::set_X_initial_guess() for (int ib = 0; ib < nstates; ++ib) { const int ipair = ib % np; - const int occ_global = std::get<0>(ix2ioiv[ipair]); // occ - const int virt_global = std::get<1>(ix2ioiv[ipair]); // virt + const int occ_global = std::get<0>(ix2ioiv[ipair]); // occ + const int virt_global = std::get<1>(ix2ioiv[ipair]); // virt const int ik = ib / np; - const int xstart_b = ib * nloc_per_state; //start index of band ib - const int xstart_bs = (openshell && is == 1) ? xstart_b + nk * paraX_[0].get_local_size() : xstart_b; // start index of band ib, spin is - const int is_in_x = openshell ? 0 : is; // if openshell, spin-up and spin-down are put together + const int xstart_b = ib * nloc_per_state; // start index of band ib + const int xstart_bs = (openshell && is == 1) ? xstart_b + nk * paraX_[0].get_local_size() + : xstart_b; // start index of band ib, spin is + const int is_in_x = openshell ? 0 : is; // if openshell, spin-up and spin-down are put together if (px.in_this_processor(virt_global, occ_global)) { const int xstart_pair = ik * px.get_local_size(); - const int ipair_loc = px.global2local_col(occ_global) * px.get_row_size() + px.global2local_row(virt_global); + const int ipair_loc = + px.global2local_col(occ_global) * px.get_row_size() + px.global2local_row(virt_global); X[is_in_x].data()[xstart_bs + xstart_pair + ipair_loc] = (static_cast(1.0) / static_cast(nk)); } } } } -template -void ModuleESolver::ESolver_LR::read_ks_wfc() +template void ModuleESolver::ESolver_LR::read_ks_wfc() { assert(this->psi_ks != nullptr); this->eig_ks.create(this->kv.get_nks(), this->nbands); this->wg_ks.create(this->kv.get_nks(), this->nbands); - if (this->inp_->ri_hartree_benchmark == "aims") // for aims benchmark + if (this->inp_->ri_hartree_benchmark == "aims") // for aims benchmark { #ifdef __EXX int ncore = 0; - std::vector eig_ks_vec = RI_Benchmark::read_aims_ebands(this->in_dir + "band_out", nocc_in, nvirt_in, ncore); - std::cout << "ncore=" << ncore << ", nocc=" << nocc_in << ", nvirt=" << nvirt_in << ", nbands=" << this->nbands << std::endl; + std::vector eig_ks_vec = RI_Benchmark::read_aims_ebands( + this->in_dir + "band_out", + nocc_in, + nvirt_in, + ncore); + std::cout << "ncore=" << ncore << ", nocc=" << nocc_in << ", nvirt=" << nvirt_in << ", nbands=" << this->nbands + << std::endl; std::cout << "eig_ks_vec.size()=" << eig_ks_vec.size() << std::endl; if (eig_ks_vec.size() != this->nbands) { @@ -150,29 +166,46 @@ void ModuleESolver::ESolver_LR::read_ks_wfc() { this->eig_ks(0, i) = eig_ks_vec[i]; } - RI_Benchmark::read_aims_eigenvectors(*this->psi_ks, this->in_dir + "KS_eigenvectors.out", ncore, nbands, nbasis); + RI_Benchmark::read_aims_eigenvectors( + *this->psi_ks, + this->in_dir + "KS_eigenvectors.out", + ncore, + nbands, + nbasis); #else ModuleBase::WARNING_QUIT("ESolver_LR", "RI benchmark is only supported when compile with LibRI."); #endif } - else if (!ModuleIO::read_wfc_nao(this->in_dir, this->paraMat_, *this->psi_ks, - this->eig_ks, - this->wg_ks, - this->kv.ik2iktot, - this->kv.get_nkstot(), - this->inp_->nspin, - this->inp_->init_wfc_file_format == "binary", - /*skip_bands=*/this->nocc_max - this->nocc_in)) { + else if (!ModuleIO::read_wfc_nao( + this->in_dir, + this->paraMat_, + *this->psi_ks, + this->eig_ks, + this->wg_ks, + this->kv.ik2iktot, + this->kv.get_nkstot(), + this->inp_->nspin, + this->inp_->init_wfc_file_format == "binary", + /*skip_bands=*/this->nocc_max - this->nocc_in)) + { ModuleBase::WARNING_QUIT("ESolver_LR", "read ground-state wavefunction failed."); } if (this->inp_->cal_force) - { // allocate psi_ks_all and eig_ks_all to read all the bands - this->psi_ks_all_own_.reset(new psi::Psi(this->kv.get_nks(), paraMat_all_.ncol_bands, paraMat_all_.get_row_size(), this->kv.ngk, true)); + { // allocate psi_ks_all and eig_ks_all to read all the bands + this->psi_ks_all_own_.reset(new psi::Psi( + this->kv.get_nks(), + paraMat_all_.ncol_bands, + paraMat_all_.get_row_size(), + this->kv.ngk, + true)); this->psi_ks_all_ = this->psi_ks_all_own_.get(); this->eig_ks_all.create(this->kv.get_nks(), this->inp_->nbands); this->wg_ks_all.create(this->kv.get_nks(), this->inp_->nbands); - if (!ModuleIO::read_wfc_nao(this->in_dir, paraMat_all_, *this->psi_ks_all_, + if (!ModuleIO::read_wfc_nao( + this->in_dir, + paraMat_all_, + *this->psi_ks_all_, this->eig_ks_all, this->wg_ks_all, this->kv.ik2iktot, @@ -187,8 +220,7 @@ void ModuleESolver::ESolver_LR::read_ks_wfc() } } -template -void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) +template void ModuleESolver::ESolver_LR::fill_z_window_(const int *desc_src) { ModuleBase::TITLE("ESolver_LR", "fill_z_window_"); if (!this->inp_->cal_force || this->psi_ks_all_ == nullptr) @@ -203,7 +235,7 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) // file path it was read with `skip_bands = 0`. this->nbands_z_ = this->eig_ks_all.nc - start_band; if (this->nbands_z_ <= this->nbands) - { // nothing to widen: nbands was already at (or below) the X window + { // nothing to widen: nbands was already at (or below) the X window this->nbands_z_ = this->nbands; } this->nvirt_z_.assign(this->nspin, 0); @@ -213,18 +245,28 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) } const int block_size = this->paraC_.get_block_size(); - LR_Util::setup_2d_division(this->paraC_z_, block_size, this->nbasis, this->nbands_z_ + LR_Util::setup_2d_division( + this->paraC_z_, + block_size, + this->nbasis, + this->nbands_z_ #ifdef __MPI - , this->paraMat_.blacs_ctxt + , + this->paraMat_.blacs_ctxt #endif ); this->paraX_z_.clear(); for (int is = 0; is < this->nspin; ++is) { Parallel_2D px; - LR_Util::setup_2d_division(px, block_size, this->nvirt_z_[is], this->nocc[is] + LR_Util::setup_2d_division( + px, + block_size, + this->nvirt_z_[is], + this->nocc[is] #ifdef __MPI - , this->paraC_z_.blacs_ctxt + , + this->paraC_z_.blacs_ctxt #endif ); this->paraX_z_.emplace_back(std::move(px)); @@ -233,15 +275,24 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) // state's block is as long as both channels together; the closed-shell singlet/triplet // algorithm carries a single channel. (Same rule as `nloc_per_state` in // `setup_eigenvectors_X`, applied to the widened windows.) - this->nloc_per_state_z_ = this->nk * (this->openshell - ? this->paraX_z_[0].get_local_size() + this->paraX_z_[1].get_local_size() - : this->paraX_z_[0].get_local_size()); + this->nloc_per_state_z_ = + this->nk * (this->openshell ? this->paraX_z_[0].get_local_size() + this->paraX_z_[1].get_local_size() + : this->paraX_z_[0].get_local_size()); #ifdef __MPI - this->psi_ks_z_.reset(new psi::Psi(this->kv.get_nks(), this->paraC_z_.get_col_size(), - this->paraC_z_.get_row_size(), this->kv.ngk, true)); + this->psi_ks_z_.reset(new psi::Psi( + this->kv.get_nks(), + this->paraC_z_.get_col_size(), + this->paraC_z_.get_row_size(), + this->kv.ngk, + true)); #else - this->psi_ks_z_.reset(new psi::Psi(this->kv.get_nks(), this->nbands_z_, this->nbasis, this->kv.ngk, true)); + this->psi_ks_z_.reset(new psi::Psi( + this->kv.get_nks(), + this->nbands_z_, + this->nbasis, + this->kv.ngk, + true)); #endif this->eig_ks_z_.create(this->kv.get_nks(), this->nbands_z_); @@ -252,13 +303,22 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) this->psi_ks_all_->fix_k(ik); this->psi_ks_z_->fix_k(ik); const int first_band = start_band + 1; - Cpxgemr2d(this->nbasis, this->nbands_z_, this->psi_ks_all_->get_pointer(), 1, first_band, - const_cast(desc_src), this->psi_ks_z_->get_pointer(), 1, 1, - this->paraC_z_.desc, this->paraC_z_.blacs_ctxt); + Cpxgemr2d( + this->nbasis, + this->nbands_z_, + this->psi_ks_all_->get_pointer(), + 1, + first_band, + const_cast(desc_src), + this->psi_ks_z_->get_pointer(), + 1, + 1, + this->paraC_z_.desc, + this->paraC_z_.blacs_ctxt); #else for (int ib = 0; ib < this->nbands_z_; ++ib) { - const auto* start = &(*this->psi_ks_all_)(ik, start_band + ib, 0); + const auto *start = &(*this->psi_ks_all_)(ik, start_band + ib, 0); std::copy(start, start + this->nbasis, &(*this->psi_ks_z_)(ik, ib, 0)); } #endif @@ -267,8 +327,8 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) this->eig_ks_z_(ik, ib) = this->eig_ks_all(ik, start_band + ib); } } - this->ofs_running_ << "Z-vector window: nbands = " << this->nbands_z_ - << " (X window: " << this->nbands << "), nvirt ="; + this->ofs_running_ << "Z-vector window: nbands = " << this->nbands_z_ << " (X window: " << this->nbands + << "), nvirt ="; for (int is = 0; is < this->nspin; ++is) { this->ofs_running_ << " " << this->nvirt_z_[is] << "(X window: " << this->nvirt[is] << ")"; @@ -278,8 +338,12 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) // the same windows. Diagnose once, without changing the truncated eigenproblem. if (!this->ks_initialized_) { - const std::string warning = LR_Util::force_window_warning(this->nbasis, - this->eig_ks_all.nc, start_band, this->nvirt, this->nvirt_z_); + const std::string warning = LR_Util::force_window_warning( + this->nbasis, + this->eig_ks_all.nc, + start_band, + this->nvirt, + this->nvirt_z_); if (!warning.empty()) { this->ofs_running_ << warning << std::endl; @@ -287,12 +351,15 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) } } -template -void ModuleESolver::ESolver_LR::read_ks_chg(Charge& chg_gs) +template void ModuleESolver::ESolver_LR::read_ks_chg(Charge &chg_gs) { chg_gs.set_rhopw(this->pw_rho); const bool kin_den = XC_Functional::get_ked_flag() || (this->inp_->out_elf[0] > 0); // mohan add 20251202 - chg_gs.allocate(this->nspin, kin_den, XC_Functional::get_ked_flag(), this->inp_->test_charge); + chg_gs.allocate( + this->nspin, + kin_den, + XC_Functional::get_ked_flag(), + this->inp_->test_charge); this->ofs_running_ << " try to read charge from file : "; for (int is = 0; is < this->nspin; ++is) { @@ -306,13 +373,16 @@ void ModuleESolver::ESolver_LR::read_ks_chg(Charge& chg_gs) ssc << this->in_dir << "chgs" << is + 1 << ".cube"; } this->ofs_running_ << ssc.str() << std::endl; - if (ModuleIO::read_vdata_palgrid(pgrid(), - this->my_rank_, - this->ofs_running_, - ssc.str(), - chg_gs.rho[is], - this->ucell_->nat)) - this->ofs_running_ << " Read in the charge density: " << ssc.str() << std::endl; + if (ModuleIO::read_vdata_palgrid( + pgrid(), + this->my_rank_, + this->ofs_running_, + ssc.str(), + chg_gs.rho[is], + this->ucell_->nat)) + { + this->ofs_running_ << " Read in the charge density: " << ssc.str() << std::endl; + } } } template class ModuleESolver::ESolver_LR; diff --git a/source/source_esolver/esolver_lr_rlx.cpp b/source/source_esolver/esolver_lr_rlx.cpp index 0bcc4d2ae4..2028759ec2 100644 --- a/source/source_esolver/esolver_lr_rlx.cpp +++ b/source/source_esolver/esolver_lr_rlx.cpp @@ -1,24 +1,23 @@ +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" #include "source_esolver/esolver_lr_lcao_tddft.h" -#include "source_lcao/module_lr/zeq_solver.h" +#include "source_estate/module_dm/dm_from_psi.h" +#include "source_io/module_output/output_log.h" #include "source_lcao/module_lr/cal_edm.h" -#include "source_lcao/module_lr/lr_force.h" +#include "source_lcao/module_lr/grad_degen.h" #include "source_lcao/module_lr/gradient_inputs.h" #include "source_lcao/module_lr/gradient_output.h" #include "source_lcao/module_lr/lr_amp.h" -#include "source_lcao/module_lr/grad_degen.h" -#include "source_base/parallel_reduce.h" -#include "source_base/timer.h" +#include "source_lcao/module_lr/lr_force.h" +#include "source_lcao/module_lr/zeq_solver.h" + #include #include #include -#include "source_estate/module_dm/dm_from_psi.h" -#include "source_io/module_output/output_log.h" using namespace LR; - -template -void ModuleESolver::ESolver_LR::setup_relax_target_() +template void ModuleESolver::ESolver_LR::setup_relax_target_() { this->excited_relax_ = (this->inp_->calculation == "relax"); if (!this->excited_relax_) @@ -30,20 +29,20 @@ void ModuleESolver::ESolver_LR::setup_relax_target_() // excited-state gradient only exists at gamma. Fail here rather than after the SCF. if (!std::is_same::value) { - ModuleBase::WARNING_QUIT("ESolver_LR", - "excited-state relaxation currently requires gamma-only sampling: the complex " - "Z-vector solver is not implemented."); + ModuleBase::WARNING_QUIT( + "ESolver_LR", "excited-state relaxation currently requires gamma-only sampling: the complex " + "Z-vector solver is not implemented."); } if (this->inp_->lr_target_state >= this->nstates) { - ModuleBase::WARNING_QUIT("ESolver_LR", - "lr_target_state is beyond the states actually solved (lr_nstates <= 0 expands to " - "all particle-hole pairs, which may be fewer than requested)."); + ModuleBase::WARNING_QUIT( + "ESolver_LR", "lr_target_state is beyond the states actually solved (lr_nstates <= 0 expands to " + "all particle-hole pairs, which may be fewer than requested)."); } // `openshell` is only settled after the ground-state occupations have been read, which is why // this cannot live in the input-file checks - const std::string& spin = this->inp_->lr_target_spin; + const std::string &spin = this->inp_->lr_target_spin; if (this->openshell) { // An open-shell calculation solves one spin-conserving channel, so there is nothing to @@ -53,8 +52,9 @@ void ModuleESolver::ESolver_LR::setup_relax_target_() if (spin == "triplet") { this->ofs_running_ << " WARNING: lr_target_spin=triplet is ignored. This is an" - " open-shell calculation with a single spin-conserving channel (updown), which is" - " what the relaxation will follow." << std::endl; + " open-shell calculation with a single spin-conserving channel (updown), which is" + " what the relaxation will follow." + << std::endl; } this->target_is_ = 0; } @@ -65,29 +65,28 @@ void ModuleESolver::ESolver_LR::setup_relax_target_() // usually means lr_unrestricted was meant to be set. if (spin == "updown") { - ModuleBase::WARNING_QUIT("ESolver_LR", - "lr_target_spin=updown, but this is a closed-shell calculation, where singlet and " - "triplet are separate states with separate gradients. Pick one of them, or set " - "lr_unrestricted to run spin-unrestricted."); + ModuleBase::WARNING_QUIT( + "ESolver_LR", "lr_target_spin=updown, but this is a closed-shell calculation, where singlet and " + "triplet are separate states with separate gradients. Pick one of them, or set " + "lr_unrestricted to run spin-unrestricted."); } this->target_is_ = (spin == "triplet") ? 1 : 0; if (this->target_is_ >= this->nspin) { - ModuleBase::WARNING_QUIT("ESolver_LR", - "lr_target_spin=triplet requires nspin=2: the triplet channel is not built here."); + ModuleBase::WARNING_QUIT( + "ESolver_LR", "lr_target_spin=triplet requires nspin=2: the triplet channel is not built here."); } } this->force_gs_.create(this->ucell_->nat, 3); this->lr_force_.create(this->ucell_->nat, 3); this->target_state_ = this->inp_->lr_target_state; // seed; overlap takes over from step 2 - this->ofs_running_ << " Excited-state relaxation follows state " << this->inp_->lr_target_state - << " of the " << (this->openshell ? "updown" : (this->target_is_ == 1 ? "triplet" : "singlet")) - << " channel, tracked by cross-geometry orbital and amplitude overlap." << std::endl; + this->ofs_running_ << " Excited-state relaxation follows state " << this->inp_->lr_target_state << " of the " + << (this->openshell ? "updown" : (this->target_is_ == 1 ? "triplet" : "singlet")) + << " channel, tracked by cross-geometry orbital and amplitude overlap." << std::endl; } /// Compare roots in a common electron-hole basis using exact cross-geometry AO overlap. -template -void ModuleESolver::ESolver_LR::follow_target_state_(std::ofstream& ofs) +template void ModuleESolver::ESolver_LR::follow_target_state_(std::ofstream &ofs) { ModuleBase::timer::start("ESolver_LR", "follow_target_state_"); if (!this->excited_relax_) @@ -96,23 +95,42 @@ void ModuleESolver::ESolver_LR::follow_target_state_(std::ofstream& ofs) return; } const int channel = this->openshell ? 0 : this->target_is_; - const T* const amplitudes = this->X[channel].template data(); - const TwoCenterIntegrator& overlap_integrator = *this->tcb().overlap_orb; + const T *const amplitudes = this->X[channel].template data(); + const TwoCenterIntegrator &overlap_integrator = *this->tcb().overlap_orb; const bool reference_first = LR_Util::tolower(this->inp_->lr_degen_mode) == "jt"; - const LR::RootInputs inputs{*this->ucell_, this->orb_cutoff_, overlap_integrator, - *this->psi_ks, this->paraC_, this->paraMat_, this->paraX_, this->nocc, this->nvirt, this->openshell, this->target_is_, reference_first}; + const LR::RootInputs inputs{*this->ucell_, + this->orb_cutoff_, + overlap_integrator, + *this->psi_ks, + this->paraC_, + this->paraMat_, + this->paraX_, + this->nocc, + this->nvirt, + this->openshell, + this->target_is_, + reference_first}; const int energy_offset = channel * this->nstates; std::vector energies(this->nstates); std::copy_n(this->pelec->ekb.c + energy_offset, this->nstates, energies.begin()); const bool single_state = LR_Util::tolower(this->inp_->lr_degen_mode) == "state"; const double group_threshold = single_state ? 0.0 : this->inp_->lr_degen_thr; - LR::follow_cross_root(inputs, amplitudes, this->nloc_per_state, this->nstates, - this->inp_->lr_target_state, energies, group_threshold, this->target_state_, this->target_X_prev_, this->target_basis_prev_, ofs); + LR::follow_cross_root( + inputs, + amplitudes, + this->nloc_per_state, + this->nstates, + this->inp_->lr_target_state, + energies, + group_threshold, + this->target_state_, + this->target_X_prev_, + this->target_basis_prev_, + ofs); ModuleBase::timer::end("ESolver_LR", "follow_target_state_"); } -template -double ModuleESolver::ESolver_LR::cal_energy() +template double ModuleESolver::ESolver_LR::cal_energy() { // Outside a relaxation nothing consumes this, and returning a non-zero value would change // what the existing single-point outputs report. @@ -127,19 +145,19 @@ double ModuleESolver::ESolver_LR::cal_energy() return this->etot_gs_ + this->target_omega_(); } -template -void ModuleESolver::ESolver_LR::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +template +void ModuleESolver::ESolver_LR::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - const UnitCell& ucell = static_cast(basecell); + const UnitCell &ucell = static_cast(basecell); if (!this->excited_relax_) - { // single-point runs print the gradients of every state from `after_all_runners` instead + { // single-point runs print the gradients of every state from `after_all_runners` instead return; } if (this->lr_force_.nr != ucell.nat) { - ModuleBase::WARNING_QUIT("ESolver_LR::cal_force", - "the excited-state gradient has not been computed for this geometry."); + ModuleBase::WARNING_QUIT( + "ESolver_LR::cal_force", "the excited-state gradient has not been computed for this geometry."); } // Both halves already follow the ABACUS force convention F = -dE/dR (Ry/Bohr), so they add. // The "Gradients of each excited state" heading that `cal_force(int)` prints under is a @@ -147,40 +165,44 @@ void ModuleESolver::ESolver_LR::cal_force(BaseCell& basecell, ModuleBase: // computes (E(-h) - E(+h))/h, which is -d(Omega)/dR, and the two agree in sign. force.create(ucell.nat, 3); force = this->force_gs_ + this->lr_force_; - ModuleIO::print_force(this->ofs_running_, ucell, "EXCITED-STATE TOTAL-FORCE (eV/Angstrom)", force, false); + ModuleIO::print_force( + this->ofs_running_, + ucell, + "EXCITED-STATE TOTAL-FORCE (eV/Angstrom)", + force, + false); } -template -void ModuleESolver::ESolver_LR::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +template +void ModuleESolver::ESolver_LR::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { static_cast(stress); basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - ModuleBase::WARNING_QUIT("ESolver_LR::cal_stress", - "the excited-state stress is not implemented (every LR gradient stress term is a " - "dummy passed with isstress=false)."); + ModuleBase::WARNING_QUIT( + "ESolver_LR::cal_stress", "the excited-state stress is not implemented (every LR gradient stress term is a " + "dummy passed with isstress=false)."); } -template -ct::Tensor ModuleESolver::ESolver_LR::pad_group_to_z_(const int ispin, - const std::vector& group) const +template +ct::Tensor ModuleESolver::ESolver_LR::pad_group_to_z_(const int ispin, const std::vector &group) const { const int d = static_cast(group.size()); const int nloc_g = this->nloc_per_state_z_; - ct::Tensor Xz = LR_Util::newTensor({ d, nloc_g }); + ct::Tensor Xz = LR_Util::newTensor({d, nloc_g}); Xz.zero(); // One at a time rather than as a range: `group` is sorted, but nothing guarantees its members // are contiguous in the state list. for (int k = 0; k < d; ++k) { const ct::Tensor one = this->pad_X_to_z_(ispin, group[k], 1); - std::copy(one.template data(), one.template data() + nloc_g, + std::copy( + one.template data(), one.template data() + nloc_g, Xz.template data() + static_cast(k) * nloc_g); } return Xz; } -template -void ModuleESolver::ESolver_LR::resolve_target_multiplet_() +template void ModuleESolver::ESolver_LR::resolve_target_multiplet_() { // Keyed on `target_state_`, not on `lr_target_state`: the overlap tracking re-chooses the // followed root at every ionic step, and the multiplet has to be the one containing the root @@ -196,9 +218,8 @@ void ModuleESolver::ESolver_LR::resolve_target_multiplet_() { omega[ist] = this->pelec->ekb.c[ekb_off + ist]; } - const std::vector> groups - = LR::group_degenerate_states(omega, this->inp_->lr_degen_thr); - for (const std::vector& g : groups) + const std::vector> groups = LR::group_degenerate_states(omega, this->inp_->lr_degen_thr); + for (const std::vector &g : groups) { if (std::find(g.begin(), g.end(), this->target_state_) == g.end()) { @@ -227,8 +248,7 @@ void ModuleESolver::ESolver_LR::resolve_target_multiplet_() } } -template -double ModuleESolver::ESolver_LR::target_omega_() const +template double ModuleESolver::ESolver_LR::target_omega_() const { if (this->target_group_.empty()) { @@ -236,15 +256,15 @@ double ModuleESolver::ESolver_LR::target_omega_() const } const int ekb_off = this->openshell ? 0 : this->target_is_ * this->nstates; double sum = 0.0; - for (const int ist: this->target_group_) + for (const int ist : this->target_group_) { sum += this->pelec->ekb.c[ekb_off + ist]; } return sum / static_cast(this->target_group_.size()); } -template -ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::ofstream& ofs) +template +ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::ofstream &ofs) { this->resolve_target_multiplet_(); if (this->target_group_.empty()) @@ -263,9 +283,13 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::of { omega[k] = this->pelec->ekb.c[ekb_off + this->target_group_[k]]; } - const std::vector forces = this->openshell - ? this->cal_force_openshell_Xz(Xz, omega, this->target_group_.front()) - : this->cal_force_Xz(this->target_is_, Xz, omega, this->target_group_.front()); + const std::vector forces = + this->openshell ? this->cal_force_openshell_Xz(Xz, omega, this->target_group_.front()) + : this->cal_force_Xz( + this->target_is_, + Xz, + omega, + this->target_group_.front()); ofs << " Followed state " << this->target_state_ << " is degenerate with"; for (const int ist : this->target_group_) { @@ -285,16 +309,19 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::of return this->cal_jt_force_(forces, ofs); } -template +template ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( - const std::vector& diag, std::ofstream& ofs) + const std::vector &diag, std::ofstream &ofs) { // Regime (c): descend the Jahn-Teller branch. This needs the whole gradient matrix, so the // off-diagonal elements are assembled here -- d(d-1)/2 further Z-vector solves on top of the // d diagonal ones already in `diag`. const int d = static_cast(this->target_group_.size()); - const std::vector> g - = this->cal_grad_matrix_degenerate(this->target_is_, this->target_group_, diag, ofs); + const std::vector> g = this->cal_grad_matrix_degenerate( + this->target_is_, + this->target_group_, + diag, + ofs); const int nat = diag[0].nr; const int ncoord = nat * 3; // flatten to the layout `find_jt_direction` takes: one d x d block per nuclear coordinate. @@ -316,10 +343,20 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( } const LR::JTDirection jt = LR::find_jt_direction(gflat, ncoord, d); const int channel = this->openshell ? 0 : this->target_is_; - const T* const amplitudes = this->X[channel].template data(); - LR::save_mixed_root(amplitudes, this->nloc_per_state, this->target_group_, jt.mixing, this->target_X_prev_); + const T *const amplitudes = this->X[channel].template data(); + LR::save_mixed_root( + amplitudes, + this->nloc_per_state, + this->target_group_, + jt.mixing, + this->target_X_prev_); std::vector jt_part; - const std::vector sym = LR::split_symmetric_part(gflat, ncoord, d, jt.mixing, jt_part); + const std::vector sym = LR::split_symmetric_part( + gflat, + ncoord, + d, + jt.mixing, + jt_part); const double fac = ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A; ofs << " lr_degen_mode=jt: descending the steepest branch of the multiplet." << std::endl @@ -330,8 +367,8 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( ofs << " " << jt.mixing[k]; } ofs << std::endl - << " starts agreeing = " << jt.restarts_agreeing << " of " - << (d + (1 << (d - 1))) << " (iterations " << jt.iterations << ")" << std::endl; + << " starts agreeing = " << jt.restarts_agreeing << " of " << (d + (1 << (d - 1))) << " (iterations " + << jt.iterations << ")" << std::endl; // The two halves matter separately: the symmetric part is common to the whole multiplet and // only relaxes the geometry, while the remainder is what actually breaks the degeneracy. At a // stationary point of the average surface the first is zero and the whole force is Jahn-Teller. @@ -342,19 +379,25 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( nsym += sym[a] * sym[a]; njt += jt_part[a] * jt_part[a]; } - ofs << " |symmetric part| = " << std::sqrt(nsym) * fac << " eV/Angstrom (common to the" - " multiplet; relaxes the geometry without splitting it)" << std::endl - << " |Jahn-Teller part| = " << std::sqrt(njt) * fac << " eV/Angstrom (the symmetry-" - "breaking remainder)" << std::endl; + ofs << " |symmetric part| = " << std::sqrt(nsym) * fac + << " eV/Angstrom (common to the" + " multiplet; relaxes the geometry without splitting it)" + << std::endl + << " |Jahn-Teller part| = " << std::sqrt(njt) * fac + << " eV/Angstrom (the symmetry-" + "breaking remainder)" + << std::endl; if (std::sqrt(njt) < 1e-8) { ofs << " WARNING: the symmetry-breaking part vanishes -- every branch of this multiplet has" - " the same gradient, so there is no Jahn-Teller direction to descend here. This is the" - " expected outcome for a linear molecule, where the effect is second order" - " (Renner-Teller) and no first-order term exists." << std::endl; + " the same gradient, so there is no Jahn-Teller direction to descend here. This is the" + " expected outcome for a linear molecule, where the effect is second order" + " (Renner-Teller) and no first-order term exists." + << std::endl; } ofs << " NOTE: this is the first-order DIRECTION only. The distortion amplitude also needs the" - " harmonic term, and the step norm is Cartesian rather than mass-weighted." << std::endl; + " harmonic term, and the step norm is Cartesian rather than mass-weighted." + << std::endl; // The force handed back is that of the descending branch, q(v) with v the optimal mixing -- // i.e. the branch's own gradient, which is what a relaxation must follow. Once a step has @@ -372,7 +415,7 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( return f; } -template +template ModuleBase::matrix ModuleESolver::ESolver_LR::MultipletLVC::average_force() const { assert(!this->g.empty()); diff --git a/source/source_esolver/esolver_nep.cpp b/source/source_esolver/esolver_nep.cpp index 2f95725139..ace96f16c7 100644 --- a/source/source_esolver/esolver_nep.cpp +++ b/source/source_esolver/esolver_nep.cpp @@ -16,11 +16,12 @@ * @date 2025-10-10 */ #include "esolver_nep.h" + #include "source_base/parallel_common.h" #include "source_base/timer.h" +#include "source_cell/cif_io.h" #include "source_cell/mdcell.h" #include "source_cell/module_neighlist/neighbor_search.h" -#include "source_cell/cif_io.h" #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" @@ -31,7 +32,7 @@ using namespace ModuleESolver; -void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_NEP::before_all_runners(BaseCell &basecell, const Input_para &inp) { this->inp_ = &inp; nep_potential = 0.0; @@ -39,10 +40,9 @@ void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) if (basecell.kind() == BaseCell::Kind::mdcell) { - MDCell& mdcell = static_cast(basecell); + MDCell &mdcell = static_cast(basecell); #ifdef __NEP - const double cutoff = std::max(nep.paramb.rc_radial_max, nep.paramb.rc_angular_max) - * ModuleBase::ANGSTROM_AU; + const double cutoff = std::max(nep.paramb.rc_radial_max, nep.paramb.rc_angular_max) * ModuleBase::ANGSTROM_AU; mdcell.set_neighbor_cutoff(cutoff); initialize_type_map_(mdcell.type_labels()); #else @@ -51,17 +51,18 @@ void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) return; } - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); nep_force.create(ucell.nat, 3); atype.resize(ucell.nat); _e.resize(ucell.nat); _f.resize(3 * ucell.nat); _v.resize(9 * ucell.nat); - ModuleIO::CifParser::write(PARAM.globalv.global_out_dir + "STRU.cif", - ucell, - "# Generated by ABACUS ModuleIO::CifParser", - "data_?"); + ModuleIO::CifParser::write( + PARAM.globalv.global_out_dir + "STRU.cif", + ucell, + "# Generated by ABACUS ModuleIO::CifParser", + "data_?"); #ifdef __NEP /// determine the type map from STRU to NEP model @@ -69,7 +70,7 @@ void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) #endif } -void ESolver_NEP::runner(BaseCell& basecell, const int istep) +void ESolver_NEP::runner(BaseCell &basecell, const int istep) { ModuleBase::TITLE("ESolver_NEP", "runner"); ModuleBase::timer::start("ESolver_NEP", "runner"); @@ -80,7 +81,7 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) ModuleBase::WARNING_QUIT("ESolver_NEP", "Please recompile with -D__NEP"); #else static_cast(istep); - MDCell& mdcell = static_cast(basecell); + MDCell &mdcell = static_cast(basecell); if (!mdcell.has_neighbor_search()) { ModuleBase::WARNING_QUIT("ESolver", "MDCell neighbors must be prepared by the caller before runner()."); @@ -93,17 +94,17 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) ModuleBase::WARNING_QUIT("ESolver_NEP", "MDCell contains no atoms."); } - const std::vector& owned_atoms = mdcell.owned_atoms(); - const std::vector& ghost_atoms = mdcell.ghost_atoms(); + const std::vector &owned_atoms = mdcell.owned_atoms(); + const std::vector &ghost_atoms = mdcell.ghost_atoms(); std::vector local_type(static_cast(natom), 0); - std::vector > position(static_cast(natom)); - std::vector > force(static_cast(natom)); - std::vector position_ptrs(static_cast(natom), NULL); - std::vector force_ptrs(static_cast(natom), NULL); + std::vector> position(static_cast(natom)); + std::vector> force(static_cast(natom)); + std::vector position_ptrs(static_cast(natom), NULL); + std::vector force_ptrs(static_cast(natom), NULL); for (int iat = 0; iat < natom; ++iat) { - const LocalAtom& atom = iat < nowned_atoms ? owned_atoms[static_cast(iat)] - : ghost_atoms[static_cast(iat - nowned_atoms)]; + const LocalAtom &atom = iat < nowned_atoms ? owned_atoms[static_cast(iat)] + : ghost_atoms[static_cast(iat - nowned_atoms)]; if (atom.type < 0 || static_cast(atom.type) >= md_type_to_nep_type_.size()) { ModuleBase::WARNING_QUIT("ESolver_NEP", "MDCell atom type is outside the NEP type map."); @@ -117,53 +118,72 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) force_ptrs[static_cast(iat)] = force[static_cast(iat)].data(); } - const NeighborList& neighbor_list = mdcell.neighbor_search().get_neighbor_list(); + const NeighborList &neighbor_list = mdcell.neighbor_search().get_neighbor_list(); std::vector ilist(static_cast(nowned_atoms), 0); std::vector numneigh(static_cast(natom), 0); - std::vector firstneigh(static_cast(natom), NULL); + std::vector firstneigh(static_cast(natom), NULL); for (int iat = 0; iat < nowned_atoms; ++iat) { ilist[static_cast(iat)] = iat; numneigh[static_cast(iat)] = neighbor_list.get_numneigh(iat); - firstneigh[static_cast(iat)] = const_cast(neighbor_list.get_firstneigh(iat)); + firstneigh[static_cast(iat)] = const_cast(neighbor_list.get_firstneigh(iat)); } double local_energy = 0.0; - double local_virial[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + double local_virial[6] = {0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0}; ModuleBase::timer::start("ESolver_NEP", "compute"); - nep.compute_for_lammps(nowned_atoms, - nowned_atoms, - nowned_atoms > 0 ? ilist.data() : NULL, - numneigh.data(), - firstneigh.data(), - local_type.data(), - md_type_to_nep_type_.data(), - position_ptrs.data(), - local_energy, - local_virial, - NULL, - force_ptrs.data(), - NULL); + nep.compute_for_lammps( + nowned_atoms, + nowned_atoms, + nowned_atoms > 0 ? ilist.data() : NULL, + numneigh.data(), + firstneigh.data(), + local_type.data(), + md_type_to_nep_type_.data(), + position_ptrs.data(), + local_energy, + local_virial, + NULL, + force_ptrs.data(), + NULL); ModuleBase::timer::end("ESolver_NEP", "compute"); - std::vector& mutable_owned_atoms = mdcell.owned_atoms(); - std::vector& mutable_ghost_atoms = mdcell.ghost_atoms(); + std::vector &mutable_owned_atoms = mdcell.owned_atoms(); + std::vector &mutable_ghost_atoms = mdcell.ghost_atoms(); for (int iat = 0; iat < nowned_atoms; ++iat) { - mutable_owned_atoms[static_cast(iat)].force.set(force[static_cast(iat)][0], - force[static_cast(iat)][1], - force[static_cast(iat)][2]); + mutable_owned_atoms[static_cast(iat)].force.set( + force[static_cast(iat)][0], force[static_cast(iat)][1], + force[static_cast(iat)][2]); } for (int iat = 0; iat < nghost; ++iat) { - mutable_ghost_atoms[static_cast(iat)].force.set(force[static_cast(nowned_atoms + iat)][0], - force[static_cast(nowned_atoms + iat)][1], - force[static_cast(nowned_atoms + iat)][2]); + mutable_ghost_atoms[static_cast(iat)].force.set( + force[static_cast(nowned_atoms + iat)][0], + force[static_cast(nowned_atoms + iat)][1], + force[static_cast(nowned_atoms + iat)][2]); } #ifdef __MPI - MPI_Allreduce(MPI_IN_PLACE, &local_energy, 1, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); - MPI_Allreduce(MPI_IN_PLACE, local_virial, 6, MPI_DOUBLE, MPI_SUM, mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + &local_energy, + 1, + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); + MPI_Allreduce( + MPI_IN_PLACE, + local_virial, + 6, + MPI_DOUBLE, + MPI_SUM, + mdcell.communicator()); #endif const double fact_e = 1.0 / ModuleBase::Ry_to_eV; const double fact_f = 1.0 / (ModuleBase::Ry_to_eV * ModuleBase::ANGSTROM_AU); @@ -171,10 +191,10 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) nep_potential = local_energy * fact_e; for (int iat = 0; iat < nowned_atoms; ++iat) { - LocalAtom& atom = mutable_owned_atoms[static_cast(iat)]; + LocalAtom &atom = mutable_owned_atoms[static_cast(iat)]; atom.force *= fact_f; } - for (LocalAtom& atom : mutable_ghost_atoms) + for (LocalAtom &atom : mutable_ghost_atoms) { atom.force *= fact_f; } @@ -189,7 +209,7 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) return; } - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); // note that NEP are column major, thus a transpose is needed // cell @@ -225,7 +245,13 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) nep_force.zero_out(); nep_virial.zero_out(); - nep.compute(atype, cell, coord, _e, _f, _v); + nep.compute( + atype, + cell, + coord, + _e, + _f, + _v); // unit conversion const double fact_e = 1.0 / ModuleBase::Ry_to_eV; @@ -270,20 +296,17 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) ModuleBase::timer::end("ESolver_NEP", "runner"); } -double ESolver_NEP::cal_energy() -{ - return nep_potential; -} +double ESolver_NEP::cal_energy() { return nep_potential; } -void ESolver_NEP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_NEP::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { if (basecell.kind() == BaseCell::Kind::mdcell) { - const MDCell& mdcell = static_cast(basecell); + const MDCell &mdcell = static_cast(basecell); force.create(mdcell.owned_atoms().size(), 3); for (int iat = 0; iat < mdcell.owned_atoms().size(); ++iat) { - const LocalAtom& atom = mdcell.owned_atoms()[static_cast(iat)]; + const LocalAtom &atom = mdcell.owned_atoms()[static_cast(iat)]; force(iat, 0) = atom.force.x; force(iat, 1) = atom.force.y; force(iat, 2) = atom.force.z; @@ -291,24 +314,39 @@ void ESolver_NEP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) return; } force = nep_force; - UnitCell& ucell = static_cast(basecell); - ModuleIO::print_force(GlobalV::ofs_running, ucell, "TOTAL-FORCE (eV/Angstrom)", force, false); + UnitCell &ucell = static_cast(basecell); + ModuleIO::print_force( + GlobalV::ofs_running, + ucell, + "TOTAL-FORCE (eV/Angstrom)", + force, + false); } -void ESolver_NEP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_NEP::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { stress = nep_virial; if (basecell.kind() == BaseCell::Kind::unitcell) { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } else { #ifdef __MPI - if (static_cast(basecell).mpi_rank() == 0) + if (static_cast(basecell).mpi_rank() == 0) #endif { - ModuleIO::print_stress("TOTAL-STRESS", stress, true, false, GlobalV::ofs_running); + ModuleIO::print_stress( + "TOTAL-STRESS", + stress, + true, + false, + GlobalV::ofs_running); } } @@ -321,7 +359,7 @@ void ESolver_NEP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) } } -void ESolver_NEP::after_all_runners(BaseCell& basecell) +void ESolver_NEP::after_all_runners(BaseCell &basecell) { static_cast(basecell); @@ -332,7 +370,7 @@ void ESolver_NEP::after_all_runners(BaseCell& basecell) } #ifdef __NEP -void ESolver_NEP::type_map(const UnitCell& ucell) +void ESolver_NEP::type_map(const UnitCell &ucell) { std::vector type_labels(static_cast(ucell.ntype)); for (int it = 0; it < ucell.ntype; ++it) @@ -352,7 +390,7 @@ void ESolver_NEP::type_map(const UnitCell& ucell) assert(ucell.nat == iat); } -void ESolver_NEP::initialize_type_map_(const std::vector& type_labels) +void ESolver_NEP::initialize_type_map_(const std::vector &type_labels) { // parse the element list from NEP model file std::unordered_map label; @@ -385,8 +423,7 @@ void ESolver_NEP::initialize_type_map_(const std::vector& type_labe const std::unordered_map::const_iterator found = label.find(type_labels[it]); if (found == label.end()) { - ModuleBase::WARNING_QUIT("ESolver_NEP", - "The label " + type_labels[it] + " is not found in the type map."); + ModuleBase::WARNING_QUIT("ESolver_NEP", "The label " + type_labels[it] + " is not found in the type map."); } md_type_to_nep_type_[it] = found->second; } diff --git a/source/source_esolver/esolver_nep.h b/source/source_esolver/esolver_nep.h index e7d56562d0..661d203724 100644 --- a/source/source_esolver/esolver_nep.h +++ b/source/source_esolver/esolver_nep.h @@ -15,13 +15,13 @@ class ESolver_NEP : public ESolver { public: #ifdef __NEP - ESolver_NEP(const std::string& pot_file) : nep(pot_file) + ESolver_NEP(const std::string &pot_file) : nep(pot_file) { classname = "ESolver_NEP"; nep_file = pot_file; } #else - ESolver_NEP(const std::string& pot_file) + ESolver_NEP(const std::string &pot_file) { classname = "ESolver_NEP"; nep_file = pot_file; @@ -34,7 +34,7 @@ class ESolver_NEP : public ESolver * @param inp input parameters * @param cell unitcell information */ - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; /** * @brief Run the NEP solver for a given ion/md step and unit cell @@ -42,7 +42,7 @@ class ESolver_NEP : public ESolver * @param istep the current ion/md step * @param cell unitcell information */ - void runner(BaseCell& basecell, const int istep) override; + void runner(BaseCell &basecell, const int istep) override; /** * @brief get the total energy without ion kinetic energy @@ -57,21 +57,21 @@ class ESolver_NEP : public ESolver * * @param force the computed atomic forces */ - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; /** * @brief get the computed lattice virials * * @param stress the computed lattice virials */ - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; /** * @brief Prints the final total energy of the NEP model to the output file * * This function prints the final total energy of the NEP model in eV to the output file along with some formatting. */ - void after_all_runners(BaseCell& basecell) override; + void after_all_runners(BaseCell &basecell) override; private: /** @@ -79,8 +79,8 @@ class ESolver_NEP : public ESolver * * @param ucell unitcell information */ - void type_map(const UnitCell& ucell); - void initialize_type_map_(const std::vector& type_labels); + void type_map(const UnitCell &ucell); + void initialize_type_map_(const std::vector &type_labels); /** * @brief NEP related variables for ESolver_NEP class @@ -94,8 +94,8 @@ class ESolver_NEP : public ESolver NEP nep; ///< NEP object for NEP calculations #endif - std::string nep_file; ///< directory of NEP model file - std::vector atype = {}; ///< atom type mapping for NEP model + std::string nep_file; ///< directory of NEP model file + std::vector atype = {}; ///< atom type mapping for NEP model std::vector md_type_to_nep_type_; double nep_potential; ///< computed potential energy ModuleBase::matrix nep_force; ///< computed atomic forces diff --git a/source/source_esolver/esolver_of.cpp b/source/source_esolver/esolver_of.cpp index 74374e4593..ae080191d1 100644 --- a/source/source_esolver/esolver_of.cpp +++ b/source/source_esolver/esolver_of.cpp @@ -1,28 +1,24 @@ #include "esolver_of.h" -#include - #include "source_io/module_parameter/parameter.h" + +#include //-----------temporary------------------------- #include "source_base/global_function.h" +#include "source_cell/cal_ux.h" #include "source_estate/module_charge/chg_init.h" #include "source_estate/module_charge/chg_symm.h" #include "source_estate/module_charge/chg_tools.h" #include "source_hamilt/module_ewald/h_ewald_pw.h" -#include "source_cell/cal_ux.h" -#include "source_pw/module_pwdft/force_pw.h" -#include "source_pw/module_ofdft/of_stress_pw.h" -#include "source_pw/module_ofdft/of_print_info.h" #include "source_hamilt/module_xc/xc_functional.h" - +#include "source_pw/module_ofdft/of_print_info.h" +#include "source_pw/module_ofdft/of_stress_pw.h" +#include "source_pw/module_pwdft/force_pw.h" namespace ModuleESolver { -ESolver_OF::ESolver_OF() -{ - this->classname = "ESolver_OF"; -} +ESolver_OF::ESolver_OF() { this->classname = "ESolver_OF"; } ESolver_OF::~ESolver_OF() { @@ -42,10 +38,10 @@ ESolver_OF::~ESolver_OF() delete this->opt_cg_mag_; } -void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_OF::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ESolver_FP::before_all_runners(ucell, inp); @@ -57,12 +53,16 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) this->of_tolp_ = inp.of_tolp; this->max_iter_ = inp.scf_nmax; this->dV_ = ucell.omega / this->pw_rho->nxyz; - this->bound_cal_potential_ - = std::bind(&ESolver_OF::cal_potential, this, std::placeholders::_1, std::placeholders::_2, std::ref(ucell)); + this->bound_cal_potential_ = std::bind( + &ESolver_OF::cal_potential, + this, + std::placeholders::_1, + std::placeholders::_2, + std::ref(ucell)); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SETUP UNITCELL"); -// XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); + // XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); int func_type = XC_Functional::get_func_type(); if (func_type > 2) { @@ -81,23 +81,45 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) init_rho_cfg.domag_z = PARAM.globalv.domag_z; init_rho_cfg.npol = PARAM.globalv.npol; init_rho_cfg.meta_gga = XC_Functional::get_ked_flag(); - this->chr.init_rho(ucell, this->Pgrid, this->sf.strucFac, ucell.symm, &this->kv, nullptr, init_rho_cfg); - module_charge::check_rho(this->chr.rho, this->chr.nspin, this->chr.rhopw->nrxx, ucell.omega, - this->chr.rhopw->nxyz, inp.nelec); // check the rho + this->chr.init_rho( + ucell, + this->Pgrid, + this->sf.strucFac, + ucell.symm, + &this->kv, + nullptr, + init_rho_cfg); + module_charge::check_rho( + this->chr.rho, + this->chr.nspin, + this->chr.rhopw->nrxx, + ucell.omega, + this->chr.rhopw->nxyz, + inp.nelec); // check the rho // initialize local pseudopotential - this->locpp.init_vloc(ucell,pw_rho); - this->locpp.print_vloc(ucell, pw_rho, inp.out_element_info, PARAM.globalv.global_out_dir); + this->locpp.init_vloc(ucell, pw_rho); + this->locpp.print_vloc( + ucell, + pw_rho, + inp.out_element_info, + PARAM.globalv.global_out_dir); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "LOCAL POTENTIAL"); - // initialize elecstate, including potential this->init_elecstate(ucell); // calculate the total local pseudopotential in real space - const int istep=0; - elecstate::init_scf(ucell, Pgrid, sf.strucFac, locpp.numeric, istep, - PARAM.globalv.global_out_dir, *this->inp_, this->pelec); + const int istep = 0; + elecstate::init_scf( + ucell, + Pgrid, + sf.strucFac, + locpp.numeric, + istep, + PARAM.globalv.global_out_dir, + *this->inp_, + this->pelec); // liuyu move here 2023-10-09 // D in uspp need vloc, thus behind init_scf() @@ -122,7 +144,11 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) } delete this->kedf_manager_; this->kedf_manager_ = new KEDF_Manager(); - this->kedf_manager_->init(inp, this->pw_rho, this->dV_, this->nelec_[0]); + this->kedf_manager_->init( + inp, + this->pw_rho, + this->dV_, + this->nelec_[0]); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT KEDF"); // Initialize optimization methods @@ -132,17 +158,17 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) this->allocate_array(); } -void ESolver_OF::runner(BaseCell& basecell, const int istep) +void ESolver_OF::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::timer::start("ESolver_OF", "runner"); // get Ewald energy, initial rho and phi if necessary this->before_opt(istep, ucell); this->iter_ = 0; - bool conv_esolver = false; // this conv_esolver is added by mohan 20250302 + bool conv_esolver = false; // this conv_esolver is added by mohan 20250302 this->iter_time = ModuleBase::get_time(); while (true) @@ -155,7 +181,6 @@ void ESolver_OF::runner(BaseCell& basecell, const int istep) this->energy_last_ = this->energy_current_; this->energy_current_ = this->cal_energy(); - // check if the job is done if (this->check_exit(conv_esolver)) { @@ -170,7 +195,11 @@ void ESolver_OF::runner(BaseCell& basecell, const int istep) this->iter_++; - ESolver_FP::iter_finish(ucell, istep, this->iter_, conv_esolver); + ESolver_FP::iter_finish( + ucell, + istep, + this->iter_, + conv_esolver); } this->after_opt(istep, ucell, conv_esolver); @@ -186,7 +215,7 @@ void ESolver_OF::runner(BaseCell& basecell, const int istep) * @param istep * @param ucell */ -void ESolver_OF::before_opt(const int istep, UnitCell& ucell) +void ESolver_OF::before_opt(const int istep, UnitCell &ucell) { ModuleBase::TITLE("ESolver_OF", "before_opt"); ModuleBase::timer::start("ESolver_OF", "before_opt"); @@ -202,15 +231,23 @@ void ESolver_OF::before_opt(const int istep, UnitCell& ucell) this->init_elecstate(ucell); // Initialize KEDF - this->kedf_manager_->init(*this->inp_, this->pw_rho, this->dV_, this->nelec_[0]); + this->kedf_manager_->init( + *this->inp_, + this->pw_rho, + this->dV_, + this->nelec_[0]); // Initialize optimization methods this->init_opt(); // Refresh the arrays delete this->psi_; - this->psi_ = new psi::Psi(1, this->inp_->nspin, - this->pw_rho->nrxx, this->pw_rho->nrxx, true); + this->psi_ = new psi::Psi( + 1, + this->inp_->nspin, + this->pw_rho->nrxx, + this->pw_rho->nrxx, + true); for (int is = 0; is < this->inp_->nspin; ++is) { @@ -219,20 +256,35 @@ void ESolver_OF::before_opt(const int istep, UnitCell& ucell) delete this->ptemp_rho_; this->ptemp_rho_ = new Charge(); - this->ptemp_rho_->set_rhopw(this->pw_rho); - const bool kin_den = XC_Functional::get_ked_flag() || (this->inp_->out_elf[0] > 0); // mohan add 20251202 - this->ptemp_rho_->allocate(this->inp_->nspin, kin_den, XC_Functional::get_ked_flag(), - this->inp_->test_charge); + this->ptemp_rho_->set_rhopw(this->pw_rho); + const bool kin_den = XC_Functional::get_ked_flag() || (this->inp_->out_elf[0] > 0); // mohan add 20251202 + this->ptemp_rho_->allocate( + this->inp_->nspin, + kin_den, + XC_Functional::get_ked_flag(), + this->inp_->test_charge); this->resize_spin_arrays(); } - elecstate::init_scf(ucell, Pgrid, sf.strucFac, locpp.numeric, istep, PARAM.globalv.global_out_dir, *this->inp_, this->pelec); + elecstate::init_scf( + ucell, + Pgrid, + sf.strucFac, + locpp.numeric, + istep, + PARAM.globalv.global_out_dir, + *this->inp_, + this->pelec); const int nspin = this->inp_->nspin; if (this->inp_->init_chg == "file") { - module_charge::symmetrize_rho(nspin, this->chr, this->pw_rho, ucell.symm); + module_charge::symmetrize_rho( + nspin, + this->chr, + this->pw_rho, + ucell.symm); for (int is = 0; is < nspin; ++is) { for (int ibs = 0; ibs < this->pw_rho->nrxx; ++ibs) @@ -278,19 +330,20 @@ void ESolver_OF::before_opt(const int istep, UnitCell& ucell) * * @param ucell */ -void ESolver_OF::update_potential(UnitCell& ucell) +void ESolver_OF::update_potential(UnitCell &ucell) { // (1) get dL/dphi unitcell::cal_ux(ucell, this->inp_->nspin); this->pelec->pot->update_from_charge(&this->chr, &ucell); // Hartree + XC + external - this->kedf_manager_->get_potential(this->chr.rho, - this->pphi_, - this->pw_rho, - this->pelec->pot->get_eff_v()); // KEDF potential + this->kedf_manager_->get_potential( + this->chr.rho, + this->pphi_, + this->pw_rho, + this->pelec->pot->get_eff_v()); // KEDF potential for (int is = 0; is < this->inp_->nspin; ++is) { - const double* vr_eff = this->pelec->pot->get_eff_v(is); + const double *vr_eff = this->pelec->pot->get_eff_v(is); for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { this->pdEdphi_[is][ir] = vr_eff[ir]; @@ -298,8 +351,8 @@ void ESolver_OF::update_potential(UnitCell& ucell) this->pelec->eferm.set_efval(is, this->cal_mu(this->pphi_[is], this->pdEdphi_[is], this->nelec_[is])); for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - this->pdLdphi_[is][ir] - = this->pdEdphi_[is][ir] - 2. * this->pelec->eferm.get_efval(is) * this->pphi_[is][ir]; + this->pdLdphi_[is][ir] = + this->pdEdphi_[is][ir] - 2. * this->pelec->eferm.get_efval(is) * this->pphi_[is][ir]; } } @@ -312,7 +365,11 @@ void ESolver_OF::update_potential(UnitCell& ucell) for (int is = 0; is < this->inp_->nspin; ++is) { - this->normdLdphi_ += this->inner_product(this->pdLdphi_[is], this->pdLdphi_[is], this->pw_rho->nrxx, 1.0); + this->normdLdphi_ += this->inner_product( + this->pdLdphi_[is], + this->pdLdphi_[is], + this->pw_rho->nrxx, + 1.0); } Parallel_Reduce::reduce_all(this->normdLdphi_); this->normdLdphi_ = sqrt(this->normdLdphi_ / this->pw_rho->nxyz / this->inp_->nspin); @@ -323,14 +380,14 @@ void ESolver_OF::update_potential(UnitCell& ucell) * * @param ucell */ -void ESolver_OF::optimize(UnitCell& ucell) +void ESolver_OF::optimize(UnitCell &ucell) { // (1) get |d0> with optimization algorithm this->get_direction(ucell); // initialize temp_phi and temp_rho used in line search - std::vector ptemp_phi_storage(static_cast(this->inp_->nspin) - * static_cast(this->pw_rho->nrxx)); - std::vector ptemp_phi(this->inp_->nspin); + std::vector ptemp_phi_storage( + static_cast(this->inp_->nspin) * static_cast(this->pw_rho->nrxx)); + std::vector ptemp_phi(this->inp_->nspin); for (int is = 0; is < this->inp_->nspin; ++is) { ptemp_phi[is] = ptemp_phi_storage.data() + static_cast(is) * this->pw_rho->nrxx; @@ -365,8 +422,8 @@ void ESolver_OF::update_rho() { for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - this->pphi_[is][ir] - = this->pphi_[is][ir] * cos(this->theta_[is]) + this->pdirect_[is][ir] * sin(this->theta_[is]); + this->pphi_[is][ir] = + this->pphi_[is][ir] * cos(this->theta_[is]) + this->pdirect_[is][ir] * sin(this->theta_[is]); this->chr.rho[is][ir] = this->pphi_[is][ir] * this->pphi_[is][ir]; } } @@ -379,7 +436,7 @@ void ESolver_OF::update_rho() * * @return exit or not */ -bool ESolver_OF::check_exit(bool& conv_esolver) +bool ESolver_OF::check_exit(bool &conv_esolver) { conv_esolver = false; bool potConv = false; @@ -390,23 +447,30 @@ bool ESolver_OF::check_exit(bool& conv_esolver) { potConv = true; } - if (this->iter_ >= 3 && std::abs(this->normdLdphi_ - this->normdLdphi_last_) < 1e-10 - && std::abs(this->normdLdphi_ - this->normdLdphi_llast_) < 1e-10) + if (this->iter_ >= 3 && std::abs(this->normdLdphi_ - this->normdLdphi_last_) < 1e-10 && + std::abs(this->normdLdphi_ - this->normdLdphi_llast_) < 1e-10) { potHold = true; } - if (this->iter_ >= 3 && std::abs(this->energy_current_ - this->energy_last_) < this->of_tole_ - && std::abs(this->energy_current_ - this->energy_llast_) < this->of_tole_) + if (this->iter_ >= 3 && std::abs(this->energy_current_ - this->energy_last_) < this->of_tole_ && + std::abs(this->energy_current_ - this->energy_llast_) < this->of_tole_) { energyConv = true; } - conv_esolver = (this->of_conv_ == "energy" && energyConv) || (this->of_conv_ == "potential" && potConv) - || (this->of_conv_ == "both" && potConv && energyConv); + conv_esolver = (this->of_conv_ == "energy" && energyConv) || (this->of_conv_ == "potential" && potConv) || + (this->of_conv_ == "both" && potConv && energyConv); - OFDFT::print_info(this->iter_, this->iter_time, this->energy_current_, this->energy_last_, - this->normdLdphi_, this->pelec, this->kedf_manager_, conv_esolver); + OFDFT::print_info( + this->iter_, + this->iter_time, + this->energy_current_, + this->energy_last_, + this->normdLdphi_, + this->pelec, + this->kedf_manager_, + conv_esolver); if (conv_esolver || this->iter_ >= this->max_iter_) { @@ -434,7 +498,7 @@ bool ESolver_OF::check_exit(bool& conv_esolver) * @param istep * @param ucell */ -void ESolver_OF::after_opt(const int istep, UnitCell& ucell, const bool conv_esolver) +void ESolver_OF::after_opt(const int istep, UnitCell &ucell, const bool conv_esolver) { ModuleBase::TITLE("ESolver_OF", "after_opt"); ModuleBase::timer::start("ESolver_OF", "after_opt"); @@ -444,7 +508,11 @@ void ESolver_OF::after_opt(const int istep, UnitCell& ucell, const bool conv_eso //------------------------------------------------------------------ if (this->inp_->out_elf[0] > 0) { - this->kedf_manager_->get_energy_density(this->chr.rho, this->pphi_, this->pw_rho, this->chr.kin_r); + this->kedf_manager_->get_energy_density( + this->chr.rho, + this->pphi_, + this->pw_rho, + this->chr.kin_r); } // should not be here? mohan note 2025-03-03 @@ -465,12 +533,13 @@ void ESolver_OF::after_opt(const int istep, UnitCell& ucell, const bool conv_eso if (this->inp_->of_ml_gene_data) { this->pelec->pot->update_from_charge(&this->chr, &ucell); // Hartree + XC + external - this->kedf_manager_->get_potential(this->chr.rho, - this->pphi_, - this->pw_rho, - this->pelec->pot->get_eff_v()); // KEDF potential - - const double* vr_eff = this->pelec->pot->get_eff_v(0); + this->kedf_manager_->get_potential( + this->chr.rho, + this->pphi_, + this->pw_rho, + this->pelec->pot->get_eff_v()); // KEDF potential + + const double *vr_eff = this->pelec->pot->get_eff_v(0); for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { this->pdEdphi_[0][ir] = vr_eff[ir]; @@ -489,10 +558,10 @@ void ESolver_OF::after_opt(const int istep, UnitCell& ucell, const bool conv_eso /** * @brief Output the FINAL_ETOT */ -void ESolver_OF::after_all_runners(BaseCell& basecell) +void ESolver_OF::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ESolver_FP::after_all_runners(ucell); } @@ -505,19 +574,21 @@ void ESolver_OF::after_all_runners(BaseCell& basecell) */ double ESolver_OF::cal_energy() { - this->pelec->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + this->pelec->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); double kinetic_energy = this->kedf_manager_->get_energy(); // kinetic energy - double pseudopot_energy = 0.; // electron-ion interaction energy + double pseudopot_energy = 0.; // electron-ion interaction energy for (int is = 0; is < this->inp_->nspin; ++is) { - pseudopot_energy += this->inner_product(this->pelec->pot->get_fixed_v(), - this->chr.rho[is], - this->pw_rho->nrxx, - this->dV_); + pseudopot_energy += this->inner_product( + this->pelec->pot->get_fixed_v(), + this->chr.rho[is], + this->pw_rho->nrxx, + this->dV_); } Parallel_Reduce::reduce_pool(pseudopot_energy); this->pelec->f_en.ekinetic = kinetic_energy; @@ -531,19 +602,31 @@ double ESolver_OF::cal_energy() * * @param [out] force */ -void ESolver_OF::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_OF::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); Forces ff(ucell.nat); - + // here nullptr is for DFT+U, which may cause bugs, mohan note 2025-11-07 // solvent can be used? mohan ask 2025-11-07 - ff.cal_force(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad, - this->inp_->dft_plus_u || this->inp_->sc_mag_switch, - ucell, force, this->get_vdw_result(), *pelec, this->pw_rho, &ucell.symm, &sf, - this->solvent, nullptr, &this->locpp); + ff.cal_force( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + this->inp_->dft_plus_u || this->inp_->sc_mag_switch, + ucell, + force, + this->get_vdw_result(), + *pelec, + this->pw_rho, + &ucell.symm, + &sf, + this->solvent, + nullptr, + &this->locpp); } /** @@ -551,19 +634,34 @@ void ESolver_OF::cal_force(BaseCell& basecell, ModuleBase::matrix& force) * * @param [out] stress */ -void ESolver_OF::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_OF::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::matrix kinetic_stress_; kinetic_stress_.create(3, 3); - this->kedf_manager_->get_stress(ucell.omega, this->chr.rho, - this->pphi_, this->pw_rho, kinetic_stress_); // kinetic stress + this->kedf_manager_->get_stress( + ucell.omega, + this->chr.rho, + this->pphi_, + this->pw_rho, + kinetic_stress_); // kinetic stress OF_Stress_PW ss(this->pelec, this->pw_rho); - ss.cal_stress(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, - this->inp_->gga_grad, PARAM.globalv.gamma_only_pw, - stress, kinetic_stress_, ucell, this->get_vdw_result(), &ucell.symm, this->locpp, &sf, &kv); + ss.cal_stress( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + PARAM.globalv.gamma_only_pw, + stress, + kinetic_stress_, + ucell, + this->get_vdw_result(), + &ucell.symm, + this->locpp, + &sf, + &kv); } } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_of.h b/source/source_esolver/esolver_of.h index 401ec38f84..e915a54b8b 100644 --- a/source/source_esolver/esolver_of.h +++ b/source/source_esolver/esolver_of.h @@ -1,15 +1,15 @@ #ifndef ESOLVER_OF_H #define ESOLVER_OF_H -#include -#include - #include "esolver_fp.h" #include "source_base/opt_dcsrch.h" #include "source_base/opt_tn.h" #include "source_psi/psi.h" #include "source_pw/module_ofdft/kedf_manager.h" +#include +#include + namespace ModuleESolver { class ESolver_OF : public ESolver_FP @@ -18,28 +18,28 @@ class ESolver_OF : public ESolver_FP ESolver_OF(); ~ESolver_OF(); - virtual void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + virtual void before_all_runners(BaseCell &basecell, const Input_para &inp) override; - virtual void runner(BaseCell& basecell, const int istep) override; + virtual void runner(BaseCell &basecell, const int istep) override; - virtual void after_all_runners(BaseCell& basecell) override; + virtual void after_all_runners(BaseCell &basecell) override; virtual double cal_energy() override; - virtual void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + virtual void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; - virtual void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + virtual void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; protected: // ======================= variables ========================== // ---------- the kinetic energy density functionals ---------- - KEDF_Manager* kedf_manager_ = nullptr; // KEDF manager, which will be initialized in before_all_runners + KEDF_Manager *kedf_manager_ = nullptr; // KEDF manager, which will be initialized in before_all_runners // ----------------- the optimization methods ------------------ - ModuleBase::Opt_CG* opt_cg_ = nullptr; - ModuleBase::Opt_TN* opt_tn_ = nullptr; - ModuleBase::Opt_DCsrch* opt_dcsrch_ = nullptr; - ModuleBase::Opt_CG* opt_cg_mag_ = nullptr; // for spin2 case, under testing + ModuleBase::Opt_CG *opt_cg_ = nullptr; + ModuleBase::Opt_TN *opt_tn_ = nullptr; + ModuleBase::Opt_DCsrch *opt_dcsrch_ = nullptr; + ModuleBase::Opt_CG *opt_cg_mag_ = nullptr; // for spin2 case, under testing // ----------------- necessary parameters from INPUT ------------ std::string of_kinetic_ = "wt"; // Kinetic energy functional, such as TF, VW, WT @@ -50,27 +50,27 @@ class ESolver_OF : public ESolver_FP int max_iter_ = 50; // scf_nmax // ------------------ parameters from other module -------------- - double dV_ = 0; // volume of one grid point in real space + double dV_ = 0; // volume of one grid point in real space std::vector nelec_; // number of electrons with each spin // ----- parameters and arrays used in density optimization ----- - int iter_ = 0; // iteration number + int iter_ = 0; // iteration number std::vector pdirect_storage_; - std::vector pdirect_; // row views; optimization direction of phi, which is sqrt(rho) + std::vector pdirect_; // row views; optimization direction of phi, which is sqrt(rho) std::vector> precip_dir_storage_; - std::vector*> precip_dir_; // row views; used when of_full_pw=false. - std::vector theta_; // step length + std::vector *> precip_dir_; // row views; used when of_full_pw=false. + std::vector theta_; // step length std::vector pdEdphi_storage_; - std::vector pdEdphi_; // row views; dE/dphi + std::vector pdEdphi_; // row views; dE/dphi std::vector pdLdphi_storage_; - std::vector pdLdphi_; // row views; dL/dphi - double** pphi_ = nullptr; // pphi[i] = ppsi.get_pointer(i), which will be freed in ~Psi(). - std::string task_; // used in line search - int tn_spin_flag_ = -1; // spin flag used in cal_potential, which will be called by opt_tn - int max_dcsrch_ = 200; // max no. of line search - int flag_ = -1; // flag of TN - Charge* ptemp_rho_ = nullptr; // used in line search - psi::Psi* psi_ = nullptr; // sqrt(rho) + std::vector pdLdphi_; // row views; dL/dphi + double **pphi_ = nullptr; // pphi[i] = ppsi.get_pointer(i), which will be freed in ~Psi(). + std::string task_; // used in line search + int tn_spin_flag_ = -1; // spin flag used in cal_potential, which will be called by opt_tn + int max_dcsrch_ = 200; // max no. of line search + int flag_ = -1; // flag of TN + Charge *ptemp_rho_ = nullptr; // used in line search + psi::Psi *psi_ = nullptr; // sqrt(rho) // ----------------- used for convergence check ------------------- double energy_llast_ = 0; @@ -81,43 +81,57 @@ class ESolver_OF : public ESolver_FP double normdLdphi_ = 100.; // ==================== main process of OFDFT ====================== - void before_opt(const int istep, UnitCell& ucell); - void update_potential(UnitCell& ucell); - void optimize(UnitCell& ucell); + void before_opt(const int istep, UnitCell &ucell); + void update_potential(UnitCell &ucell); + void optimize(UnitCell &ucell); void update_rho(); - bool check_exit(bool& conv_esolver); - void after_opt(const int istep, UnitCell& ucell, const bool conv_esolver); + bool check_exit(bool &conv_esolver); + void after_opt(const int istep, UnitCell &ucell, const bool conv_esolver); // ============================ tools =============================== // --------------------- initialize --------------------------------- - void init_elecstate(UnitCell& ucell); + void init_elecstate(UnitCell &ucell); void allocate_array(); void resize_spin_arrays(); // --------------------- calculate physical qualities --------------- - std::function bound_cal_potential_; - void cal_potential_wrapper(double* ptemp_phi, double* rdLdphi); - void cal_potential(double* ptemp_phi, double* rdLdphi, UnitCell& ucell); - void cal_dEdtheta(double** ptemp_phi, Charge* temp_rho, UnitCell& ucell, double* ptheta, double* rdEdtheta); - double cal_mu(double* pphi, double* pdEdphi, double nelec); + std::function bound_cal_potential_; + void cal_potential_wrapper(double *ptemp_phi, double *rdLdphi); + void cal_potential(double *ptemp_phi, double *rdLdphi, UnitCell &ucell); + void cal_dEdtheta( + double **ptemp_phi, + Charge *temp_rho, + UnitCell &ucell, + double *ptheta, + double *rdEdtheta); + double cal_mu(double *pphi, double *pdEdphi, double nelec); // --------------------- determine the optimization direction ------- void adjust_direction(); - void check_direction(double* dEdtheta, double** ptemp_phi, UnitCell& ucell); - void test_direction(double* dEdtheta, double** ptemp_phi, UnitCell& ucell); + void check_direction(double *dEdtheta, double **ptemp_phi, UnitCell &ucell); + void test_direction(double *dEdtheta, double **ptemp_phi, UnitCell &ucell); // --------------------- interface to blas -------------------------- - double inner_product(double* pa, double* pb, int length, double dV = 1) const + double inner_product( + double *pa, + double *pb, + int length, + double dV = 1) const { - double innerproduct = BlasConnector::dot(length, pa, 1, pb, 1); + double innerproduct = BlasConnector::dot( + length, + pa, + 1, + pb, + 1); innerproduct *= dV; return innerproduct; } // ---------------------- interfaces to optimization methods -------- void init_opt(); - void get_direction(UnitCell& ucell); - void get_step_length(double* dEdtheta, double** ptemp_phi, UnitCell& ucell); + void get_direction(UnitCell &ucell); + void get_step_length(double *dEdtheta, double **ptemp_phi, UnitCell &ucell); }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_of_interface.cpp b/source/source_esolver/esolver_of_interface.cpp index af9e048819..99a302fa89 100644 --- a/source/source_esolver/esolver_of_interface.cpp +++ b/source/source_esolver/esolver_of_interface.cpp @@ -48,7 +48,7 @@ void ESolver_OF::init_opt() } } -void ESolver_OF::cal_potential_wrapper(double* ptemp_phi, double* rdLdphi) +void ESolver_OF::cal_potential_wrapper(double *ptemp_phi, double *rdLdphi) { this->bound_cal_potential_(ptemp_phi, rdLdphi); } @@ -57,19 +57,20 @@ void ESolver_OF::cal_potential_wrapper(double* ptemp_phi, double* rdLdphi) * @brief [Interface to opt] * Call optimization methods to get the optimization direction */ -void ESolver_OF::get_direction(UnitCell& ucell) +void ESolver_OF::get_direction(UnitCell &ucell) { for (int is = 0; is < this->inp_->nspin; ++is) { if (this->of_method_ == "tn") { this->tn_spin_flag_ = is; - opt_tn_->next_direct(this->pphi_[is], - this->pdLdphi_[is], - this->flag_, - this->pdirect_[is], - this, - &ESolver_OF::cal_potential_wrapper); + opt_tn_->next_direct( + this->pphi_[is], + this->pdLdphi_[is], + this->flag_, + this->pdirect_[is], + this, + &ESolver_OF::cal_potential_wrapper); } else if (this->of_method_ == "cg1") { @@ -98,7 +99,7 @@ void ESolver_OF::get_direction(UnitCell& ucell) * @param ptemp_phi * @param ucell */ -void ESolver_OF::get_step_length(double* dEdtheta, double** ptemp_phi, UnitCell& ucell) +void ESolver_OF::get_step_length(double *dEdtheta, double **ptemp_phi, UnitCell &ucell) { double temp_energy = 0.0; // energy of temp_phi and temp_rho double kinetic_energy = 0.0; // kinetic energy @@ -111,22 +112,28 @@ void ESolver_OF::get_step_length(double* dEdtheta, double** ptemp_phi, UnitCell& while (true) { // update energy - this->pelec->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + this->pelec->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); temp_energy = this->pelec->f_en.etot; kinetic_energy = this->kedf_manager_->get_energy(); // kinetic energy - pseudopot_energy = this->inner_product(this->pelec->pot->get_fixed_v(), - this->ptemp_rho_->rho[0], - this->pw_rho->nrxx, - this->dV_); + pseudopot_energy = this->inner_product( + this->pelec->pot->get_fixed_v(), + this->ptemp_rho_->rho[0], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(pseudopot_energy); temp_energy += kinetic_energy + pseudopot_energy; // line search to update theta[0] - this->opt_dcsrch_->dcSrch(temp_energy, dEdtheta[0], this->theta_[0], this->task_); + this->opt_dcsrch_->dcSrch( + temp_energy, + dEdtheta[0], + this->theta_[0], + this->task_); numDC++; // decide what to do next according to the output of line search @@ -135,13 +142,18 @@ void ESolver_OF::get_step_length(double* dEdtheta, double** ptemp_phi, UnitCell& // update tempPhi and tempRho for (int i = 0; i < this->pw_rho->nrxx; ++i) { - ptemp_phi[0][i] - = this->pphi_[0][i] * cos(this->theta_[0]) + this->pdirect_[0][i] * sin(this->theta_[0]); + ptemp_phi[0][i] = + this->pphi_[0][i] * cos(this->theta_[0]) + this->pdirect_[0][i] * sin(this->theta_[0]); this->ptemp_rho_->rho[0][i] = ptemp_phi[0][i] * ptemp_phi[0][i]; } // get dEdtheta of new tempPhi and tempRho - this->cal_dEdtheta(ptemp_phi, this->ptemp_rho_, ucell, this->theta_.data(), dEdtheta); + this->cal_dEdtheta( + ptemp_phi, + this->ptemp_rho_, + ucell, + this->theta_.data(), + dEdtheta); if (numDC > this->max_dcsrch_) { diff --git a/source/source_esolver/esolver_of_tddft.cpp b/source/source_esolver/esolver_of_tddft.cpp index 3c068b2c77..f7c5b36e44 100644 --- a/source/source_esolver/esolver_of_tddft.cpp +++ b/source/source_esolver/esolver_of_tddft.cpp @@ -3,9 +3,9 @@ #include "source_io/module_parameter/parameter.h" //-----------temporary------------------------- #include "source_base/global_function.h" +#include "source_cell/cal_ux.h" #include "source_estate/module_charge/chg_symm.h" #include "source_hamilt/module_ewald/h_ewald_pw.h" -#include "source_cell/cal_ux.h" //-----force------------------- #include "source_pw/module_pwdft/force_pw.h" //-----stress------------------ @@ -19,26 +19,22 @@ namespace ModuleESolver ESolver_OF_TDDFT::ESolver_OF_TDDFT() { this->classname = "ESolver_OF_TDDFT"; - this->evolve_ofdft=new Evolve_OFDFT(); + this->evolve_ofdft = new Evolve_OFDFT(); } -ESolver_OF_TDDFT::~ESolver_OF_TDDFT() -{ - delete this->evolve_ofdft; -} +ESolver_OF_TDDFT::~ESolver_OF_TDDFT() { delete this->evolve_ofdft; } - -void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) +void ESolver_OF_TDDFT::runner(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::timer::start("ESolver_OF_TDDFT", "runner"); // get Ewald energy, initial rho and phi if necessary this->before_opt(istep, ucell); this->iter_ = 0; - bool conv_esolver = false; // this conv_esolver is added by mohan 20250302 + bool conv_esolver = false; // this conv_esolver is added by mohan 20250302 this->iter_time = ModuleBase::get_time(); if (this->phi_td.empty()) @@ -47,7 +43,7 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) this->phi_td.resize(size, std::complex(0.0, 0.0)); } - if ((istep==0) && this->inp_->init_chg != "file") + if ((istep == 0) && this->inp_->init_chg != "file") { while (true) { @@ -59,7 +55,6 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) this->energy_last_ = this->energy_current_; this->energy_current_ = this->cal_energy(); - // check if the job is done if (this->check_exit(conv_esolver)) { @@ -74,7 +69,11 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) this->iter_++; - ESolver_FP::iter_finish(ucell, istep, this->iter_, conv_esolver); + ESolver_FP::iter_finish( + ucell, + istep, + this->iter_, + conv_esolver); } #ifdef _OPENMP @@ -84,11 +83,11 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) { for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - phi_td[is*this->pw_rho->nrxx+ir]=pphi_[is][ir]; + phi_td[is * this->pw_rho->nrxx + ir] = pphi_[is][ir]; } } } - else if ((istep==0) && this->inp_->init_chg == "file") + else if ((istep == 0) && this->inp_->init_chg == "file") { #ifdef _OPENMP #pragma omp parallel for collapse(2) @@ -97,14 +96,19 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) { for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - phi_td[is*this->pw_rho->nrxx+ir]=pphi_[is][ir]; + phi_td[is * this->pw_rho->nrxx + ir] = pphi_[is][ir]; } - } - conv_esolver=true; + } + conv_esolver = true; } else { - this->evolve_ofdft->propagate_psi_RK4(this->pelec, this->chr, ucell, this->phi_td, this->pw_rho); + this->evolve_ofdft->propagate_psi_RK4( + this->pelec, + this->chr, + ucell, + this->phi_td, + this->pw_rho); #ifdef _OPENMP #pragma omp parallel for collapse(2) #endif @@ -112,10 +116,10 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) { for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - pphi_[is][ir]=std::abs(phi_td[is*this->pw_rho->nrxx+ir]); + pphi_[is][ir] = std::abs(phi_td[is * this->pw_rho->nrxx + ir]); } } - conv_esolver=true; + conv_esolver = true; } this->after_opt(istep, ucell, conv_esolver); diff --git a/source/source_esolver/esolver_of_tddft.h b/source/source_esolver/esolver_of_tddft.h index e70ea5c5e7..6dce7e15cc 100644 --- a/source/source_esolver/esolver_of_tddft.h +++ b/source/source_esolver/esolver_of_tddft.h @@ -12,11 +12,11 @@ class ESolver_OF_TDDFT : public ESolver_OF ESolver_OF_TDDFT(); ~ESolver_OF_TDDFT(); - virtual void runner(BaseCell& basecell, const int istep) override; + virtual void runner(BaseCell &basecell, const int istep) override; protected: std::vector> phi_td; // time dependent wavefunction - Evolve_OFDFT* evolve_ofdft = nullptr; + Evolve_OFDFT *evolve_ofdft = nullptr; }; } // namespace ModuleESolver diff --git a/source/source_esolver/esolver_of_tool.cpp b/source/source_esolver/esolver_of_tool.cpp index 375277bc6f..8890278e2d 100644 --- a/source/source_esolver/esolver_of_tool.cpp +++ b/source/source_esolver/esolver_of_tool.cpp @@ -1,15 +1,14 @@ #include "esolver_of.h" - -#include -#include - #include "source_base/formatter.h" #include "source_base/memory_recorder.h" +#include "source_cell/cal_ux.h" #include "source_estate/module_pot/efield.h" #include "source_estate/module_pot/gatefield.h" -#include "source_io/module_parameter/parameter.h" -#include "source_cell/cal_ux.h" #include "source_hamilt/module_xc/xc_functional.h" +#include "source_io/module_parameter/parameter.h" + +#include +#include namespace ModuleESolver { @@ -19,22 +18,23 @@ namespace ModuleESolver * * @param ucell */ -void ESolver_OF::init_elecstate(UnitCell& ucell) +void ESolver_OF::init_elecstate(UnitCell &ucell) { if (this->pelec == nullptr) { - this->pelec = new elecstate::ElecState((Charge*)(&chr), this->pw_rho, pw_big); + this->pelec = new elecstate::ElecState((Charge *)(&chr), this->pw_rho, pw_big); } delete this->pelec->pot; - this->pelec->pot = new elecstate::Potential(this->pw_rhod, - this->pw_rho, - &ucell, - &(this->locpp.vloc), - &(this->sf), - &(this->solvent), - &(this->pelec->f_en.etxc), - &(this->pelec->f_en.vtxc)); + this->pelec->pot = new elecstate::Potential( + this->pw_rhod, + this->pw_rho, + &ucell, + &(this->locpp.vloc), + &(this->sf), + &(this->solvent), + &(this->pelec->f_en.etxc), + &(this->pelec->f_en.vtxc)); // There is no Operator in ESolver_OF, register Potentials here! std::vector pot_register_in; if (this->inp_->vion_in_h) @@ -77,13 +77,14 @@ void ESolver_OF::init_elecstate(UnitCell& ucell) void ESolver_OF::allocate_array() { // Initialize the "wavefunction", which is sqrt(rho) - this->psi_ = new psi::Psi(1, - this->inp_->nspin, - this->pw_rho->nrxx, - this->pw_rho->nrxx, - true); + this->psi_ = new psi::Psi( + 1, + this->inp_->nspin, + this->pw_rho->nrxx, + this->pw_rho->nrxx, + true); ModuleBase::Memory::record("OFDFT::Psi", sizeof(double) * this->inp_->nspin * this->pw_rho->nrxx); - this->pphi_ = new double*[this->inp_->nspin]; + this->pphi_ = new double *[this->inp_->nspin]; for (int is = 0; is < this->inp_->nspin; ++is) { this->pphi_[is] = this->psi_->get_pointer(is); @@ -95,15 +96,19 @@ void ESolver_OF::allocate_array() this->ptemp_rho_ = new Charge(); this->ptemp_rho_->set_rhopw(this->pw_rho); const bool kin_den = XC_Functional::get_ked_flag() || (this->inp_->out_elf[0] > 0); // mohan add 20251202 - this->ptemp_rho_->allocate(this->inp_->nspin, kin_den, XC_Functional::get_ked_flag(), - this->inp_->test_charge); + this->ptemp_rho_->allocate( + this->inp_->nspin, + kin_den, + XC_Functional::get_ked_flag(), + this->inp_->test_charge); this->theta_.resize(this->inp_->nspin); this->resize_spin_arrays(); ModuleBase::Memory::record("OFDFT::pdLdphi_", sizeof(double) * this->inp_->nspin * this->pw_rho->nrxx); ModuleBase::Memory::record("OFDFT::pdEdphi_", sizeof(double) * this->inp_->nspin * this->pw_rho->nrxx); ModuleBase::Memory::record("OFDFT::pdirect_", sizeof(double) * this->inp_->nspin * this->pw_rho->nrxx); - ModuleBase::Memory::record("OFDFT::precip_dir_", sizeof(std::complex) * this->inp_->nspin * this->pw_rho->npw); + ModuleBase::Memory::record( + "OFDFT::precip_dir_", sizeof(std::complex) * this->inp_->nspin * this->pw_rho->npw); } void ESolver_OF::resize_spin_arrays() @@ -137,10 +142,10 @@ void ESolver_OF::resize_spin_arrays() * @param [in] ptemp_phi phi * @param [out] rdLdphi dL/dphi */ -void ESolver_OF::cal_potential(double* ptemp_phi, double* rdLdphi, UnitCell& ucell) +void ESolver_OF::cal_potential(double *ptemp_phi, double *rdLdphi, UnitCell &ucell) { std::vector dEdtemp_phi(this->pw_rho->nrxx); - std::vector temp_phi(this->inp_->nspin); + std::vector temp_phi(this->inp_->nspin); for (int is = 0; is < this->inp_->nspin; ++is) { @@ -160,12 +165,13 @@ void ESolver_OF::cal_potential(double* ptemp_phi, double* rdLdphi, UnitCell& uce unitcell::cal_ux(ucell, this->inp_->nspin); this->pelec->pot->update_from_charge(this->ptemp_rho_, &ucell); - ModuleBase::matrix& vr_eff = this->pelec->pot->get_eff_v(); + ModuleBase::matrix &vr_eff = this->pelec->pot->get_eff_v(); - this->kedf_manager_->get_potential(this->ptemp_rho_->rho, - temp_phi.data(), - this->pw_rho, - vr_eff); // KEDF potential + this->kedf_manager_->get_potential( + this->ptemp_rho_->rho, + temp_phi.data(), + this->pw_rho, + vr_eff); // KEDF potential for (int i = 0; i < this->pw_rho->nrxx; ++i) { dEdtemp_phi[i] = vr_eff(this->tn_spin_flag_, i); @@ -188,18 +194,24 @@ void ESolver_OF::cal_potential(double* ptemp_phi, double* rdLdphi, UnitCell& uce * @param [in] ptheta * @param [out] rdEdtheta dE/dTheta */ -void ESolver_OF::cal_dEdtheta(double** ptemp_phi, Charge* temp_rho, UnitCell& ucell, double* ptheta, double* rdEdtheta) +void ESolver_OF::cal_dEdtheta( + double **ptemp_phi, + Charge *temp_rho, + UnitCell &ucell, + double *ptheta, + double *rdEdtheta) { std::vector dphi_dtheta(this->pw_rho->nrxx); unitcell::cal_ux(ucell, this->inp_->nspin); this->pelec->pot->update_from_charge(temp_rho, &ucell); - ModuleBase::matrix& vr_eff = this->pelec->pot->get_eff_v(); + ModuleBase::matrix &vr_eff = this->pelec->pot->get_eff_v(); - this->kedf_manager_->get_potential(temp_rho->rho, - ptemp_phi, - this->pw_rho, - vr_eff); // KEDF potential + this->kedf_manager_->get_potential( + temp_rho->rho, + ptemp_phi, + this->pw_rho, + vr_eff); // KEDF potential for (int is = 0; is < this->inp_->nspin; ++is) { for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) @@ -207,7 +219,11 @@ void ESolver_OF::cal_dEdtheta(double** ptemp_phi, Charge* temp_rho, UnitCell& uc this->pdEdphi_[is][ir] = vr_eff(is, ir); dphi_dtheta[ir] = -this->pphi_[is][ir] * sin(ptheta[is]) + this->pdirect_[is][ir] * cos(ptheta[is]); } - rdEdtheta[is] = this->inner_product(this->pdEdphi_[is], dphi_dtheta.data(), this->pw_rho->nrxx, this->dV_); + rdEdtheta[is] = this->inner_product( + this->pdEdphi_[is], + dphi_dtheta.data(), + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(rdEdtheta[is]); } } @@ -221,9 +237,13 @@ void ESolver_OF::cal_dEdtheta(double** ptemp_phi, Charge* temp_rho, UnitCell& uc * @param nelec * @return mu */ -double ESolver_OF::cal_mu(double* pphi, double* pdEdphi, double nelec) +double ESolver_OF::cal_mu(double *pphi, double *pdEdphi, double nelec) { - double mu = this->inner_product(pphi, pdEdphi, this->pw_rho->nrxx, this->dV_); + double mu = this->inner_product( + pphi, + pdEdphi, + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(mu); mu = mu / (2.0 * nelec); return mu; @@ -251,8 +271,11 @@ void ESolver_OF::adjust_direction(void) // (1) make direction orthogonal to phi // |d'> = |d0> - |phi>/nelec - double inner_phi_direction - = this->inner_product(this->pphi_[0], this->pdirect_[0], this->pw_rho->nrxx, this->dV_); + double inner_phi_direction = this->inner_product( + this->pphi_[0], + this->pdirect_[0], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(inner_phi_direction); for (int i = 0; i < this->pw_rho->nrxx; ++i) { @@ -264,8 +287,11 @@ void ESolver_OF::adjust_direction(void) // (2) renormalize direction // |d> = |d'> * \sqrt(nelec) / - double norm_direction - = this->inner_product(this->pdirect_[0], this->pdirect_[0], this->pw_rho->nrxx, this->dV_); + double norm_direction = this->inner_product( + this->pdirect_[0], + this->pdirect_[0], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(norm_direction); norm_direction = std::sqrt(norm_direction); for (int i = 0; i < this->pw_rho->nrxx; ++i) @@ -282,19 +308,25 @@ void ESolver_OF::adjust_direction(void) { // (1) make direction orthogonal to phi // |d'> = |d0> - |phi>/nelec - double inner_phi_direction - = this->inner_product(this->pphi_[is], this->pdirect_[is], this->pw_rho->nrxx, this->dV_); + double inner_phi_direction = this->inner_product( + this->pphi_[is], + this->pdirect_[is], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(inner_phi_direction); for (int i = 0; i < this->pw_rho->nrxx; ++i) { - this->pdirect_[is][i] - = this->pdirect_[is][i] - this->pphi_[is][i] * inner_phi_direction / this->nelec_[is]; + this->pdirect_[is][i] = + this->pdirect_[is][i] - this->pphi_[is][i] * inner_phi_direction / this->nelec_[is]; } // (2) renormalize direction // |d> = |d'> * \sqrt(nelec) / - double norm_direction - = this->inner_product(this->pdirect_[is], this->pdirect_[is], this->pw_rho->nrxx, this->dV_); + double norm_direction = this->inner_product( + this->pdirect_[is], + this->pdirect_[is], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(norm_direction); norm_direction = std::sqrt(norm_direction); for (int i = 0; i < this->pw_rho->nrxx; ++i) @@ -314,13 +346,18 @@ void ESolver_OF::adjust_direction(void) * @param ptemp_phi * @param ucell */ -void ESolver_OF::check_direction(double* dEdtheta, double** ptemp_phi, UnitCell& ucell) +void ESolver_OF::check_direction(double *dEdtheta, double **ptemp_phi, UnitCell &ucell) { assert(this->inp_->nspin > 0); std::vector temp_theta(this->inp_->nspin, 0.0); double max_dEdtheta = 1e5; // threshould of dEdtheta, avoid the unstable optimization - this->cal_dEdtheta(ptemp_phi, this->ptemp_rho_, ucell, temp_theta.data(), dEdtheta); + this->cal_dEdtheta( + ptemp_phi, + this->ptemp_rho_, + ucell, + temp_theta.data(), + dEdtheta); // Assert dEdtheta(theta = 0) < 0, otherwise line search will not work. for (int is = 0; is < this->inp_->nspin; ++is) @@ -339,7 +376,12 @@ void ESolver_OF::check_direction(double* dEdtheta, double** ptemp_phi, UnitCell& this->pdirect_[is][ir] = -this->pdLdphi_[is][ir]; } this->adjust_direction(); - this->cal_dEdtheta(ptemp_phi, this->ptemp_rho_, ucell, temp_theta.data(), dEdtheta); + this->cal_dEdtheta( + ptemp_phi, + this->ptemp_rho_, + ucell, + temp_theta.data(), + dEdtheta); if (dEdtheta[is] > max_dEdtheta) { std::cout << "dEdtheta " << dEdtheta[is] << std::endl; @@ -364,7 +406,7 @@ void ESolver_OF::check_direction(double* dEdtheta, double** ptemp_phi, UnitCell& * @param ptemp_phi * @param ucell */ -void ESolver_OF::test_direction(double* dEdtheta, double** ptemp_phi, UnitCell& ucell) +void ESolver_OF::test_direction(double *dEdtheta, double **ptemp_phi, UnitCell &ucell) { double temp_energy = 0.; if (this->iter_ == 0) @@ -374,32 +416,39 @@ void ESolver_OF::test_direction(double* dEdtheta, double** ptemp_phi, UnitCell& this->theta_[0] = 0.001 * i; for (int ir = 0; ir < this->pw_rho->nrxx; ++ir) { - ptemp_phi[0][ir] - = this->pphi_[0][ir] * cos(this->theta_[0]) + this->pdirect_[0][ir] * sin(this->theta_[0]); + ptemp_phi[0][ir] = + this->pphi_[0][ir] * cos(this->theta_[0]) + this->pdirect_[0][ir] * sin(this->theta_[0]); ptemp_rho_->rho[0][ir] = ptemp_phi[0][ir] * ptemp_phi[0][ir]; } - this->cal_dEdtheta(ptemp_phi, ptemp_rho_, ucell, this->theta_.data(), dEdtheta); - this->pelec->cal_energies(2, - this->inp_->imp_sol, - this->inp_->sc_mag_switch, - this->inp_->dft_plus_u, - this->inp_->assume_isolated); + this->cal_dEdtheta( + ptemp_phi, + ptemp_rho_, + ucell, + this->theta_.data(), + dEdtheta); + this->pelec->cal_energies( + 2, + this->inp_->imp_sol, + this->inp_->sc_mag_switch, + this->inp_->dft_plus_u, + this->inp_->assume_isolated); temp_energy = this->pelec->f_en.etot; double kinetic_energy = 0.; double pseudopot_energy = 0.; kinetic_energy = this->kedf_manager_->get_energy(); - pseudopot_energy = this->inner_product(this->pelec->pot->get_fixed_v(), - this->ptemp_rho_->rho[0], - this->pw_rho->nrxx, - this->dV_); + pseudopot_energy = this->inner_product( + this->pelec->pot->get_fixed_v(), + this->ptemp_rho_->rho[0], + this->pw_rho->nrxx, + this->dV_); Parallel_Reduce::reduce_all(pseudopot_energy); temp_energy += kinetic_energy + pseudopot_energy; GlobalV::ofs_warning << i << " " << dEdtheta[0] << " " << temp_energy << std::endl; - if (this->theta_[0] == 0) - { - std::cout << "dEdtheta " << dEdtheta[0] << std::endl; - } - } + if (this->theta_[0] == 0) + { + std::cout << "dEdtheta " << dEdtheta[0] << std::endl; + } + } exit(0); } } diff --git a/source/source_esolver/esolver_sdft_pw.cpp b/source/source_esolver/esolver_sdft_pw.cpp index 840dd1175b..f36c2be478 100644 --- a/source/source_esolver/esolver_sdft_pw.cpp +++ b/source/source_esolver/esolver_sdft_pw.cpp @@ -7,10 +7,10 @@ #include "source_hsolver/diago_iter_assist.h" #include "source_hsolver/diago_params.h" #include "source_io/module_parameter/parameter.h" -#include "source_pw/module_stodft/sto_hsolver_pw.h" #include "source_pw/module_stodft/sto_dos.h" #include "source_pw/module_stodft/sto_elecond.h" #include "source_pw/module_stodft/sto_forces.h" +#include "source_pw/module_stodft/sto_hsolver_pw.h" #include "source_pw/module_stodft/sto_stress_pw.h" #include @@ -19,15 +19,13 @@ namespace ModuleESolver { -template -ESolver_SDFT_PW::ESolver_SDFT_PW() +template ESolver_SDFT_PW::ESolver_SDFT_PW() { this->classname = "ESolver_SDFT_PW"; this->basisname = "PW"; } -template -ESolver_SDFT_PW::~ESolver_SDFT_PW() +template ESolver_SDFT_PW::~ESolver_SDFT_PW() { //**************************************************** // do not add any codes in this deconstructor funcion @@ -35,15 +33,19 @@ ESolver_SDFT_PW::~ESolver_SDFT_PW() } template -void ESolver_SDFT_PW::before_all_runners(BaseCell& basecell, const Input_para& inp) +void ESolver_SDFT_PW::before_all_runners(BaseCell &basecell, const Input_para &inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); // 1) initialize parameters from int Input class this->nche_sto = inp.nche_sto; this->method_sto = inp.method_sto; - this->stoche.init(inp.nche_sto, inp.method_sto, inp.emax_sto, inp.emin_sto); + this->stoche.init( + inp.nche_sto, + inp.method_sto, + inp.emax_sto, + inp.emin_sto); // 2) run "before_all_runners" in ESolver_KS ESolver_KS_PW::before_all_runners(ucell, inp); @@ -58,7 +60,11 @@ void ESolver_SDFT_PW::before_all_runners(BaseCell& basecell, const In } else { - this->stowf.init_sto_orbitals_Ecut(inp.seed_sto, this->kv, *this->pw_wfc, inp.initsto_ecut); + this->stowf.init_sto_orbitals_Ecut( + inp.seed_sto, + this->kv, + *this->pw_wfc, + inp.initsto_ecut); } } else @@ -73,45 +79,48 @@ void ESolver_SDFT_PW::before_all_runners(BaseCell& basecell, const In // 4) allocate spaces for \sqrt(f(H))|chi> and |\tilde{chi}> size_t size = stowf.chi0->size(); - this->stowf.shchi = new psi::Psi(this->kv.get_nks(), - this->stowf.nchip_max, - this->pw_wfc->npwk_max, - this->kv.ngk, - true); + this->stowf.shchi = new psi::Psi( + this->kv.get_nks(), + this->stowf.nchip_max, + this->pw_wfc->npwk_max, + this->kv.ngk, + true); ModuleBase::Memory::record("SDFT::shchi", size * sizeof(T)); if (inp.nbands > 0) { - this->stowf.chiortho = new psi::Psi(this->kv.get_nks(), - this->stowf.nchip_max, - this->pw_wfc->npwk_max, - this->kv.ngk, - true); + this->stowf.chiortho = new psi::Psi( + this->kv.get_nks(), + this->stowf.nchip_max, + this->pw_wfc->npwk_max, + this->kv.ngk, + true); ModuleBase::Memory::record("SDFT::chiortho", size * sizeof(T)); } return; } -template -void ESolver_SDFT_PW::before_scf(UnitCell& ucell, const int istep) +template void ESolver_SDFT_PW::before_scf(UnitCell &ucell, const int istep) { ModuleBase::TITLE("ESolver_SDFT_PW", "before_scf"); ModuleBase::timer::start("ESolver_SDFT_PW", "before_scf"); ESolver_KS_PW::before_scf(ucell, istep); - delete reinterpret_cast*>(this->p_hamilt); - this->p_hamilt = new StoHamiltPW(this->pelec->pot, - this->pw_wfc, - &this->kv, - &this->ppcell, - &ucell, - PARAM.globalv.npol, - &this->stoche.emin_sto, - &this->stoche.emax_sto); - this->p_hamilt_sto = static_cast*>(this->p_hamilt); - - if (istep > 0 && this->inp_->nbands_sto != 0 && this->inp_->initsto_freq > 0 && istep % this->inp_->initsto_freq == 0) + delete reinterpret_cast *>(this->p_hamilt); + this->p_hamilt = new StoHamiltPW( + this->pelec->pot, + this->pw_wfc, + &this->kv, + &this->ppcell, + &ucell, + PARAM.globalv.npol, + &this->stoche.emin_sto, + &this->stoche.emax_sto); + this->p_hamilt_sto = static_cast *>(this->p_hamilt); + + if (istep > 0 && this->inp_->nbands_sto != 0 && this->inp_->initsto_freq > 0 && + istep % this->inp_->initsto_freq == 0) { this->stowf.update_sto_orbitals(this->inp_->seed_sto); } @@ -120,14 +129,22 @@ void ESolver_SDFT_PW::before_scf(UnitCell& ucell, const int istep) } template -void ESolver_SDFT_PW::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) +void ESolver_SDFT_PW::iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) { // call iter_finish() of ESolver_KS - ESolver_KS::iter_finish(ucell, istep, iter, conv_esolver); + ESolver_KS::iter_finish( + ucell, + istep, + iter, + conv_esolver); } template -void ESolver_SDFT_PW::after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) +void ESolver_SDFT_PW::after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) { ModuleBase::TITLE("ESolver_SDFT_PW", "after_scf"); ModuleBase::timer::start("ESolver_SDFT_PW", "after_scf"); @@ -139,7 +156,11 @@ void ESolver_SDFT_PW::after_scf(UnitCell& ucell, const int istep, con } template -void ESolver_SDFT_PW::hamilt2rho_single(UnitCell& ucell, int istep, int iter, double ethr) +void ESolver_SDFT_PW::hamilt2rho_single( + UnitCell &ucell, + int istep, + int iter, + double ethr) { ModuleBase::TITLE("ESolver_SDFT_PW", "hamilt2rho"); ModuleBase::timer::start("ESolver_SDFT_PW", "hamilt2rho"); @@ -149,52 +170,62 @@ void ESolver_SDFT_PW::hamilt2rho_single(UnitCell& ucell, int istep, i this->pelec->f_en.demet = 0.0; // setup diagonalization parameters for SDFT - hsolver::setup_diago_params_sdft(istep, iter, ethr, *this->inp_); + hsolver::setup_diago_params_sdft( + istep, + iter, + ethr, + *this->inp_); bool skip_charge = this->inp_->calculation == "nscf" ? true : false; // hsolver only exists in this function - StoHSolverPW sto_hsolver_pw_obj(&this->kv, - this->pw_wfc, - this->stowf, - this->stoche, - this->p_hamilt_sto, - this->inp_->calculation, - this->inp_->basis_type, - this->inp_->ks_solver, - PARAM.globalv.use_uspp, - this->inp_->nspin, - hsolver::DiagoIterAssist::SCF_ITER, - hsolver::DiagoIterAssist::PW_DIAG_NMAX, - hsolver::DiagoIterAssist::PW_DIAG_THR, - hsolver::DiagoIterAssist::need_subspace, - this->inp_->nbands, - this->inp_->diago_smooth_ethr, - this->inp_->pw_diag_ndim, - this->inp_->diag_subspace, - this->inp_->nb2d, - PARAM.globalv.ks_run, - PARAM.globalv.all_ks_run, - this->inp_->bndpar); - - sto_hsolver_pw_obj.solve(ucell, - static_cast*>(this->p_hamilt), - *this->stp.template get_psi_t(), - this->stp.psi_cpu[0], - this->pelec, - this->pw_wfc, - this->stowf, - istep, - iter, - GlobalV::ofs_running, - skip_charge); + StoHSolverPW sto_hsolver_pw_obj( + &this->kv, + this->pw_wfc, + this->stowf, + this->stoche, + this->p_hamilt_sto, + this->inp_->calculation, + this->inp_->basis_type, + this->inp_->ks_solver, + PARAM.globalv.use_uspp, + this->inp_->nspin, + hsolver::DiagoIterAssist::SCF_ITER, + hsolver::DiagoIterAssist::PW_DIAG_NMAX, + hsolver::DiagoIterAssist::PW_DIAG_THR, + hsolver::DiagoIterAssist::need_subspace, + this->inp_->nbands, + this->inp_->diago_smooth_ethr, + this->inp_->pw_diag_ndim, + this->inp_->diag_subspace, + this->inp_->nb2d, + PARAM.globalv.ks_run, + PARAM.globalv.all_ks_run, + this->inp_->bndpar); + + sto_hsolver_pw_obj.solve( + ucell, + static_cast *>(this->p_hamilt), + *this->stp.template get_psi_t(), + this->stp.psi_cpu[0], + this->pelec, + this->pw_wfc, + this->stowf, + istep, + iter, + GlobalV::ofs_running, + skip_charge); // set_diagethr need it this->esolver_KS_ne = sto_hsolver_pw_obj.stoiter.KS_ne; if (PARAM.globalv.ks_run) { - module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rho, ucell.symm); + module_charge::symmetrize_rho( + this->inp_->nspin, + this->chr, + this->pw_rho, + ucell.symm); this->pelec->f_en.deband = this->pelec->cal_delta_eband(ucell); } else @@ -207,69 +238,80 @@ void ESolver_SDFT_PW::hamilt2rho_single(UnitCell& ucell, int istep, i #endif } #ifdef __MPI - MPI_Bcast(&(this->pelec->f_en.deband), 1, MPI_DOUBLE, 0, BP_WORLD); + MPI_Bcast( + &(this->pelec->f_en.deband), + 1, + MPI_DOUBLE, + 0, + BP_WORLD); #endif ModuleBase::timer::end("ESolver_SDFT_PW", "hamilt2rho"); } -template -double ESolver_SDFT_PW::cal_energy() +template double ESolver_SDFT_PW::cal_energy() { return this->pelec->f_en.etot; } template -void ESolver_SDFT_PW::cal_force(BaseCell& basecell, ModuleBase::matrix& force) +void ESolver_SDFT_PW::cal_force(BaseCell &basecell, ModuleBase::matrix &force) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); Sto_Forces ff(ucell.nat); - ff.cal_stoforce(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad, - force, - *this->pelec, - this->pw_rho, - &ucell.symm, - &this->sf, - &this->kv, - this->pw_wfc, - this->locpp, - this->ppcell, - ucell, - *this->stp.template get_psi_t(), - this->stowf); + ff.cal_stoforce( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + force, + *this->pelec, + this->pw_rho, + &ucell.symm, + &this->sf, + &this->kv, + this->pw_wfc, + this->locpp, + this->ppcell, + ucell, + *this->stp.template get_psi_t(), + this->stowf); } template -void ESolver_SDFT_PW::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) +void ESolver_SDFT_PW::cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); Sto_Stress_PW ss; - ss.cal_stress(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, - this->inp_->gga_grad, PARAM.globalv.gamma_only_pw, - stress, - *this->pelec, - this->pw_rho, - &ucell.symm, - &this->sf, - &this->kv, - this->pw_wfc, - *this->stp.template get_psi_t(), - this->stowf, - &this->chr, - &this->locpp, - &this->ppcell, - ucell); + ss.cal_stress( + this->inp_->nspin, + PARAM.globalv.domag, + PARAM.globalv.domag_z, + this->inp_->gga_grad, + PARAM.globalv.gamma_only_pw, + stress, + *this->pelec, + this->pw_rho, + &ucell.symm, + &this->sf, + &this->kv, + this->pw_wfc, + *this->stp.template get_psi_t(), + this->stowf, + &this->chr, + &this->locpp, + &this->ppcell, + ucell); } -template -void ESolver_SDFT_PW::after_all_runners(BaseCell& basecell) +template void ESolver_SDFT_PW::after_all_runners(BaseCell &basecell) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); // 1) write down etot and eigenvalues (for MDFT) information ESolver_FP::after_all_runners(ucell); @@ -291,18 +333,19 @@ void ESolver_SDFT_PW::after_all_runners(BaseCell& basecell) this->pw_wfc, &this->kv, this->pelec, - reinterpret_cast>*>(this->stp.psi_cpu), - reinterpret_cast>*>(this->p_hamilt), + reinterpret_cast> *>(this->stp.psi_cpu), + reinterpret_cast> *>(this->p_hamilt), this->stoche, - reinterpret_cast, base_device::DEVICE_CPU>*>(&stowf)); - sto_dos.decide_param(this->inp_->dos_nche, - this->inp_->emin_sto, - this->inp_->emax_sto, - PARAM.globalv.dos_setemin, - PARAM.globalv.dos_setemax, - this->inp_->dos_emin_ev, - this->inp_->dos_emax_ev, - this->inp_->dos_scale); + reinterpret_cast, base_device::DEVICE_CPU> *>(&stowf)); + sto_dos.decide_param( + this->inp_->dos_nche, + this->inp_->emin_sto, + this->inp_->emax_sto, + PARAM.globalv.dos_setemin, + PARAM.globalv.dos_setemax, + this->inp_->dos_emin_ev, + this->inp_->dos_emax_ev, + this->inp_->dos_scale); sto_dos.caldos(this->inp_->dos_sigma, this->inp_->dos_edelta_ev, this->inp_->npart_sto); } @@ -316,17 +359,23 @@ void ESolver_SDFT_PW::after_all_runners(BaseCell& basecell) this->pw_wfc, this->stp.template get_psi_t(), &this->ppcell, - static_cast, Device>*>(this->p_hamilt), + static_cast, Device> *>(this->p_hamilt), this->stoche, &stowf); - sto_elecond.decide_nche(this->inp_->cond_dt, 1e-8, this->nche_sto, this->inp_->emin_sto, this->inp_->emax_sto); - sto_elecond.sKG(this->inp_->cond_smear, - this->inp_->cond_fwhm, - this->inp_->cond_wcut, - this->inp_->cond_dw, - this->inp_->cond_dt, - this->inp_->cond_nonlocal, - this->inp_->npart_sto); + sto_elecond.decide_nche( + this->inp_->cond_dt, + 1e-8, + this->nche_sto, + this->inp_->emin_sto, + this->inp_->emax_sto); + sto_elecond.sKG( + this->inp_->cond_smear, + this->inp_->cond_fwhm, + this->inp_->cond_wcut, + this->inp_->cond_dw, + this->inp_->cond_dt, + this->inp_->cond_nonlocal, + this->inp_->npart_sto); } } diff --git a/source/source_esolver/esolver_sdft_pw.h b/source/source_esolver/esolver_sdft_pw.h index 2a5c4965c3..8473ba05f5 100644 --- a/source/source_esolver/esolver_sdft_pw.h +++ b/source/source_esolver/esolver_sdft_pw.h @@ -2,16 +2,15 @@ #define ESOLVER_SDFT_PW_H #include "esolver_ks_pw.h" -#include "source_pw/module_stodft/sto_hamilt_pw.h" #include "source_pw/module_stodft/sto_che.h" +#include "source_pw/module_stodft/sto_hamilt_pw.h" #include "source_pw/module_stodft/sto_iter.h" #include "source_pw/module_stodft/sto_wf.h" namespace ModuleESolver { -template -class ESolver_SDFT_PW : public ESolver_KS_PW +template class ESolver_SDFT_PW : public ESolver_KS_PW { private: using Real = typename GetTypeReal::type; @@ -20,29 +19,37 @@ class ESolver_SDFT_PW : public ESolver_KS_PW ESolver_SDFT_PW(); ~ESolver_SDFT_PW(); - void before_all_runners(BaseCell& basecell, const Input_para& inp) override; + void before_all_runners(BaseCell &basecell, const Input_para &inp) override; double cal_energy() override; - void cal_force(BaseCell& basecell, ModuleBase::matrix& force) override; + void cal_force(BaseCell &basecell, ModuleBase::matrix &force) override; - void cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) override; + void cal_stress(BaseCell &basecell, ModuleBase::matrix &stress) override; public: Stochastic_WF stowf; StoChe stoche; - StoHamiltPW* p_hamilt_sto = nullptr; + StoHamiltPW *p_hamilt_sto = nullptr; protected: - virtual void before_scf(UnitCell& ucell, const int istep) override; + virtual void before_scf(UnitCell &ucell, const int istep) override; - virtual void hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr) override; + virtual void hamilt2rho_single( + UnitCell &ucell, + const int istep, + const int iter, + const double ethr) override; - virtual void iter_finish(UnitCell& ucell, const int istep, int& iter, bool& conv_esolver) override; + virtual void iter_finish( + UnitCell &ucell, + const int istep, + int &iter, + bool &conv_esolver) override; - virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override; + virtual void after_scf(UnitCell &ucell, const int istep, const bool conv_esolver) override; - virtual void after_all_runners(BaseCell& basecell) override; + virtual void after_all_runners(BaseCell &basecell) override; private: int nche_sto; ///< norder of Chebyshev diff --git a/source/source_esolver/lcao_others.cpp b/source/source_esolver/lcao_others.cpp index 1c1e867577..77d3b0d969 100644 --- a/source/source_esolver/lcao_others.cpp +++ b/source/source_esolver/lcao_others.cpp @@ -17,9 +17,9 @@ #include "source_lcao/hamilt_lcao.h" #include "source_lcao/lcao_domain.h" #include "source_lcao/module_deltaspin/spin_constrain.h" -#include "source_pw/module_pwdft/dftu_base.h" #include "source_lcao/module_operator_lcao/op_exx_lcao.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" +#include "source_pw/module_pwdft/dftu_base.h" #ifdef __EXX #endif @@ -30,11 +30,10 @@ namespace ModuleESolver { -template -void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) +template void ESolver_KS_LCAO::others(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_LCAO", "others"); ModuleBase::timer::start("ESolver_KS_LCAO", "others"); @@ -46,13 +45,14 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) if (cal_type == "test_memory") { std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "testing memory"); - Cal_Test::test_memory(ucell.nat, - ucell.ntype, - ucell.GGT, - this->pw_rho, - this->pw_wfc, - this->p_chgmix->get_mixing_mode(), - this->p_chgmix->get_mixing_ndim()); + Cal_Test::test_memory( + ucell.nat, + ucell.ntype, + ucell.GGT, + this->pw_rho, + this->pw_wfc, + this->p_chgmix->get_mixing_mode(), + this->p_chgmix->get_mixing_ndim()); std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "testing memory"); return; } @@ -61,13 +61,14 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) // test_search_neighbor(); std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "testing neighbour"); double search_radius = this->inp_->search_radius; - atom_arrange::search(PARAM.globalv.search_pbc, - GlobalV::ofs_running, - this->gd, - ucell, - search_radius, - this->inp_->test_atom_input, - true); + atom_arrange::search( + PARAM.globalv.search_pbc, + GlobalV::ofs_running, + this->gd, + ucell, + search_radius, + this->inp_->test_atom_input, + true); std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "testing neighbour"); return; } @@ -78,41 +79,55 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) // 1. prepare HS matrices, prepare grid integral // (1) Find adjacent atoms for each atom. - double search_radius = atom_arrange::set_sr_NL(GlobalV::ofs_running, - this->inp_->out_level, - orb_.get_rcutmax_Phi(), - ucell.infoNL->get_rcutmax_Beta(), - gamma_only_local); + double search_radius = atom_arrange::set_sr_NL( + GlobalV::ofs_running, + this->inp_->out_level, + orb_.get_rcutmax_Phi(), + ucell.infoNL->get_rcutmax_Beta(), + gamma_only_local); - atom_arrange::search(PARAM.globalv.search_pbc, GlobalV::ofs_running, this->gd, ucell, search_radius, this->inp_->test_atom_input); + atom_arrange::search( + PARAM.globalv.search_pbc, + GlobalV::ofs_running, + this->gd, + ucell, + search_radius, + this->inp_->test_atom_input); // (3) Periodic condition search for each grid. - gint_info_.reset(new ModuleGint::GintInfo(this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbz, - this->pw_rho->nx, - this->pw_rho->ny, - this->pw_rho->nz, - 0, - 0, - this->pw_big->nbzp_start, - this->pw_big->nbx, - this->pw_big->nby, - this->pw_big->nbzp, - orb_.Phi, - ucell, - this->gd, - this->inp_->nspin, - gamma_only_local, - PARAM.globalv.domag, - this->inp_->device == "gpu", - this->inp_->nstream)); + gint_info_.reset(new ModuleGint::GintInfo( + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbz, + this->pw_rho->nx, + this->pw_rho->ny, + this->pw_rho->nz, + 0, + 0, + this->pw_big->nbzp_start, + this->pw_big->nbx, + this->pw_big->nby, + this->pw_big->nbzp, + orb_.Phi, + ucell, + this->gd, + this->inp_->nspin, + gamma_only_local, + PARAM.globalv.domag, + this->inp_->device == "gpu", + this->inp_->nstream)); ModuleGint::Gint::set_gint_info(gint_info_.get()); // (2)For each atom, calculate the adjacent atoms in different cells // and allocate the space for H(R) and S(R). // If k point is used here, allocate HlocR after atom_arrange. - this->RA.for_2d(ucell, this->gd, this->pv, gamma_only_local, PARAM.globalv.npol, orb_.cutoffs()); + this->RA.for_2d( + ucell, + this->gd, + this->pv, + gamma_only_local, + PARAM.globalv.npol, + orb_.cutoffs()); if (this->inp_->out_level != "m" && !gamma_only_local) { ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "ParaV.nnr", this->pv.nnr); @@ -136,48 +151,55 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) } if (this->p_hamilt == nullptr) { - const bool load_exx_flag = !GlobalC::restart.info_load.restart_exx - && GlobalC::restart.info_load.load_H; - this->p_hamilt = new hamilt::HamiltLCAO(ucell, - this->gd, - &this->pv, - this->pelec->pot, - this->kv, - two_center_bundle_, - orb_, - this->dmat.dm, - this->dftu_.get(), - this->deepks, - istep, - this->exx_nao, - this->exx_info_, - *this->inp_, - load_exx_flag, - this->get_td_info()); + const bool load_exx_flag = !GlobalC::restart.info_load.restart_exx && GlobalC::restart.info_load.load_H; + this->p_hamilt = new hamilt::HamiltLCAO( + ucell, + this->gd, + &this->pv, + this->pelec->pot, + this->kv, + two_center_bundle_, + orb_, + this->dmat.dm, + this->dftu_.get(), + this->deepks, + istep, + this->exx_nao, + this->exx_info_, + *this->inp_, + load_exx_flag, + this->get_td_info()); } // for each ionic step, the overlap must be rebuilt // since it depends on ionic positions - this->deepks.build_overlap(ucell, orb_, pv, gd, *(two_center_bundle_.overlap_orb_alpha), *this->inp_); + this->deepks.build_overlap( + ucell, + orb_, + pv, + gd, + *(two_center_bundle_.overlap_orb_alpha), + *this->inp_); if (this->inp_->sc_mag_switch) { - spinconstrain::SpinConstrain& sc = spinconstrain::SpinConstrain::getScInstance(); - sc.init_sc(this->inp_->sc_thr, - this->inp_->nsc, - this->inp_->nsc_min, - this->inp_->alpha_trial, - this->inp_->sccut, - this->inp_->sc_drop_thr, - ucell, - this->inp_->sc_direction_only, - &(this->pv), - this->inp_->nspin, - this->kv, - this->p_hamilt, - this->psi, - this->dmat.dm, - this->pelec); + spinconstrain::SpinConstrain &sc = spinconstrain::SpinConstrain::getScInstance(); + sc.init_sc( + this->inp_->sc_thr, + this->inp_->nsc, + this->inp_->nsc_min, + this->inp_->alpha_trial, + this->inp_->sccut, + this->inp_->sc_drop_thr, + ucell, + this->inp_->sc_direction_only, + &(this->pv), + this->inp_->nspin, + this->kv, + this->p_hamilt, + this->psi, + this->dmat.dm, + this->pelec); } //========================================================= @@ -187,7 +209,15 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) unitcell::cal_ux(ucell, this->inp_->nspin); // pelec should be initialized before these calculations - elecstate::init_scf(ucell, this->Pgrid, this->sf.strucFac, this->locpp.numeric, istep, global_out_dir, *this->inp_, this->pelec); + elecstate::init_scf( + ucell, + this->Pgrid, + this->sf.strucFac, + this->locpp.numeric, + istep, + global_out_dir, + *this->inp_, + this->pelec); // self consistent calculations for electronic ground state if (cal_type == "get_pchg") @@ -196,24 +226,26 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) Get_pchg_lcao get_pchg(*this->psi, this->pv, this->inp_->nspin); if (gamma_only_local) { - get_pchg.begin_gamma(ucell, - this->Pgrid, - this->gd, - this->inp_->out_pchg, - global_out_dir, - GlobalV::ofs_running); + get_pchg.begin_gamma( + ucell, + this->Pgrid, + this->gd, + this->inp_->out_pchg, + global_out_dir, + GlobalV::ofs_running); } else { - get_pchg.begin_k(*this->pw_rhod, - ucell, - this->Pgrid, - this->gd, - this->kv, - this->inp_->out_pchg, - this->inp_->if_separate_k, - global_out_dir, - GlobalV::ofs_running); + get_pchg.begin_k( + *this->pw_rhod, + ucell, + this->Pgrid, + this->gd, + this->kv, + this->inp_->out_pchg, + this->inp_->if_separate_k, + global_out_dir, + GlobalV::ofs_running); } std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "getting partial charge"); } @@ -223,22 +255,24 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) Get_wf_lcao get_wf(*this->psi, this->pv, this->inp_->nspin); if (gamma_only_local) { - get_wf.begin_gamma(ucell, - this->Pgrid, - this->inp_->out_wfc_norm, - this->inp_->out_wfc_re_im, - global_out_dir, - GlobalV::ofs_running); + get_wf.begin_gamma( + ucell, + this->Pgrid, + this->inp_->out_wfc_norm, + this->inp_->out_wfc_re_im, + global_out_dir, + GlobalV::ofs_running); } else { - get_wf.begin_k(ucell, - this->Pgrid, - this->kv, - this->inp_->out_wfc_norm, - this->inp_->out_wfc_re_im, - global_out_dir, - GlobalV::ofs_running); + get_wf.begin_k( + ucell, + this->Pgrid, + this->kv, + this->inp_->out_wfc_norm, + this->inp_->out_wfc_re_im, + global_out_dir, + GlobalV::ofs_running); } std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "getting wave function"); } diff --git a/source/source_esolver/pw_others.cpp b/source/source_esolver/pw_others.cpp index e138f7f36f..0af7308c1b 100644 --- a/source/source_esolver/pw_others.cpp +++ b/source/source_esolver/pw_others.cpp @@ -9,11 +9,10 @@ namespace ModuleESolver { -template -void ESolver_KS_PW::others(BaseCell& basecell, const int istep) +template void ESolver_KS_PW::others(BaseCell &basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); - UnitCell& ucell = static_cast(basecell); + UnitCell &ucell = static_cast(basecell); ModuleBase::TITLE("ESolver_KS_PW", "others"); @@ -21,23 +20,25 @@ void ESolver_KS_PW::others(BaseCell& basecell, const int istep) if (cal_type == "test_memory") { - Cal_Test::test_memory(ucell.nat, - ucell.ntype, - ucell.GGT, - this->pw_rho, - this->pw_wfc, - this->p_chgmix->get_mixing_mode(), - this->p_chgmix->get_mixing_ndim()); + Cal_Test::test_memory( + ucell.nat, + ucell.ntype, + ucell.GGT, + this->pw_rho, + this->pw_wfc, + this->p_chgmix->get_mixing_mode(), + this->p_chgmix->get_mixing_ndim()); } else if (cal_type == "gen_bessel") { Numerical_Descriptor nc; - nc.output_descriptor(ucell, - *(this->stp.psi_cpu), - this->inp_->bessel_descriptor_lmax, - this->inp_->bessel_descriptor_rcut, - this->inp_->bessel_descriptor_tolerence, - this->kv.get_nks()); + nc.output_descriptor( + ucell, + *(this->stp.psi_cpu), + this->inp_->bessel_descriptor_lmax, + this->inp_->bessel_descriptor_rcut, + this->inp_->bessel_descriptor_tolerence, + this->kv.get_nks()); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "GENERATE DESCRIPTOR FOR DEEPKS"); } else diff --git a/source/source_esolver/test/esolver_dp_test.cpp b/source/source_esolver/test/esolver_dp_test.cpp index 4bd3c44501..bf50b111a9 100644 --- a/source/source_esolver/test/esolver_dp_test.cpp +++ b/source/source_esolver/test/esolver_dp_test.cpp @@ -1,9 +1,10 @@ -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "for_test.h" - #include "../esolver_dp.h" + +#include "for_test.h" #include "source_io/module_parameter/input_parameter.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" /************************************************ * unit tests of class ESolver_DP ***********************************************/ @@ -52,7 +53,7 @@ class ESolverDPTest : public ::testing::Test delete[] ucell.atoms; } - ModuleESolver::ESolver_DP* esolver; + ModuleESolver::ESolver_DP *esolver; Input_para inp; UnitCell ucell; }; @@ -162,9 +163,9 @@ TEST_F(ESolverDPTest, Postprocess) esolver->after_all_runners(ucell); GlobalV::ofs_running.close(); - std::string expected_output - = "\n --------------------------------------------\n !FINAL_ETOT_IS 133.3358404000000235 eV\n " - "--------------------------------------------\n\n\n"; + std::string expected_output = + "\n --------------------------------------------\n !FINAL_ETOT_IS 133.3358404000000235 eV\n " + "--------------------------------------------\n\n\n"; std::ifstream ifs("log"); std::string output((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); diff --git a/source/source_esolver/test/for_test.h b/source/source_esolver/test/for_test.h index dd7448b956..6a117d458b 100644 --- a/source/source_esolver/test/for_test.h +++ b/source/source_esolver/test/for_test.h @@ -29,7 +29,7 @@ UnitCell::UnitCell() for (int it = 0; it < ntype; it++) { - Atom* atom = &atoms[it]; + Atom *atom = &atoms[it]; for (int ia = 0; ia < atom->na; ia++) { for (int ik = 0; ik < 3; ++ik) @@ -39,38 +39,22 @@ UnitCell::UnitCell() } } } -UnitCell::~UnitCell() -{ -} -Magnetism::Magnetism() -{ -} -Magnetism::~Magnetism() -{ -} +UnitCell::~UnitCell() {} +Magnetism::Magnetism() {} +Magnetism::~Magnetism() {} Atom::Atom() { na = 1; tau.resize(na); mbl.resize(na); } -Atom::~Atom() -{ -} -Atom_pseudo::Atom_pseudo() -{ -} -Atom_pseudo::~Atom_pseudo() -{ -} -pseudo::pseudo() -{ -} -pseudo::~pseudo() -{ -} -SepPot::SepPot(){} -SepPot::~SepPot(){} +Atom::~Atom() {} +Atom_pseudo::Atom_pseudo() {} +Atom_pseudo::~Atom_pseudo() {} +pseudo::pseudo() {} +pseudo::~pseudo() {} +SepPot::SepPot() {} +SepPot::~SepPot() {} Sep_Cell::Sep_Cell() noexcept {} Sep_Cell::~Sep_Cell() noexcept {} #endif