Skip to content

Commit 073ab9b

Browse files
committed
small fixes
1 parent 4b8a763 commit 073ab9b

5 files changed

Lines changed: 61 additions & 17 deletions

File tree

source/source_esolver/esolver_lr_lcao_tddft.cpp

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,42 @@
2828
// gradient
2929
#include "source_lcao/module_lr/Grad/multipliers/zeq_solver.h"
3030

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+
3167
#ifdef __EXX
3268
template<>
3369
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
349385
this->move_exx_lri(ks_sol.exx_nao.exc->exx_ptr);
350386
} else // construct C, V from scratch
351387
{
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));
355389
exx_info.sync_from_global();
356390
this->exx_lri = std::make_shared<Exx_LRI<T>>(exx_info.info_ri);
357391
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
495529
if (((exx_kernel_list().count(xc_kernel)) && this->input.lr_solver != "spectrum")
496530
|| (PARAM.inp.cal_force && (exx_kernel_list().count(PARAM.inp.dft_functional) )))
497531
{
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)));
501534
this->exx_lri = std::make_shared<Exx_LRI<T>>(exx_info.info_ri);
502535
this->exx_lri->init(MPI_COMM_WORLD, ucell,this->kv, orb);
503536
this->exx_lri->cal_exx_ions(ucell,input.out_ri_cv);

source/source_lcao/module_lr/Grad/force/cal_hs_grad.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include <cassert>
23
#include "source_cell/module_neighbor/sltk_grid_driver.h"
34
#include "source_cell/unitcell.h"
45
#include "source_basis/module_ao/parallel_orbitals.h"
@@ -55,14 +56,7 @@ hamilt::HContainer<TR> build_hcontainer_local_op(const UnitCell& ucell, const Gr
5556
return hcontainer;
5657
}
5758

58-
// ModuleBase::Vector3<double> operator*(const ModuleBase::Vector3<double>& row_vec, ModuleBase::Matrix3& mat3)
59-
// {
60-
// return ModuleBase::Vector3<double>(row_vec.x * mat3.e11 + row_vec.y * mat3.e21 + row_vec.z * mat3.e31,
61-
// row_vec.x * mat3.e12 + row_vec.y * mat3.e22 + row_vec.z * mat3.e32,
62-
// row_vec.x * mat3.e13 + row_vec.y * mat3.e23 + row_vec.z * mat3.e33);
63-
// }
64-
65-
59+
/// @brief Calculate <dPhi|phi> or <dPhi|T|phi> by 2-center integration
6660
inline std::vector<hamilt::HContainer<double>> cal_hs_grad(const char job,
6761
const UnitCell& ucell,
6862
const Parallel_Orbitals& pv,
@@ -107,9 +101,17 @@ inline std::vector<hamilt::HContainer<double>> cal_hs_grad(const char job,
107101

108102
for (int iR = 0;iR < nR;++iR)
109103
{
110-
ModuleBase::Vector3<double> R(*it++, *it++, *it++); // int to double
104+
// Read the three components in separate statements. The order in which function
105+
// arguments are evaluated is UNSPECIFIED in C++, so `Vector3<double>(*it++, *it++, *it++)`
106+
// may store the R triple permuted and silently corrupt periodic systems.
107+
const int Rx = *it++;
108+
const int Ry = *it++;
109+
const int Rz = *it++;
110+
const ModuleBase::Vector3<double> R(Rx, Ry, Rz); // int to double
111111
ModuleBase::Vector3<double> relative_position = (tau1 - tau0 + R * ucell.latvec) * ucell.lat0;
112112
hamilt::BaseMatrix<double>* dHS_block = dHS[ixyz].find_matrix(iat0, iat1, R.x, R.y, R.z);
113+
// `ijr_info` came from this very container, so a miss means the indices are wrong.
114+
assert(dHS_block != nullptr);
113115

114116
// OMP can be used here
115117
for (int lw0 = 0;lw0 < row_indexes.size();lw0 += npol) // spin 1-3 of dHS is not needed at nspin=4

source/source_lcao/module_lr/Grad/force/lr_force.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ using TAC = std::pair<int, std::array<int, 3>>;
99
#endif
1010
namespace LR
1111
{
12+
/// `dm_gs` carries the ground-state occupations, at nspin=1 they are 2 for fully occupied
13+
/// bands, so any term that contracts against ONE channel of `dm_gs` needs this factor.
14+
/// Closed-shell bookkeeping only: the open-shell path sums the two channels explicitly and
15+
/// must not apply it.
16+
inline double gs_dm_channel_factor() { return (PARAM.inp.nspin == 1) ? 0.5 : 1.0; }
1217

1318
template<typename TK>
1419
class LR_Force

source/source_lcao/module_lr/Grad/force/lr_force_test.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,14 @@ namespace LR
4040
{
4141
const auto& Ds_gs = LR_Util::get_exx_Ds_gs(dm_gs, ucell_, kv, pv_);
4242
const auto& Ds_gs_2 = LR_Util::get_exx_Ds_gs(dm_gs, ucell_, kv, pv_);
43+
// at nspin=1 there is only one channel, and `get_exx_Ds_gs` already returns 0.5*D
44+
// (= D_up), so both halves below reuse channel 0.
45+
const int is_2nd = (Ds_gs.size() > 1) ? 1 : 0;
4346
ModuleBase::matrix f_gs_exx(ucell_.nat, 3);
4447
// test the two function using the two spin channels respectively
4548
// 0.5 is from dE = 0.5 dTr[D(HD)]. No 0.5 in excited-state calculateion of dTr[(T+Z)(HD)]
4649
f_gs_exx += cal_force_exx_gs_dm_relaxed_diff(Ds_gs.at(0), Ds_gs_2.at(0), alpha_, std::to_string(0)) * 0.5; // test passed, = 0.5 groud-state EXX force
47-
f_gs_exx += cal_force_exx_dm_trans(Ds_gs.at(1), alpha_, std::to_string(1)) * 0.5;
50+
f_gs_exx += cal_force_exx_dm_trans(Ds_gs.at(is_2nd), alpha_, std::to_string(is_2nd)) * 0.5;
4851
if (PARAM.inp.test_force)
4952
ModuleIO::print_force(GlobalV::ofs_running, ucell_, "EXX GS FORCE reproduce (eV/Angstrom)", f_gs_exx, false);
5053
f_gs_hf_pulay += f_gs_exx;

source/source_lcao/module_lr/operator_casida/operator_lr_exx.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ namespace LR
4949
}
5050
case MO_TO_AO_TYPE::CC_oo:
5151
{
52+
// Cv -> CoX^T, i.e. C_o [C_oX^T]
5253
DMBand<double>(ucell, pmat, this->kv.kvec_c, this->BvK_cells, this->psi_ks_full, this->psi_ks_full)
53-
.cal_dm_band(io, io, ik, this->Ds_onebase, 1.0, this->aims_nbasis, this->aims_nbasis);
54+
.cal_dm_band(io, iv, ik, this->Ds_onebase, 1.0);
5455
break;
5556
}
5657
case MO_TO_AO_TYPE::CXC_o:

0 commit comments

Comments
 (0)