Skip to content

Commit 6aea1fc

Browse files
committed
modify some factors and clarify in the comments
1 parent 494ee60 commit 6aea1fc

2 files changed

Lines changed: 21 additions & 13 deletions

File tree

source/module_lr/Grad/force/lr_force.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,19 @@ namespace LR
8989
this->gint_->reset_DMRGint(dm_gs.get_DMR_vector().size());
9090
elecstate::Potential pot_hxc = this->dm_to_hxc_potential(dm_gs);
9191
this->gint_->reset_DMRGint(relax_diff_dm.get_DMR_vector().size());
92+
// `cal_pulay_fs` calculates 1*Pulay-term.
93+
// For ground-state DFT, Pulay term = Hellmann-Feynman term, F = 1/2(Pulay + H-F) = Pulay, so directly call it once gives correct result.
9294
PulayForceStress::cal_pulay_fs(relax_diff_dm.get_DMR_vector().size()/*nspin*/, fhxc_dphi, stress_tmp,
9395
relax_diff_dm, this->ucell_, &pot_hxc, *this->gint_, true, false);
94-
fhxc_dphi *= 0.5; // avoid double count
96+
// fhxc_dphi *= 0.5; // avoid double count
9597

9698
// 3.3 Hartree + xc (Hellmann-Feynman)
9799
ModuleBase::matrix fhxc_dvhxc(this->ucell_.nat, 3);
98100
elecstate::Potential pot_hxc_relaxed_diff = this->dm_to_hxc_potential(relax_diff_dm);
101+
//`cal_pulay_fs` calculates only one spin channel because `relax_diff_dm` has only one.
99102
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhxc_dvhxc, stress_tmp,
100103
dm_gs, this->ucell_, &pot_hxc_relaxed_diff, *this->gint_, true, false);
101-
// fhxc_dvhxc *= 0.5; // avoid double count, but nspin=2 of ground-state dm cancels it here
104+
fhxc_dvhxc *= 2; // for the two channels of the ground-state dm.
102105

103106
// 4. kinetic (Pulay)
104107
std::vector<hamilt::HContainer<double>> dT = cal_hs_grad('T', this->ucell_, this->pv_, this->gd_, this->two_center_bundle_);
@@ -120,6 +123,9 @@ namespace LR
120123
template<typename TK>
121124
ModuleBase::matrix LR_Force<TK>::cal_force_hxc_dmtrans(const elecstate::DensityMatrix<TK, double>& dm_trans, const PotHxcLR& pot_hxc)
122125
{
126+
// `dm_trans` (D^X) carries the singlet spin normalization (sqrt(2) per channel),
127+
// so D^X in pot_hxc and cal_pulay_fs together already contribute a factor 2.
128+
// So cal_pulay_fs here returns 2*Pulay = Pulay + Hellmann-Feynman force. *2 is not needed here.
123129
return PulayForceStress::cal_pulay_fs(dm_trans, this->ucell_, &pot_hxc, *this->gint_);
124130
}
125131

@@ -134,12 +140,13 @@ namespace LR
134140
auto& exx_lri_kernel = this->exx_lri_.lock()->get();
135141
exx_lri_kernel.set_Ds(dm_trans, this->exx_lri_.lock()->get_info().dm_threshold, spin_suffix);
136142
exx_lri_kernel.cal_Hs({ "", "", spin_suffix });
137-
exx_lri_kernel.cal_force({ "", "", spin_suffix, "", "" });// using dm_trans
143+
exx_lri_kernel.cal_force({ "", "", spin_suffix, "", "" });// using dm_trans,Pulay term only
138144
for (std::size_t idim = 0; idim < 3; ++idim)
139145
for (const auto& force_item : exx_lri_kernel.force[idim])
140146
f_exx_dmtrans(force_item.first, idim) = std::real(force_item.second);
141147
const double fac = -2.0 * alpha; //-2 is the same as post_process_Hexx, Hartree to Ry (which didn't act on Hs)
142-
return f_exx_dmtrans * fac; // dm_trans (DX) already contain the spin channel (sqrt(2) times of up/down channel DX)
148+
const double pulay_to_total_sym = 2.0; // Pulay -> Pulay + Hellmann-Feynman, only when Ds_left and Ds_right are equal
149+
return f_exx_dmtrans * fac * pulay_to_total_sym; // dm_trans (DX) already contain the spin channel (sqrt(2) times of up/down channel DX)
143150
// return f_exx_dmtrans * fac * 2; // 2 is the same in post_process_Eexx at nspin=1 ( up->up + down->down, 2 spin-conserving transitions)
144151
}
145152

@@ -199,8 +206,9 @@ namespace LR
199206

