From 1cbfa01923c9d4337669f14701a0e093e1fe5be2 Mon Sep 17 00:00:00 2001 From: SY Wang Date: Mon, 26 Oct 2026 03:33:57 +0800 Subject: [PATCH] Precommit: Format source_esolver --- source/source_esolver/esolver.h | 4 +- source/source_esolver/esolver_dfpt_pw.cpp | 79 +- source/source_esolver/esolver_dfpt_pw.h | 3 +- source/source_esolver/esolver_dm2rho.cpp | 9 +- source/source_esolver/esolver_double_xc.cpp | 49 +- source/source_esolver/esolver_dp.cpp | 61 +- source/source_esolver/esolver_dp.h | 4 +- source/source_esolver/esolver_factory.cpp | 6 +- source/source_esolver/esolver_fp.cpp | 200 +++-- source/source_esolver/esolver_fp.h | 17 +- source/source_esolver/esolver_gets.cpp | 4 +- source/source_esolver/esolver_ks.cpp | 239 +++--- source/source_esolver/esolver_ks.h | 30 +- source/source_esolver/esolver_ks_lcao.cpp | 83 +- source/source_esolver/esolver_ks_lcao.h | 5 +- .../source_esolver/esolver_ks_lcao_tddft.cpp | 170 +++-- source/source_esolver/esolver_ks_lcao_tddft.h | 12 +- source/source_esolver/esolver_ks_lcaopw.cpp | 430 ++++++----- source/source_esolver/esolver_ks_lcaopw.h | 2 +- source/source_esolver/esolver_ks_pw.cpp | 47 +- source/source_esolver/esolver_ks_pw.h | 3 +- source/source_esolver/esolver_ks_pw_tddft.cpp | 31 +- source/source_esolver/esolver_lj.cpp | 31 +- source/source_esolver/esolver_lj.h | 4 +- source/source_esolver/esolver_lr_cfg.cpp | 113 +-- source/source_esolver/esolver_lr_grad.cpp | 288 ++++--- source/source_esolver/esolver_lr_init.cpp | 277 ++++--- source/source_esolver/esolver_lr_lcao_bse.cpp | 608 +++++++++------ source/source_esolver/esolver_lr_lcao_bse.h | 77 +- .../source_esolver/esolver_lr_lcao_tddft.cpp | 324 +++++--- source/source_esolver/esolver_lr_lcao_tddft.h | 722 +++++++++--------- source/source_esolver/esolver_lr_orb.cpp | 185 +++-- source/source_esolver/esolver_lr_rlx.cpp | 153 ++-- source/source_esolver/esolver_nep.cpp | 28 +- source/source_esolver/esolver_nep.h | 4 +- source/source_esolver/esolver_of.cpp | 130 ++-- source/source_esolver/esolver_of.h | 28 +- source/source_esolver/esolver_of_tddft.cpp | 24 +- source/source_esolver/esolver_of_tool.cpp | 41 +- source/source_esolver/esolver_sdft_pw.cpp | 21 +- source/source_esolver/esolver_sdft_pw.h | 2 +- source/source_esolver/lcao_others.cpp | 29 +- .../source_esolver/test/esolver_dp_test.cpp | 9 +- source/source_esolver/test/for_test.h | 16 +- 44 files changed, 2748 insertions(+), 1854 deletions(-) diff --git a/source/source_esolver/esolver.h b/source/source_esolver/esolver.h index f302584cbb8..f479824c480 100644 --- a/source/source_esolver/esolver.h +++ b/source/source_esolver/esolver.h @@ -35,7 +35,9 @@ class ESolver //! 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; diff --git a/source/source_esolver/esolver_dfpt_pw.cpp b/source/source_esolver/esolver_dfpt_pw.cpp index 777a678d4a2..a751b780064 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. @@ -44,12 +45,12 @@ 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 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) @@ -130,12 +131,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,8 +157,7 @@ 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); } } @@ -287,8 +285,7 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) } 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) @@ -312,9 +309,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()); } @@ -343,7 +339,9 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) // 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()); + = 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) { @@ -360,8 +358,15 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) "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); + 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) @@ -383,8 +388,7 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell) 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; + 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); @@ -397,8 +401,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) { @@ -412,20 +416,29 @@ 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_, + 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); } diff --git a/source/source_esolver/esolver_dfpt_pw.h b/source/source_esolver/esolver_dfpt_pw.h index 8a2688dfadf..739e252a534 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; } diff --git a/source/source_esolver/esolver_dm2rho.cpp b/source/source_esolver/esolver_dm2rho.cpp index 77b7825cc34..98adee105a7 100644 --- a/source/source_esolver/esolver_dm2rho.cpp +++ b/source/source_esolver/esolver_dm2rho.cpp @@ -6,8 +6,8 @@ #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 @@ -66,7 +66,12 @@ void ESolver_DM2rho::runner(BaseCell& basecell, const int istep) // 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 diff --git a/source/source_esolver/esolver_double_xc.cpp b/source/source_esolver/esolver_double_xc.cpp index 5afe888d977..7b2ec771c31 100644 --- a/source/source_esolver/esolver_double_xc.cpp +++ b/source/source_esolver/esolver_double_xc.cpp @@ -69,9 +69,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; } @@ -104,14 +104,16 @@ 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.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); + 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) @@ -158,8 +160,7 @@ 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; + 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, @@ -305,10 +306,10 @@ void ESolver_DoubleXC::iter_finish(UnitCell& ucell, const int istep, int 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------"<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; @@ -424,10 +425,16 @@ 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}; + 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(), @@ -454,7 +461,9 @@ void ESolver_DoubleXC::cal_force(BaseCell& basecell, ModuleBase::matrix& this->exx_nao, &ucell.symm, this->exx_info_, - fs_cfg, nullptr, nullptr); + 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_dp.cpp b/source/source_esolver/esolver_dp.cpp index 98708ee051e..041c74befab 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 @@ -117,7 +118,7 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) 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)]; + : 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; @@ -139,7 +140,7 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) 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> sorted_neighbors(static_cast(nowned_atoms)); for (int iat = 0; iat < nowned_atoms; ++iat) { ilist[static_cast(iat)] = iat; @@ -147,10 +148,9 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) = 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(); + 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(); @@ -171,14 +171,34 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) 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); -#else DPInputNlist nlist(nowned_atoms, ilist_data, numneigh_data, - firstneigh_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); #endif #ifdef __DPMD_HAS_NLIST_MAPPING if (use_mapping) @@ -200,13 +220,15 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) 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]); + force[3 * (nowned_atoms + iat) + 1], + force[3 * (nowned_atoms + iat) + 2]); } if (virial.size() != 9) @@ -229,7 +251,7 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) 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; } @@ -328,7 +350,9 @@ void ESolver_DP::cal_force(BaseCell& basecell, ModuleBase::matrix& force) force = dp_force; ModuleIO::print_force(GlobalV::ofs_running, static_cast(basecell), - "TOTAL-FORCE (eV/Angstrom)", force, false); + "TOTAL-FORCE (eV/Angstrom)", + force, + false); } void ESolver_DP::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) @@ -425,8 +449,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 8b8067552df..3deace46a24 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -139,8 +139,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 de52d69a84c..1ab131a0262 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" diff --git a/source/source_esolver/esolver_fp.cpp b/source/source_esolver/esolver_fp.cpp index 149f50dc8cb..644c1c8f5d0 100644 --- a/source/source_esolver/esolver_fp.cpp +++ b/source/source_esolver/esolver_fp.cpp @@ -1,27 +1,26 @@ #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 { @@ -31,13 +30,13 @@ 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); - delete this->pelec; + delete this->pelec; } void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) @@ -105,8 +104,14 @@ void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) 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); @@ -118,10 +123,18 @@ void ESolver_FP::before_all_runners(BaseCell& basecell, const Input_para& inp) 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, + 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); + this->inp_->symmetry_prec, + inp.nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SYMMETRY"); } @@ -132,7 +145,20 @@ 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,19 +166,26 @@ 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); //! 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; } @@ -168,18 +201,24 @@ 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, - PARAM.inp.test_charge, - PARAM.globalv.domag, - PARAM.globalv.domag_z, - GlobalV::ofs_warning}; + 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); //! 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) @@ -205,8 +244,7 @@ void ESolver_FP::before_scf(UnitCell& ucell, const int istep) // 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,10 +252,18 @@ 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, + 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); + this->inp_->symmetry_prec, + this->inp_->nspin, + this->inp_->calculation, + cal_symm_repr); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "SYMMETRY"); } @@ -230,15 +276,20 @@ 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, - 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); + 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); } //! Evaluate the vdW correction once for this ionic configuration. @@ -258,15 +309,26 @@ 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; } @@ -288,13 +350,13 @@ void ESolver_FP::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& if (GlobalV::MY_POOL == 0) { module_charge::write_rhog(PARAM.globalv.global_out_dir + this->inp_->suffix + "-CHARGE-DENSITY.restart", - PARAM.globalv.gamma_only_pw, - this->pw_rhod, - this->inp_->nspin, - ucell.GT, - this->chr.rhog_save, - pw_world, - &GlobalV::ofs_warning); + PARAM.globalv.gamma_only_pw, + this->pw_rhod, + this->inp_->nspin, + ucell.GT, + this->chr.rhog_save, + pw_world, + &GlobalV::ofs_warning); } if (XC_Functional::get_ked_flag()) @@ -308,14 +370,15 @@ void ESolver_FP::iter_finish(UnitCell& ucell, const int istep, int& iter, bool& } if (GlobalV::MY_POOL == 0) { - module_charge::write_rhog(PARAM.globalv.global_out_dir + this->inp_->suffix + "-TAU-DENSITY.restart", - PARAM.globalv.gamma_only_pw, - this->pw_rhod, - this->inp_->nspin, - ucell.GT, - kin_g.data(), - pw_world, - &GlobalV::ofs_warning); + module_charge::write_rhog(PARAM.globalv.global_out_dir + this->inp_->suffix + + "-TAU-DENSITY.restart", + PARAM.globalv.gamma_only_pw, + this->pw_rhod, + this->inp_->nspin, + ucell.GT, + kin_g.data(), + pw_world, + &GlobalV::ofs_warning); } } } @@ -332,7 +395,6 @@ void ESolver_FP::after_all_runners(BaseCell& basecell) 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 8d409b9d83b..5a6d24a7e3c 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_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_pw/module_pwdft/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/stru_fac.h" // structure factor +#include "source_pw/module_pwdft/vl_pw.h" // local pseudopotential #include #include @@ -48,7 +48,10 @@ class ESolver_FP : public 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_; diff --git a/source/source_esolver/esolver_gets.cpp b/source/source_esolver/esolver_gets.cpp index d0a2d727587..e5ba58eae55 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 diff --git a/source/source_esolver/esolver_ks.cpp b/source/source_esolver/esolver_ks.cpp index 9d12dfe07dd..50325f06aaa 100644 --- a/source/source_esolver/esolver_ks.cpp +++ b/source/source_esolver/esolver_ks.cpp @@ -1,29 +1,30 @@ #include "esolver_ks.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/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_pw/module_pwdft/setup_pwwfc.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_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() +{ +} ESolver_KS::~ESolver_KS() { @@ -38,7 +39,6 @@ ESolver_KS::~ESolver_KS() pw::teardown_pwwfc(this->pw_wfc); } - void ESolver_KS::before_all_runners(BaseCell& basecell, const Input_para& inp) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); @@ -73,23 +73,23 @@ 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); @@ -113,13 +113,17 @@ void ESolver_KS::before_all_runners(BaseCell& basecell, const Input_para& inp) 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 - + 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 { @@ -141,29 +145,40 @@ 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); + 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); + 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); + hsolver_error = hsolver::cal_hsolve_error(this->inp_->basis_type, policy, diag_ethr, this->inp_->nelec); } } } @@ -185,17 +200,17 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) bool conv_esolver = false; this->niter = this->maxniter; 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 <= this->maxniter) { - if(iter == this->maxniter) + if (iter == this->maxniter) { - this->scf_nmax_flag=true; + this->scf_nmax_flag = true; } // 3) initialization of SCF iterations @@ -230,8 +245,7 @@ void ESolver_KS::runner(BaseCell& basecell, const int istep) { 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; @@ -258,7 +272,7 @@ void ESolver_KS::before_scf(UnitCell& ucell, const int istep) 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); } @@ -272,16 +286,34 @@ 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) @@ -293,10 +325,10 @@ ESolver_KS::DensityStage ESolver_KS::density_stage(const int istep, const int it return DensityStage::standard; } -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) { - // 1.1) print out band gap + // 1.1) print out band gap if (!PARAM.globalv.two_fermi) { this->pelec->cal_bandgap(); @@ -320,9 +352,14 @@ 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 @@ -354,8 +391,14 @@ 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; @@ -387,46 +430,59 @@ 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 + // Iter finish ESolver_FP::iter_finish(ucell, istep, iter, conv_esolver); - // 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, 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, + drho, + dkin, + duration, + *this->inp_, + PARAM.globalv.two_fermi, + diag_ethr, + 0, + true, + this->ds_rms_); #ifdef __JSON // add Json of scf mag - Json::add_output_scf_mag(ucell.magnet.tot_mag, ucell.magnet.abs_mag, + 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); + 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) { 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); @@ -441,7 +497,6 @@ void ESolver_KS::after_scf(UnitCell& ucell, const int istep, const bool conv_eso // 4) write band information to band.txt ModuleIO::write_bands(*this->inp_, this->pelec->ekb, this->kv, GlobalV::ofs_running); - } void ESolver_KS::after_all_runners(BaseCell& basecell) diff --git a/source/source_esolver/esolver_ks.h b/source/source_esolver/esolver_ks.h index 29001c4180a..41d26634187 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 @@ -83,13 +83,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 2622e593074..8d370e6a354 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -49,7 +49,8 @@ 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 @@ -186,7 +187,12 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const 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. @@ -259,7 +265,14 @@ void ESolver_KS_LCAO::before_scf(UnitCell& ucell, const int istep, const } // 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_); @@ -474,7 +487,11 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const // call iter_init() of ESolver_KS ESolver_KS::iter_init(ucell, istep, iter); - module_charge::chgmixing_ks_lcao(iter, this->p_chgmix, *this->dftu_, this->dmat.dm->get_dmr_ptr(1)->get_nnr(), *this->inp_); + module_charge::chgmixing_ks_lcao(iter, + this->p_chgmix, + *this->dftu_, + this->dmat.dm->get_dmr_ptr(1)->get_nnr(), + *this->inp_); if (iter == 1) { @@ -490,7 +507,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; } } @@ -504,7 +522,8 @@ 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; @@ -513,12 +532,22 @@ void ESolver_KS_LCAO::iter_init(UnitCell& ucell, const int istep, const 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 @@ -611,13 +640,25 @@ void ESolver_KS_LCAO::hamilt2rho_single(UnitCell& ucell, int istep, int 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); + 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 @@ -639,11 +680,15 @@ 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 @@ -718,10 +763,7 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& // 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}; + const DFTU_BASE::OccmatStepInfo occmat_step{istep, iter, this->scf_thr, this->drho}; DFTU_BASE::write_latest_occmat(*this->dftu_, ucell, global_out_dir, @@ -745,7 +787,8 @@ void ESolver_KS_LCAO::iter_finish(UnitCell& ucell, const int istep, int& 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; } diff --git a/source/source_esolver/esolver_ks_lcao.h b/source/source_esolver/esolver_ks_lcao.h index 6fca9c417ec..b94422ef14b 100644 --- a/source/source_esolver/esolver_ks_lcao.h +++ b/source/source_esolver/esolver_ks_lcao.h @@ -52,7 +52,10 @@ class ESolver_KS_LCAO : public ESolver_KS 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; diff --git a/source/source_esolver/esolver_ks_lcao_tddft.cpp b/source/source_esolver/esolver_ks_lcao_tddft.cpp index ff2b1e06e40..475228b533b 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.cpp +++ b/source/source_esolver/esolver_ks_lcao_tddft.cpp @@ -160,10 +160,15 @@ 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) { @@ -187,7 +192,11 @@ 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(); @@ -202,7 +211,13 @@ 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++) { @@ -227,11 +242,19 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist const bool replay_restart = this->inp_->mdp.md_restart && !restart_done; if (this->inp_->out_vecpot && GlobalV::MY_RANK == 0 && !replay_restart) { - ModuleIO::write_td_vector_pot(PARAM.globalv.global_out_dir, this->totstep, td_field_manager_->A_right_ha()); + ModuleIO::write_td_vector_pot(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) @@ -262,7 +285,14 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist 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_); + 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, @@ -360,7 +390,10 @@ 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) @@ -390,25 +423,26 @@ void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const { 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); } @@ -452,15 +486,28 @@ void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell, const 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); + 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); } } @@ -497,8 +544,8 @@ 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; @@ -512,8 +559,8 @@ void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell, this->store_h_s_psi(ucell, istep, iter, force_save); // Calculate the RT-TDDFT energy-density matrix at the last converged substep when required by td_edm and the gauge - if (conv_esolver && estep == estep_max - 1 && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) && this->inp_->td_edm == 0 - && this->inp_->td_stype != 2) + if (conv_esolver && estep == estep_max - 1 && istep >= (this->inp_->init_wfc == "file" ? 0 : 1) + && this->inp_->td_edm == 0 && this->inp_->td_stype != 2) { if (use_tensor && use_lapack) { @@ -524,13 +571,19 @@ void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell, } 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; @@ -559,16 +612,18 @@ 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(); } @@ -628,15 +683,31 @@ 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 @@ -707,7 +778,12 @@ 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 b5fa43c01f9..79ee0c027f5 100644 --- a/source/source_esolver/esolver_ks_lcao_tddft.h +++ b/source/source_esolver/esolver_ks_lcao_tddft.h @@ -34,7 +34,10 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> protected: //! 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; @@ -46,7 +49,12 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR> 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; diff --git a/source/source_esolver/esolver_ks_lcaopw.cpp b/source/source_esolver/esolver_ks_lcaopw.cpp index 5c6ba6e9549..375d2e38979 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,256 +37,262 @@ 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, + ModuleIO::write_Vxc_LIP(this->inp_->nspin, PARAM.globalv.nlocal, GlobalV::DRANK, *this->stp.template get_psi_t(), @@ -308,11 +316,11 @@ namespace ModuleESolver , *this->exx_lip #endif - ); - } -#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 63dc3ed13c0..03d3199490d 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" diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index f1e6c5fa47c..35985c57285 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 @@ -212,7 +212,10 @@ 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) { @@ -239,7 +242,8 @@ 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(); } @@ -296,7 +300,8 @@ void ESolver_KS_PW::hamilt2rho_single(UnitCell& ucell, const int iste 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(); } @@ -345,7 +350,9 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int 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 @@ -397,10 +404,7 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int this->inp_->scf_nmax, this->inp_->out_occ_mat, this->inp_->dft_plus_u}; - const DFTU_BASE::OccmatStepInfo occmat_step{istep, - iter, - this->scf_thr, - this->drho}; + const DFTU_BASE::OccmatStepInfo occmat_step{istep, 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; @@ -408,11 +412,11 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int if (latest_ready) { DFTU_BASE::write_latest_occmat(*this->dftu_, - ucell, - global_out_dir, - occmat_step, - occmat_cfg, - DFTU_BASE::SOC_LAYOUT_PAULI); + ucell, + global_out_dir, + occmat_step, + occmat_cfg, + DFTU_BASE::SOC_LAYOUT_PAULI); } // append the current electronic-step section to occ_matg{#}.txt @@ -430,7 +434,14 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int DFTU_BASE::SOC_LAYOUT_PAULI); // the output quantities - ModuleIO::ctrl_iter_pw(istep, iter, conv_esolver, this->stp, this->kv, this->pw_wfc, *this->inp_, GlobalV::ofs_running); + ModuleIO::ctrl_iter_pw(istep, + iter, + conv_esolver, + this->stp, + this->kv, + this->pw_wfc, + *this->inp_, + GlobalV::ofs_running); } template diff --git a/source/source_esolver/esolver_ks_pw.h b/source/source_esolver/esolver_ks_pw.h index a03e73c943e..9286c9a7c73 100644 --- a/source/source_esolver/esolver_ks_pw.h +++ b/source/source_esolver/esolver_ks_pw.h @@ -49,7 +49,8 @@ class ESolver_KS_PW : public ESolver_KS virtual void allocate_hamilt(const UnitCell& ucell); - /** @brief Let RT-TDDFT bind its endpoint field before wavefunction initialization uses H; ordinary DFT does nothing. */ + /** @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 diff --git a/source/source_esolver/esolver_ks_pw_tddft.cpp b/source/source_esolver/esolver_ks_pw_tddft.cpp index 0008a72f3fe..95a0efdac67 100644 --- a/source/source_esolver/esolver_ks_pw_tddft.cpp +++ b/source/source_esolver/esolver_ks_pw_tddft.cpp @@ -143,7 +143,11 @@ void ESolver_KS_PW_TDDFT::prepare_init_hamilt(const UnitCell& ucell) { // The updated basis and endpoint A determine the required nonlocal projector range. const double q_unshifted = pw::td_momentum_bound(*this->pw_wfc, ucell.tpiba); - pw::ensure_td_vnl(ucell, q_unshifted, this->td_field_manager_->A_right_ha(), this->td_field_manager_->A_prop_ha(), &this->ppcell); + pw::ensure_td_vnl(ucell, + q_unshifted, + this->td_field_manager_->A_right_ha(), + this->td_field_manager_->A_prop_ha(), + &this->ppcell); elecstate::Potential& potential = *this->pelec->pot; const Real* veff = potential.template get_veff_smooth_data(); const Real* vofk = potential.template get_vofk_smooth_data(); @@ -225,7 +229,10 @@ 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) @@ -251,7 +258,8 @@ void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const in this->inp_->nbands, this->pelec->skip_weights); elecstate::calEBand(this->pelec->ekb, this->pelec->wg, this->pelec->f_en); - elecstate::ElecStatePW* estate = static_cast*>(this->pelec); + elecstate::ElecStatePW* estate + = static_cast*>(this->pelec); estate->psiToRho(*current); module_charge::symmetrize_rho(this->inp_->nspin, this->chr, this->pw_rhod, ucell.symm); } @@ -271,7 +279,8 @@ void ESolver_KS_PW_TDDFT::hamilt2rho_single(UnitCell& ucell, const in const Real* endpoint_vofk = potential.template get_vofk_smooth_data(); const ESolver_KS::DensityStage stage = this->density_stage(istep, iter); const bool corrector = stage != ESolver_KS::DensityStage::predictor; - const pw::TDPotentialView propagation = this->history_.prop_pot(potential, XC_Functional::get_ked_flag(), corrector); + const pw::TDPotentialView propagation + = this->history_.prop_pot(potential, XC_Functional::get_ked_flag(), corrector); ModuleBase::Vector3 momentum_shift(0.0, 0.0, 0.0); if (this->td_field_manager_->gauge() == 1) { @@ -321,8 +330,8 @@ void ESolver_KS_PW_TDDFT::after_scf(UnitCell& ucell, const int istep, if (!conv_esolver) { const int evolution_step = istep + 1; - const std::string message - = "Cannot propagate an unconverged electronic state. Electronic evolution step: " + std::to_string(evolution_step) + "."; + const std::string message = "Cannot propagate an unconverged electronic state. Electronic evolution step: " + + std::to_string(evolution_step) + "."; ModuleBase::WARNING_QUIT("ESolver_KS_PW_TDDFT", message); } if (istep == 0 && this->inp_->td_orthonormal == "none") @@ -426,7 +435,12 @@ void ESolver_KS_PW_TDDFT::print_eij(const int istep) #endif if (main_rank) { - const ModuleIO::EijOutputInfo info{this->inp_->td_print_eij, istep + 1, this->niter, physical_k + 1, nspin, spin + 1}; + const ModuleIO::EijOutputInfo info{this->inp_->td_print_eij, + istep + 1, + this->niter, + physical_k + 1, + nspin, + spin + 1}; ModuleIO::print_eij(eij.data(), nband, nband, info, log_); } } @@ -480,7 +494,8 @@ void ESolver_KS_PW_TDDFT::report_orth(const UnitCell& ucell, int iste const double delta_rho = rho_electrons - initial_rho_electrons_; const std::ios::fmtflags saved_flags = log_.flags(); const std::streamsize saved_precision = log_.precision(); - log_ << " PW RT-TDDFT conservation: evolution step " << evolution_step << ", " << stage << ", " << this->inp_->td_orthonormal << '\n'; + log_ << " PW RT-TDDFT conservation: evolution step " << evolution_step << ", " << stage << ", " + << this->inp_->td_orthonormal << '\n'; log_ << std::right << std::fixed << std::setprecision(10); ModuleBase::GlobalFunc::OUT(log_, "Npsi", electrons); ModuleBase::GlobalFunc::OUT(log_, "Nrho", rho_electrons); diff --git a/source/source_esolver/esolver_lj.cpp b/source/source_esolver/esolver_lj.cpp index e30eef32e54..e84789de4b1 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 @@ -34,7 +34,10 @@ 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; } @@ -82,35 +85,37 @@ void ESolver_LJ::runner(BaseCell& cell, const int istep) 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); + 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); + 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; } diff --git a/source/source_esolver/esolver_lj.h b/source/source_esolver/esolver_lj.h index 8f8ca3056b5..a816c3baad3 100644 --- a/source/source_esolver/esolver_lj.h +++ b/source/source_esolver/esolver_lj.h @@ -31,9 +31,9 @@ class ESolver_LJ : public ESolver 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. diff --git a/source/source_esolver/esolver_lr_cfg.cpp b/source/source_esolver/esolver_lr_cfg.cpp index 2e07da67927..22d433e782c 100644 --- a/source/source_esolver/esolver_lr_cfg.cpp +++ b/source/source_esolver/esolver_lr_cfg.cpp @@ -1,18 +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 +template void ModuleESolver::ESolver_LR::set_dimension() { this->nspin = this->inp_->nspin; @@ -24,16 +25,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 +49,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,7 +64,7 @@ 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; @@ -71,7 +78,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 +92,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,46 +115,47 @@ void ModuleESolver::ESolver_LR::set_dimension() this->ofs_running_ << "number of excited states to be solved: " << this->nstates << std::endl; } -template +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 +template void ModuleESolver::ESolver_LR::init_pot(const Charge& chg_gs) { this->pot.assign(nspin, nullptr); @@ -154,14 +164,27 @@ void ModuleESolver::ESolver_LR::init_pot(const Charge& chg_gs) 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); + 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 9149c00e7c7..c676ca9e5d9 100644 --- a/source/source_esolver/esolver_lr_grad.cpp +++ b/source/source_esolver/esolver_lr_grad.cpp @@ -1,23 +1,23 @@ +#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 +template void ModuleESolver::ESolver_LR::init_pot_groundstate(const Charge& chg_gs) { ModuleBase::TITLE("ESolver_LR", "init_pot_gs"); @@ -25,7 +25,7 @@ void ModuleESolver::ESolver_LR::init_pot_groundstate(const Charge& chg_gs 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 @@ -36,42 +36,61 @@ void ModuleESolver::ESolver_LR::init_pot_groundstate(const Charge& chg_gs } 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 +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"); @@ -84,19 +103,26 @@ 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(); 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) @@ -124,24 +150,48 @@ std::vector ModuleESolver::ESolver_LR::cal_force(cons return this->cal_force_Xz(ispin, Xz, omega, ist_begin); } -template +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 +template std::vector ModuleESolver::ESolver_LR::cal_force_Xz(const int ispin, - 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_Xz"); const int nst = static_cast(omega.size()); @@ -149,12 +199,26 @@ 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); @@ -162,7 +226,7 @@ std::vector ModuleESolver::ESolver_LR::cal_force_Xz(c return forces; } -template +template void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispin, std::ofstream& ofs) { const std::vector forces = this->cal_force(ispin); @@ -174,9 +238,7 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi // 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; - }), + [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 @@ -188,9 +250,8 @@ 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) { @@ -207,7 +268,7 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi double lo = omega[group.front()]; double hi = omega[group.front()]; double sum = 0.0; - for (const int ist : group) + for (const int ist: group) { lo = std::min(lo, omega[ist]); hi = std::max(hi, omega[ist]); @@ -220,10 +281,12 @@ void ModuleESolver::ESolver_LR::cal_force_and_grad_matrix_(const int ispi } } -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"); @@ -269,14 +332,13 @@ ModuleESolver::ESolver_LR::cal_grad_matrix_degenerate(const int ispin, // one $\Omega$ for every combination: the members share it up to `omega_spread`, and the mean // is the neutral choice for a vector that belongs to no single member double omega_sum = 0.0; - for (const double omega : omega_member) + for (const double omega: omega_member) { 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,36 +347,33 @@ 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) { - LR::combine_normalized( - Xz.template data() + static_cast(pairs[ip].first) * nloc_g, - Xz.template data() + static_cast(pairs[ip].second) * nloc_g, - static_cast(nloc_g), - Xp.template data() + static_cast(ip) * nloc_g); + LR::combine_normalized(Xz.template data() + static_cast(pairs[ip].first) * nloc_g, + Xz.template data() + static_cast(pairs[ip].second) * nloc_g, + static_cast(nloc_g), + Xp.template data() + static_cast(ip) * nloc_g); } 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); + 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 +397,11 @@ 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,12 +409,26 @@ 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); @@ -361,7 +436,7 @@ std::vector ModuleESolver::ESolver_LR::cal_force_open return forces; } -template +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); @@ -373,21 +448,39 @@ module_dm::DensityMatrix ModuleESolver::ESolver_LR::cal_dm_gs( // 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 + 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 +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 ); @@ -395,7 +488,7 @@ void ModuleESolver::ESolver_LR::test_force() // 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) @@ -414,13 +507,20 @@ void ModuleESolver::ESolver_LR::test_force() /// ======================================= 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 a33589d4955..6819ed8cb20 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,53 +23,60 @@ 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<> +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<> +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<> +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"); @@ -144,15 +151,15 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons 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 +167,25 @@ 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,19 +195,23 @@ 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->paraC_.get_col_size(), - this->paraC_.get_row_size(), - this->kv.ngk, - true)); + 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)); #endif @@ -213,13 +232,13 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons // 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); + || (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(); @@ -229,7 +248,7 @@ void ModuleESolver::ESolver_LR::initialize_from_ks_(UnitCell& ucell, cons 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_owned_ = true; // the position-dependent `cal_exx_ions` is left to `refresh_from_ks_` } } #endif @@ -252,20 +271,29 @@ 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); @@ -281,28 +309,29 @@ 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_", - "the ground-state spin population changed between ionic steps, but nocc/nvirt and" - " the distributions built from them were fixed at the first step."); + "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,7 +356,6 @@ void ModuleESolver::ESolver_LR::refresh_from_ks_(UnitCell& ucell) #endif } - template void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell, const Input_para& inp) { @@ -345,17 +373,38 @@ 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, + 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); + 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,8 +414,13 @@ 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_); @@ -397,7 +451,6 @@ void ModuleESolver::ESolver_LR::initialize_from_unitcell_(UnitCell& ucell true)); this->read_ks_wfc(); - if (nspin == 2) { // Complete file populations were read before selecting the occupied window. @@ -410,25 +463,29 @@ 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, - this->pw_rho->ny, - this->pw_rho->nz, - this->pw_rho->nplane, - this->pw_rho->nrxx, - pw_big->nbz, - pw_big->bz, - GlobalV::NPROC); + this->pw_rho->ny, + this->pw_rho->nz, + this->pw_rho->nplane, + this->pw_rho->nrxx, + pw_big->nbz, + pw_big->bz, + GlobalV::NPROC); Charge chg_gs; if (this->inp_->ri_hartree_benchmark == "none") { @@ -439,38 +496,36 @@ 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_, - this->inp_->out_level, - orb.get_rcutmax_Phi(), - ucell.infoNL->get_rcutmax_Beta(), - PARAM.globalv.gamma_only_local); + 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( - 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()); // if EXX from scratch, init 2-center integral and calculate Cs, Vs // when: @@ -488,12 +543,12 @@ 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 be778ecdf20..4b04f175914 100644 --- a/source/source_esolver/esolver_lr_lcao_bse.cpp +++ b/source/source_esolver/esolver_lr_lcao_bse.cpp @@ -1,17 +1,19 @@ -#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 { @@ -24,7 +26,7 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para 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,8 @@ 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,8 +45,13 @@ 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_); @@ -70,33 +77,34 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para 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_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->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; @@ -112,44 +120,43 @@ void ESolver_BSE::before_all_runners(BaseCell& basecell, const Input_para 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->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->nk, - this->kRlist, - this->nocc[0], - this->nvirt[0], - *this->psi_ks_global, - this->inp_->bse_q_approx_mode, - this->inp_->bse_q_approx_threshold, - this->inp_->out_ri_cv, - this->out_dir, - GlobalV::MY_RANK, - GlobalV::NPROC); + this->nk, + this->kRlist, + this->nocc[0], + this->nvirt[0], + *this->psi_ks_global, + this->inp_->bse_q_approx_mode, + this->inp_->bse_q_approx_threshold, + this->inp_->out_ri_cv, + this->out_dir, + GlobalV::MY_RANK, + GlobalV::NPROC); if (!this->inp_->bse_ri_hartree && this->inp_->ri_hartree_benchmark == "none") { @@ -169,17 +176,20 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) 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,21 +202,33 @@ 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); + 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, @@ -230,10 +252,10 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) 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); }; @@ -307,9 +329,9 @@ 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 - { - if (GlobalV::MY_RANK == 0) { + auto read_tda_states = [&](const std::string& label, Real* e, T* v, const int& dim, const int& nst) -> void { + 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)); } @@ -319,19 +341,20 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) 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 - { - 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)); + 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)); } #ifdef __MPI 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") @@ -356,15 +379,17 @@ void ESolver_BSE::runner(BaseCell& basecell, const int istep) 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) { + 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; } @@ -389,7 +414,7 @@ void ESolver_BSE::after_all_runners(BaseCell& 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::set benchmarks = {"abacus-librpa", "abacus", "none"}; if (benchmarks.find(this->inp_->ri_hartree_benchmark) == benchmarks.end()) { return; @@ -400,13 +425,26 @@ 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"); @@ -421,9 +459,8 @@ 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"); + ModuleBase::WARNING_QUIT("ESolver_BSE", + "conditional exciton density only supports exciton_plot_format = slice"); } if (this->inp_->exciton_fixed_coordinate.size() != 6) { @@ -437,16 +474,20 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) 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_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_plane, - this->inp_->exciton_slice_pos, - this->inp_->exciton_slice_npoints, - this->inp_->exciton_slice_range, "hole"); + 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_plane, + this->inp_->exciton_slice_pos, + this->inp_->exciton_slice_npoints, + this->inp_->exciton_slice_range, + "hole"); } else if (plot_type == "average") { @@ -459,16 +500,18 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) } if (write_slice) { - 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", - 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, + "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", + this->inp_->exciton_slice_plane, + this->inp_->exciton_slice_pos, + this->inp_->exciton_slice_npoints, + this->inp_->exciton_slice_range); } } else @@ -504,39 +547,65 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) 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 +613,30 @@ 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 +644,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 +659,9 @@ void ESolver_BSE::after_all_runners(BaseCell& basecell) ModuleBase::timer::end("ESolver_BSE", "after_all_runners"); } -template +template void ESolver_BSE::ipa_solver() -{// if ipa, assign X as identity matrix directly +{ // 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 +682,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,14 +697,15 @@ 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 +template void ESolver_BSE::lri_init() { ModuleBase::TITLE("ESolver_BSE", "LRI init"); @@ -633,21 +718,21 @@ 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); @@ -657,7 +742,7 @@ void ESolver_BSE::lri_init() ModuleBase::TITLE("ESolver_BSE", "Finish LRI init"); } -template +template void ESolver_BSE::read_ks_wfc() { assert(this->psi_ks != nullptr); @@ -672,57 +757,95 @@ void ESolver_BSE::read_ks_wfc() 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)); + 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,33 +859,41 @@ void ESolver_BSE::read_ks_wfc() this->eig_ks = std::move(this->pelec->ekb); } -template +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 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 +template void ESolver_BSE::allocate_eigen_infos() { ModuleBase::TITLE("ESolver_BSE", "allocate_eigen_infos"); @@ -770,9 +901,13 @@ void 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)); @@ -782,25 +917,36 @@ void ESolver_BSE::allocate_eigen_infos() : 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") { + 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") { + 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 50aa82db1dc..d91df95c45c 100644 --- a/source/source_esolver/esolver_lr_lcao_bse.h +++ b/source/source_esolver/esolver_lr_lcao_bse.h @@ -6,54 +6,57 @@ 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 94427875726..8f158869ae9 100644 --- a/source/source_esolver/esolver_lr_lcao_tddft.cpp +++ b/source/source_esolver/esolver_lr_lcao_tddft.cpp @@ -1,16 +1,18 @@ // 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 @@ -18,10 +20,11 @@ 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) + 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); @@ -55,7 +58,7 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste 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,14 +66,14 @@ 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 @@ -85,16 +88,15 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste 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 { + 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)); @@ -105,11 +107,17 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste // allocate and initialize A matrix and density matrix if (openshell) { - for (int is : {0, 1}) + 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); + 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); } } @@ -133,76 +141,112 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste 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); } + 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) + 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->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); } + 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 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) { @@ -211,7 +255,14 @@ void ModuleESolver::ESolver_LR::runner(BaseCell& basecell, const int iste 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); } + 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_) @@ -237,15 +288,15 @@ 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"); @@ -259,18 +310,34 @@ void ModuleESolver::ESolver_LR::after_all_runners(BaseCell& 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_); @@ -278,7 +345,7 @@ void ModuleESolver::ESolver_LR::after_all_runners(BaseCell& basecell) } 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_); @@ -288,30 +355,43 @@ void ModuleESolver::ESolver_LR::after_all_runners(BaseCell& basecell) 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) { @@ -320,28 +400,48 @@ void ModuleESolver::ESolver_LR::after_all_runners(BaseCell& basecell) } 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 77a2adbc75d..4fdbe4fe505 100644 --- a/source/source_esolver/esolver_lr_lcao_tddft.h +++ b/source/source_esolver/esolver_lr_lcao_tddft.h @@ -1,29 +1,27 @@ #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 { @@ -32,357 +30,363 @@ struct GradientInputs; } namespace ModuleESolver { - struct LRRuntime +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 +{ + public: + ESolver_LR(const Input_para& inp, const std::string& in_dir, const std::string& out_dir, const LRRuntime& runtime); + ~ESolver_LR() { - 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 + } + + /// 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 { - 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->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 *this->locpp_ptr_; + return static_cast(states.size()); } - /// 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 + /// $\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 ff0492ddf61..1c2d1253075 100644 --- a/source/source_esolver/esolver_lr_orb.cpp +++ b/source/source_esolver/esolver_lr_orb.cpp @@ -1,15 +1,16 @@ // 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 +template void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbitals& pmat, const int nbands_in) { #ifdef __MPI @@ -39,7 +40,7 @@ void ModuleESolver::ESolver_LR::set_parallel_orbitals_band(Parallel_Orbit #endif } -template +template void ModuleESolver::ESolver_LR::setup_eigenvectors_X() { ModuleBase::TITLE("ESolver_LR", "setup_eigenvectors_X"); @@ -47,19 +48,24 @@ void ModuleESolver::ESolver_LR::setup_eigenvectors_X() // 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 })); + this->X.resize(openshell ? 1 : nspin, LR_Util::newTensor({nstates, nloc_per_state})); for (auto& x: X) { x.zero(); @@ -72,11 +78,11 @@ void ModuleESolver::ESolver_LR::setup_eigenvectors_X() } } -template +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]; @@ -84,7 +90,7 @@ void ModuleESolver::ESolver_LR::set_X_initial_guess() 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 + 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)) { @@ -104,8 +110,8 @@ void ModuleESolver::ESolver_LR::set_X_initial_guess() /// global index map between (i,c) and ix ModuleBase::matrix ioiv2ix; std::vector> ix2ioiv; - std::pair>> indexmap = - LR_Util::set_ix_map_diagonal(ix_mode, no, nv); + std::pair>> indexmap + = LR_Util::set_ix_map_diagonal(ix_mode, no, nv); ioiv2ix = std::move(std::get<0>(indexmap)); ix2ioiv = std::move(std::get<1>(indexmap)); @@ -113,34 +119,38 @@ 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 +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,36 +160,49 @@ 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_, - this->eig_ks_all, - this->wg_ks_all, - this->kv.ik2iktot, - this->kv.get_nkstot(), - this->inp_->nspin, - this->inp_->init_wfc_file_format == "binary", - /*skip_bands=*/0)) + 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, + this->kv.get_nkstot(), + this->inp_->nspin, + this->inp_->init_wfc_file_format == "binary", + /*skip_bands=*/0)) { ModuleBase::WARNING_QUIT("ESolver_LR", "read all ground-state wavefunctions for force calculation failed."); } @@ -187,7 +210,7 @@ void ModuleESolver::ESolver_LR::read_ks_wfc() } } -template +template void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) { ModuleBase::TITLE("ESolver_LR", "fill_z_window_"); @@ -203,7 +226,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 +236,26 @@ 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,13 +264,17 @@ 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)); #endif @@ -252,9 +287,17 @@ 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) { @@ -267,8 +310,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 +321,8 @@ 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,7 +330,7 @@ void ModuleESolver::ESolver_LR::fill_z_window_(const int* desc_src) } } -template +template void ModuleESolver::ESolver_LR::read_ks_chg(Charge& chg_gs) { chg_gs.set_rhopw(this->pw_rho); @@ -307,12 +350,12 @@ void ModuleESolver::ESolver_LR::read_ks_chg(Charge& chg_gs) } 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; + 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 0bcc4d2ae4c..b6477a19b20 100644 --- a/source/source_esolver/esolver_lr_rlx.cpp +++ b/source/source_esolver/esolver_lr_rlx.cpp @@ -1,23 +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 +template void ModuleESolver::ESolver_LR::setup_relax_target_() { this->excited_relax_ = (this->inp_->calculation == "relax"); @@ -31,14 +31,14 @@ void ModuleESolver::ESolver_LR::setup_relax_target_() 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."); + "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)."); + "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 @@ -53,8 +53,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; } @@ -66,27 +67,27 @@ void ModuleESolver::ESolver_LR::setup_relax_target_() 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."); + "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."); + "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 +template void ModuleESolver::ESolver_LR::follow_target_state_(std::ofstream& ofs) { ModuleBase::timer::start("ESolver_LR", "follow_target_state_"); @@ -99,19 +100,38 @@ void ModuleESolver::ESolver_LR::follow_target_state_(std::ofstream& ofs) 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 +template double ModuleESolver::ESolver_LR::cal_energy() { // Outside a relaxation nothing consumes this, and returning a non-zero value would change @@ -127,19 +147,19 @@ double ModuleESolver::ESolver_LR::cal_energy() return this->etot_gs_ + this->target_omega_(); } -template +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); 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."); + "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 @@ -150,36 +170,36 @@ void ModuleESolver::ESolver_LR::cal_force(BaseCell& basecell, ModuleBase: ModuleIO::print_force(this->ofs_running_, ucell, "EXCITED-STATE TOTAL-FORCE (eV/Angstrom)", force, false); } -template +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)."); + "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, - Xz.template data() + static_cast(k) * nloc_g); + std::copy(one.template data(), + one.template data() + nloc_g, + Xz.template data() + static_cast(k) * nloc_g); } return Xz; } -template +template void ModuleESolver::ESolver_LR::resolve_target_multiplet_() { // Keyed on `target_state_`, not on `lr_target_state`: the overlap tracking re-chooses the @@ -196,9 +216,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,7 +246,7 @@ void ModuleESolver::ESolver_LR::resolve_target_multiplet_() } } -template +template double ModuleESolver::ESolver_LR::target_omega_() const { if (this->target_group_.empty()) @@ -243,7 +262,7 @@ double ModuleESolver::ESolver_LR::target_omega_() const return sum / static_cast(this->target_group_.size()); } -template +template ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::ofstream& ofs) { this->resolve_target_multiplet_(); @@ -263,11 +282,11 @@ 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_) + for (const int ist: this->target_group_) { if (ist != this->target_state_) { @@ -285,9 +304,9 @@ ModuleBase::matrix ModuleESolver::ESolver_LR::cal_lr_force_relax_(std::of return this->cal_jt_force_(forces, ofs); } -template -ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_( - const std::vector& diag, std::ofstream& ofs) +template +ModuleBase::matrix ModuleESolver::ESolver_LR::cal_jt_force_(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 @@ -330,8 +349,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 +361,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 +397,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 2f95725139b..e9f7c6a40a5 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" @@ -41,8 +42,7 @@ void ESolver_NEP::before_all_runners(BaseCell& basecell, const Input_para& inp) { 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 @@ -96,14 +96,14 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) 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(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)]; + : 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."); @@ -151,14 +151,15 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) 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]); + 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 @@ -174,7 +175,7 @@ void ESolver_NEP::runner(BaseCell& basecell, const int istep) 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; } @@ -385,8 +386,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 e7d56562d0e..a2f216904bc 100644 --- a/source/source_esolver/esolver_nep.h +++ b/source/source_esolver/esolver_nep.h @@ -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 74374e45934..abc7f80c140 100644 --- a/source/source_esolver/esolver_of.cpp +++ b/source/source_esolver/esolver_of.cpp @@ -1,20 +1,19 @@ #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 { @@ -62,7 +61,7 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) 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) { @@ -82,22 +81,31 @@ void ESolver_OF::before_all_runners(BaseCell& basecell, const Input_para& inp) 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 + 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.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() @@ -142,7 +150,7 @@ void ESolver_OF::runner(BaseCell& basecell, const int istep) 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 +163,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)) { @@ -209,8 +216,7 @@ void ESolver_OF::before_opt(const int istep, UnitCell& ucell) // 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,15 +225,21 @@ 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") @@ -403,10 +415,16 @@ bool ESolver_OF::check_exit(bool& conv_esolver) } conv_esolver = (this->of_conv_ == "energy" && energyConv) || (this->of_conv_ == "potential" && potConv) - || (this->of_conv_ == "both" && potConv && energyConv); + || (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_) { @@ -466,10 +484,10 @@ void ESolver_OF::after_opt(const int istep, UnitCell& ucell, const bool conv_eso { 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->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) { @@ -511,13 +529,11 @@ double ESolver_OF::cal_energy() 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; @@ -537,13 +553,24 @@ void ESolver_OF::cal_force(BaseCell& basecell, ModuleBase::matrix& force) 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, + 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); + ucell, + force, + this->get_vdw_result(), + *pelec, + this->pw_rho, + &ucell.symm, + &sf, + this->solvent, + nullptr, + &this->locpp); } /** @@ -558,12 +585,25 @@ void ESolver_OF::cal_stress(BaseCell& basecell, ModuleBase::matrix& stress) 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 401ec38f843..344ab3d4b16 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 @@ -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> precip_dir_storage_; std::vector*> precip_dir_; // row views; used when of_full_pw=false. - std::vector theta_; // step length + std::vector theta_; // step length std::vector pdEdphi_storage_; 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; diff --git a/source/source_esolver/esolver_of_tddft.cpp b/source/source_esolver/esolver_of_tddft.cpp index 3c068b2c77c..22319fe432e 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,7 +19,7 @@ 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() @@ -27,7 +27,6 @@ ESolver_OF_TDDFT::~ESolver_OF_TDDFT() delete this->evolve_ofdft; } - void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) { basecell.require_kind(BaseCell::Kind::unitcell, __FUNCTION__); @@ -38,7 +37,7 @@ void ESolver_OF_TDDFT::runner(BaseCell& basecell, const int istep) 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 +46,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 +58,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)) { @@ -84,11 +82,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,10 +95,10 @@ 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 { @@ -112,10 +110,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_tool.cpp b/source/source_esolver/esolver_of_tool.cpp index 375277bc6f4..e1c333ddfbc 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 { @@ -77,11 +76,7 @@ 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]; for (int is = 0; is < this->inp_->nspin; ++is) @@ -95,15 +90,15 @@ 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() @@ -162,9 +157,7 @@ void ESolver_OF::cal_potential(double* ptemp_phi, double* rdLdphi, UnitCell& uce this->pelec->pot->update_from_charge(this->ptemp_rho_, &ucell); 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, + 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) { @@ -196,9 +189,7 @@ void ESolver_OF::cal_dEdtheta(double** ptemp_phi, Charge* temp_rho, UnitCell& uc this->pelec->pot->update_from_charge(temp_rho, &ucell); ModuleBase::matrix& vr_eff = this->pelec->pot->get_eff_v(); - this->kedf_manager_->get_potential(temp_rho->rho, - ptemp_phi, - this->pw_rho, + 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) { @@ -395,11 +386,11 @@ void ESolver_OF::test_direction(double* dEdtheta, double** ptemp_phi, UnitCell& 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 840dd1175bb..9614c463358 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 @@ -111,7 +111,8 @@ void ESolver_SDFT_PW::before_scf(UnitCell& ucell, const int istep) &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) + 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); } @@ -226,8 +227,11 @@ void ESolver_SDFT_PW::cal_force(BaseCell& basecell, ModuleBase::matri Sto_Forces ff(ucell.nat); - ff.cal_stoforce(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad, - force, + 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, @@ -248,9 +252,12 @@ void ESolver_SDFT_PW::cal_stress(BaseCell& basecell, ModuleBase::matr 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, + 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, diff --git a/source/source_esolver/esolver_sdft_pw.h b/source/source_esolver/esolver_sdft_pw.h index 2a5c4965c3a..cc0182e72df 100644 --- a/source/source_esolver/esolver_sdft_pw.h +++ b/source/source_esolver/esolver_sdft_pw.h @@ -2,8 +2,8 @@ #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" diff --git a/source/source_esolver/lcao_others.cpp b/source/source_esolver/lcao_others.cpp index 1c1e8675773..473af4d684b 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 @@ -84,7 +84,12 @@ void ESolver_KS_LCAO::others(BaseCell& basecell, const int istep) 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, @@ -136,8 +141,7 @@ 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; + 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, @@ -187,7 +191,14 @@ 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,12 +207,8 @@ 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 { diff --git a/source/source_esolver/test/esolver_dp_test.cpp b/source/source_esolver/test/esolver_dp_test.cpp index 4bd3c445015..68005e524bf 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 ***********************************************/ diff --git a/source/source_esolver/test/for_test.h b/source/source_esolver/test/for_test.h index dd7448b9569..03be6589e52 100644 --- a/source/source_esolver/test/for_test.h +++ b/source/source_esolver/test/for_test.h @@ -69,8 +69,16 @@ pseudo::pseudo() pseudo::~pseudo() { } -SepPot::SepPot(){} -SepPot::~SepPot(){} -Sep_Cell::Sep_Cell() noexcept {} -Sep_Cell::~Sep_Cell() noexcept {} +SepPot::SepPot() +{ +} +SepPot::~SepPot() +{ +} +Sep_Cell::Sep_Cell() noexcept +{ +} +Sep_Cell::~Sep_Cell() noexcept +{ +} #endif