|
28 | 28 | // gradient |
29 | 29 | #include "source_lcao/module_lr/Grad/multipliers/zeq_solver.h" |
30 | 30 |
|
| 31 | +#ifdef __EXX |
| 32 | +namespace |
| 33 | +{ |
| 34 | + /// Screening of the Coulomb operator that `Exx_LRI` is built with: `hse` is erfc-screened, |
| 35 | + /// `hf` and `pbe0` are bare. |
| 36 | + /// |
| 37 | + /// One `Exx_LRI` carries ONE screening, and it may be needed for two different reasons: the |
| 38 | + /// LR kernel (when `xc_kernel` is a hybrid) and the ground-state force (when |
| 39 | + /// `dft_functional` is a hybrid). Keying the choice off `xc_kernel` alone -- which is what |
| 40 | + /// this used to do -- silently produced *unscreened* exchange whenever the object existed |
| 41 | + /// only for the force, e.g. `dft_functional hse` with `xc_kernel lda` or `rpa`. |
| 42 | + Conv_Coulomb_Pot_K::Ccp_Type exx_ccp_type(const std::string& name) |
| 43 | + { |
| 44 | + return (name == "hse") ? Conv_Coulomb_Pot_K::Ccp_Type::Erfc |
| 45 | + : Conv_Coulomb_Pot_K::Ccp_Type::Hf; |
| 46 | + } |
| 47 | + |
| 48 | + /// Which functional the single `Exx_LRI` must follow. Prefer the LR kernel, since that one |
| 49 | + /// enters the eigenproblem; fall back to the ground-state functional, which is the only |
| 50 | + /// reason the object exists when the kernel is local. |
| 51 | + std::string exx_source(const std::string& xc_kernel, const std::string& dft_functional) |
| 52 | + { |
| 53 | + const bool k = LR::exx_kernel_list().count(xc_kernel) > 0; |
| 54 | + const bool g = LR::exx_kernel_list().count(dft_functional) > 0; |
| 55 | + if (k && g && xc_kernel != dft_functional) |
| 56 | + { |
| 57 | + GlobalV::ofs_running << " WARNING: xc_kernel (" << xc_kernel << ") and dft_functional (" |
| 58 | + << dft_functional << ") are two DIFFERENT hybrids. A single Exx_LRI carries one" |
| 59 | + " screening, so only " << xc_kernel << "'s is used; the ground-state EXX force" |
| 60 | + " will be inconsistent." << std::endl; |
| 61 | + } |
| 62 | + return k ? xc_kernel : dft_functional; |
| 63 | + } |
| 64 | +} |
| 65 | +#endif |
| 66 | + |
31 | 67 | #ifdef __EXX |
32 | 68 | template<> |
33 | 69 | void ModuleESolver::ESolver_LR<double>::move_exx_lri(std::shared_ptr<Exx_LRI<double>>& exx_ks) |
@@ -349,9 +385,7 @@ void ModuleESolver::ESolver_LR<T, TR>::initialize_from_ks_(ModuleESolver::ESolve |
349 | 385 | this->move_exx_lri(ks_sol.exx_nao.exc->exx_ptr); |
350 | 386 | } else // construct C, V from scratch |
351 | 387 | { |
352 | | - // set ccp_type according to the xc_kernel |
353 | | - if (xc_kernel == "hf" || xc_kernel == "pbe0") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; } |
354 | | - else if (xc_kernel == "hse") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Erfc; } |
| 388 | + exx_info.info_global.ccp_type = exx_ccp_type(exx_source(xc_kernel, dft_functional)); |
355 | 389 | exx_info.sync_from_global(); |
356 | 390 | this->exx_lri = std::make_shared<Exx_LRI<T>>(exx_info.info_ri); |
357 | 391 | this->exx_lri->init(MPI_COMM_WORLD, ucell,this->kv, ks_sol.orb_); |
@@ -495,9 +529,8 @@ void ModuleESolver::ESolver_LR<T, TR>::initialize_from_unitcell_(UnitCell& ucell |
495 | 529 | if (((exx_kernel_list().count(xc_kernel)) && this->input.lr_solver != "spectrum") |
496 | 530 | || (PARAM.inp.cal_force && (exx_kernel_list().count(PARAM.inp.dft_functional) ))) |
497 | 531 | { |
498 | | - // set ccp_type according to the xc_kernel |
499 | | - if (xc_kernel == "hf") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; } |
500 | | - else if (xc_kernel == "hse") { exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Erfc; } |
| 532 | + exx_info.info_global.ccp_type = |
| 533 | + exx_ccp_type(exx_source(xc_kernel, LR_Util::tolower(PARAM.inp.dft_functional))); |
501 | 534 | this->exx_lri = std::make_shared<Exx_LRI<T>>(exx_info.info_ri); |
502 | 535 | this->exx_lri->init(MPI_COMM_WORLD, ucell,this->kv, orb); |
503 | 536 | this->exx_lri->cal_exx_ions(ucell,input.out_ri_cv); |
|
0 commit comments