200207
// -2 * 0.5 * alpha
201208
// -2 is the same as post_process_Hexx (a.u. to Ry, which didn't act on Hs)
202-
// 0.5 is the 2-electron integral prefactor
203-
const double fac = -alpha;
209+
// 0.5 is the 2-electron integral prefactor,used in ground-state energy/force where two density matrix are identical
210+
// But the LR-grad Lagrangian/force 2-e term here Tr[(T+Z)H[D]] does not have 1/2 factor.
211+
const double fac = -2 * alpha;
204212
return f_exx_gs_diff * fac;
205213
}
206214
#endif

source/module_lr/Grad/force/lr_force_test.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,29 +170,29 @@ namespace LR
170170
elecstate::DensityMatrix<TK, double> dm_kl_sym = init_dm_eff(k, l, true);
171171
ModuleBase::matrix fhartree_pulay(this->ucell_.nat, 3), fhartree_h_f(this->ucell_.nat, 3);
172172
ModuleBase::matrix stress_tmp; // dummy
173-
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhartree_pulay, stress_tmp, dm_ij_sym, this->ucell_, &pot_hxc_kl, *this->gint_, true, false); // 2 * Pulay term
174-
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhartree_h_f, stress_tmp, dm_kl_sym, this->ucell_, &pot_hxc_ij, *this->gint_, true, false); // 2 * Hellmann-Feynman term
173+
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhartree_pulay, stress_tmp, dm_ij_sym, this->ucell_, &pot_hxc_kl, *this->gint_, true, false); // Pulay term
174+
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhartree_h_f, stress_tmp, dm_kl_sym, this->ucell_, &pot_hxc_ij, *this->gint_, true, false); // Hellmann-Feynman term
175175
ModuleIO::print_force(GlobalV::ofs_running, this->ucell_,
176176
"H2_SZ_CENTER4_HXC_dtau(" + std::to_string(i) + std::to_string(j) + "|" + std::to_string(k) + std::to_string(l) + ") FORCE (Ry/au)",
177-
-(fhartree_pulay + fhartree_h_f), true); // F_Hxc_ijkl = -1/2*dtau(ij|kl), dtau(ij|kl) = -2F = -(2F_pulay + 2F_H-F)
177+
-(fhartree_pulay + fhartree_h_f), true); // F_Hxc_ijkl = -dtau(ij|kl)
178178
ModuleIO::print_force(GlobalV::ofs_running, this->ucell_,
179179
"H2_SZ_CENTER4_HXC_Pulay_dtau(" + std::to_string(i) + std::to_string(j) + "|" + std::to_string(k) + std::to_string(l) + ") FORCE (Ry/au)",
180-
-fhartree_pulay, true); // F_Hxc_ijkl = -1/2*dtau(ij|kl)
180+
-fhartree_pulay, true); // F_Hxc_ijkl = -dtau(ij|kl)
181181
ModuleIO::print_force(GlobalV::ofs_running, this->ucell_,
182182
"H2_SZ_CENTER4_HXC_H-F_dtau(" + std::to_string(i) + std::to_string(j) + "|" + std::to_string(k) + std::to_string(l) + ") FORCE (Ry/au)",
183-
-fhartree_h_f, true); // F_Hxc_ijkl = -1/2*dtau(ij|kl)
183+
-fhartree_h_f, true); // F_Hxc_ijkl = -dtau(ij|kl)
184184
#ifdef __EXX
185185
if (!this->exx_lri_.expired())
186186
{ // match the Gint result with LibRI
187187
auto ds_kl = LR_Util::get_exx_Ds_spin1(dm_kl, ucell_, kv, pv_); // returns ds_kl*0.5
188188
auto ds_ij = LR_Util::get_exx_Ds_spin1(dm_ij, ucell_, kv, pv_); // returns ds_ij*0.5
189189
// calulates F=0.5*d(ik|jl) (only one spin channel). 0.5 is the 2-electron integral prefactor.
190190
// 4 cancels the two 0.5s in Ds, induced by `split_m2D_ktoR`.
191-
// No spin factor hard-coded in this function.
191+
// No spin factor or two-electron-energy factor (1/2) are hard-coded in this function.
192192
ModuleBase::matrix f_exx = this->cal_force_exx_gs_dm_relaxed_diff(ds_kl, ds_ij, alpha_ * 4.0, "");
193193
ModuleIO::print_force(GlobalV::ofs_running, ucell_,
194194
"H2_SZ_CENTER4_EXX_dtau(" + std::to_string(i) + std::to_string(j) + "|" + std::to_string(k) + std::to_string(l) + ") FORCE (Ry/au)",
195-
f_exx * 2, true); //d(ik|jl)=2F
195+
f_exx , true); //d(ik|jl)=F
196196
}
197197
#endif
198198
}

0 commit comments

Comments
 (0)