Skip to content

Commit ba5d443

Browse files
committed
feat: lr-grad openshell implementation
1 parent a264c13 commit ba5d443

17 files changed

Lines changed: 1486 additions & 97 deletions

source/source_esolver/esolver_lr_lcao_tddft.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ namespace ModuleESolver
160160
void init_pot_groundstate(const Charge& chg_gs);
161161
ct::Tensor solve_zvector_eqation(const int ispin);
162162
std::vector<ModuleBase::matrix> cal_force(const int ispin);
163+
/// open-shell (spin-unrestricted) excited-state force: X holds [up | down] and every
164+
/// density matrix has two independent channels
165+
std::vector<ModuleBase::matrix> cal_force_openshell();
163166
void test_force(); // test: reproduce the force of ground state
164167
elecstate::DensityMatrix<T, double> cal_dm_gs(); ///< ground-state density matrix
165168

source/source_lcao/module_lr/Grad/esolver_lr_grad.cpp

Lines changed: 172 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ ct::Tensor ModuleESolver::ESolver_LR<T, TR>::solve_zvector_eqation(const int isp
114114
std::weak_ptr<Exx_LRI<T>>(this->exx_lri), this->exx_info.info_global.hybrid_alpha,
115115
#endif
116116
std::weak_ptr<PotHxcLR>(this->pot[ispin]), std::weak_ptr<PotHxcLR>(this->pot_hxc_gs),
117-
this->kv, this->paraX_, this->paraC_, this->paraMat_, this->spin_types[ispin]);
117+
this->kv, this->paraX_, this->paraC_, this->paraMat_, this->spin_types[ispin], this->openshell);
118118
ModuleBase::timer::end("ESolver_LR", "solve_zvector_eqation");
119119
return Z;
120120
}
@@ -123,6 +123,7 @@ template<typename T, typename TR>
123123
std::vector<ModuleBase::matrix> ModuleESolver::ESolver_LR<T, TR>::cal_force(const int ispin)
124124
{
125125
if (PARAM.inp.test_force && ispin == 0) { this->test_force(); }
126+
if (this->openshell) { return this->cal_force_openshell(); }
126127

127128
const ct::Tensor& Z = this->solve_zvector_eqation(ispin);
128129

@@ -302,7 +303,10 @@ std::vector<ModuleBase::matrix> ModuleESolver::ESolver_LR<T, TR>::cal_force(cons
302303
const auto& Ds_gs = LR_Util::get_exx_Ds_spin1(dm_gs, (*this->ucell_), this->kv, this->paraMat_); // returns 0.5*D[0]
303304
const auto& Ds_relaxed_diff = LR_Util::get_exx_Ds_spin1(relaxed_diff_dm, (*this->ucell_), this->kv, this->paraMat_); // returns 0.5*D[0]
304305
// LR_Util::print_CV(Ds_relaxed_diff, "Ds_relaxed_diff for EXX force");
305-
ModuleBase::matrix force_exx_gs_relaxed_diff = lr_force.cal_force_exx_gs_dm_relaxed_diff(Ds_gs, Ds_relaxed_diff, alpha * 4.0); // cancel the two 0.5s in Ds
306+
// `get_exx_Ds_spin1` feeds `split_m2D_ktoR(..., nspin=1)`, which reads only channel 0
307+
// with a 0.5 prefactor. For `dm_gs` that channel is $D^\text{gs}_\uparrow$ at nspin=2
308+
// but the spin-summed $D^\text{gs}$ at nspin=1, i.e. twice as large.
309+
ModuleBase::matrix force_exx_gs_relaxed_diff = lr_force.cal_force_exx_gs_dm_relaxed_diff(Ds_gs, Ds_relaxed_diff, alpha * 4.0) * gs_dm_channel_factor(); // cancel the two 0.5s in Ds
306310
if (PARAM.inp.test_force)
307311
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "EXX GS-(T+Z) FORCE (eV/Angstrom)", force_exx_gs_relaxed_diff, false);
308312
force_hamiltgs_relaxed_diff += force_exx_gs_relaxed_diff;
@@ -312,7 +316,7 @@ std::vector<ModuleBase::matrix> ModuleESolver::ESolver_LR<T, TR>::cal_force(cons
312316
// test H[T] force (Z=0), EXX part
313317
const auto& Ds_diff = LR_Util::get_exx_Ds_spin1(diff_dm, (*this->ucell_), this->kv, this->paraMat_); // returns 0.5*D[0]
314318
GlobalV::ofs_running << "========== [TEST H_GS-(T) force (Z=0), EXX part] ===========" << std::endl;
315-
ModuleBase::matrix force_exx_gs_diff = lr_force.cal_force_exx_gs_dm_relaxed_diff(Ds_gs, Ds_diff, alpha * 4.0); // cancel the two 0.5s in Ds
319+
ModuleBase::matrix force_exx_gs_diff = lr_force.cal_force_exx_gs_dm_relaxed_diff(Ds_gs, Ds_diff, alpha * 4.0) * gs_dm_channel_factor(); // cancel the two 0.5s in Ds
316320
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "H_GS-T EXX FORCE (Z=0) (eV/Angstrom)", force_exx_gs_diff, false);
317321
GlobalV::ofs_running << "========== [\\TEST H_GS-(T) force (Z=0), EXX part] ===========" << std::endl;
318322
}
@@ -327,6 +331,171 @@ std::vector<ModuleBase::matrix> ModuleESolver::ESolver_LR<T, TR>::cal_force(cons
327331
return forces;
328332
}
329333

334+
template<typename T, typename TR>
335+
std::vector<ModuleBase::matrix> ModuleESolver::ESolver_LR<T, TR>::cal_force_openshell()
336+
{
337+
ModuleBase::TITLE("ESolver_LR", "cal_force_openshell");
338+
ModuleBase::timer::start("ESolver_LR", "cal_force");
339+
340+
// Open shell: there is a single eigenproblem whose vector is the concatenation
341+
// [up-block | down-block], and every density matrix has two independent channels.
342+
// The spin-orbital formulas apply verbatim -- unlike the closed-shell singlet/triplet
343+
// algorithm, X here is normalized over BOTH channels, so it carries no implicit sqrt(2)
344+
// and none of the collapsed 2/4 factors are needed.
345+
const ct::Tensor& Z = this->solve_zvector_eqation(0);
346+
347+
const std::vector<int> ld_x = { this->nk * this->paraX_[0].get_local_size(),
348+
this->nk * this->paraX_[1].get_local_size() };
349+
const std::vector<int> off_x = { 0, ld_x[0] };
350+
std::vector<psi::Psi<T>> c_spin;
351+
for (int is : {0, 1}) { c_spin.push_back(LR_Util::get_psi_spin(*this->psi_ks, is, this->nk)); }
352+
353+
LR_Force<T> lr_force((*this->ucell_), this->kv.kvec_d, this->paraMat_,
354+
*this->pw_rhod, *this->pw_rho, this->locpp, this->sf, this->gd, this->two_center_bundle_
355+
#ifdef __EXX
356+
, std::weak_ptr<Exx_LRI<T>>(this->exx_lri), this->exx_info.info_global.hybrid_alpha
357+
#endif
358+
);
359+
GlobalV::ofs_running << "Start to calculate excited-state force of updown (open shell)" << std::endl;
360+
361+
std::vector<ModuleBase::matrix> forces(this->nstates);
362+
for (int istate = 0;istate < this->nstates;++istate)
363+
{
364+
const int offset = istate * this->nloc_per_state;
365+
const T* const X_istate = this->X[0].template data<T>() + offset;
366+
const T* const Z_istate = Z.template data<T>() + offset;
367+
368+
// 1. the k-space blocks of each spin channel
369+
std::vector<std::vector<ct::Tensor>> dmx_k(2), dmdiff_k(2), relaxed_k(2);
370+
for (int is : {0, 1})
371+
{
372+
dmx_k[is] = cal_dm_trans_pblas(X_istate + off_x[is], this->paraX_[is], c_spin[is], this->paraC_,
373+
this->nbasis, this->nocc[is], this->nvirt[is], this->paraMat_);
374+
dmdiff_k[is] = cal_dm_diff_pblas(X_istate + off_x[is], this->paraX_[is], c_spin[is], this->paraC_,
375+
this->nbasis, this->nocc[is], this->nvirt[is], this->paraMat_);
376+
std::vector<ct::Tensor> dmz_k = cal_dm_trans_pblas(Z_istate + off_x[is], this->paraX_[is], c_spin[is],
377+
this->paraC_, this->nbasis, this->nocc[is], this->nvirt[is], this->paraMat_);
378+
for (auto& d : dmz_k) { LR_Util::matsym(d.template data<T>(), this->nbasis, this->paraMat_); }
379+
relaxed_k[is] = dmdiff_k[is] + dmz_k;
380+
}
381+
382+
// 2. $D^X$. Complex and UN-symmetrized first (the EXX kernel needs the full
383+
// non-symmetric $D^X$), then the real symmetrized copy for the grid Hxc force --
384+
// `build_dm_from_dmk_spin` symmetrizes IN PLACE, hence the ordering.
385+
auto dm_trans = LR_Util::build_dm_from_dmk_spin<T, T>(dmx_k,
386+
this->paraMat_, this->nk, this->kv.kvec_d, (*this->ucell_), this->gd, this->orb_cutoff_);
387+
LR_Util::transpose_DMR(dm_trans, (*this->ucell_).nat);
388+
auto dm_trans_real = LR_Util::build_dm_from_dmk_spin<T, double>(dmx_k,
389+
this->paraMat_, this->nk, this->kv.kvec_d, (*this->ucell_), this->gd, this->orb_cutoff_,
390+
/*symmetrize=*/true);
391+
LR_Util::transpose_DMR(dm_trans_real, (*this->ucell_).nat);
392+
393+
// 3. the relaxed difference density matrix $T+D^Z$
394+
const elecstate::DensityMatrix<T, T>& relaxed_diff_dm =
395+
LR_Util::build_dm_from_dmk_spin<T, T>(relaxed_k,
396+
this->paraMat_, this->nk, this->kv.kvec_d, (*this->ucell_), this->gd, this->orb_cutoff_);
397+
elecstate::DensityMatrix<T, double> relaxed_diff_dm_real(&this->paraMat_, 2, this->kv.kvec_d, this->nk);
398+
LR_Util::initialize_DMR(relaxed_diff_dm_real, this->paraMat_, (*this->ucell_), this->gd, this->orb_cutoff_);
399+
LR_Util::get_DMR_real_imag_part(relaxed_diff_dm, relaxed_diff_dm_real, 'R');
400+
401+
// 4. the energy-weighted density matrix
402+
std::weak_ptr<PotHxcLR> pot_weak = this->pot[0];
403+
std::weak_ptr<PotHxcLR> pot_hxc_gs_weak = this->pot_hxc_gs;
404+
#ifdef __EXX
405+
std::weak_ptr<Exx_LRI<T>> exx_lri_weak = this->exx_lri;
406+
#endif
407+
const std::vector<std::vector<ct::Tensor>>& edm_k =
408+
cal_edm_from_XZ_istate_openshell(X_istate, Z_istate,
409+
this->pelec->ekb.c[istate], this->eig_ks.c, dm_trans,
410+
*this->psi_ks, this->nspin, this->nbasis, this->nocc, this->nvirt,
411+
(*this->ucell_), this->orb_cutoff_,
412+
#ifdef __EXX
413+
exx_lri_weak, this->exx_info.info_global.hybrid_alpha,
414+
#endif
415+
pot_weak, pot_hxc_gs_weak,
416+
this->kv, this->gd, this->paraX_, this->paraC_, this->paraMat_, this->xc_kernel);
417+
elecstate::DensityMatrix<T, double> edm_real = LR_Util::build_dm_from_dmk_spin<T, double>(edm_k,
418+
this->paraMat_, this->nk, this->kv.kvec_d, (*this->ucell_), this->gd, this->orb_cutoff_,
419+
/*symmetrize=*/true);
420+
421+
// 5. the force terms
422+
ModuleBase::matrix force_hxc_dmtrans = lr_force.cal_force_hxc_dmtrans(dm_trans_real, *this->pot[0]);
423+
if (PARAM.inp.test_force)
424+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "HXC DMTRANS FORCE (eV/Angstrom)", force_hxc_dmtrans, false);
425+
426+
const elecstate::DensityMatrix<T, double>& dm_gs = this->cal_dm_gs();
427+
428+
// the $g^{xc}$ half of $\partial_x K[D^X]D^X$, i.e. the derivative of the xc kernel
429+
// through the ground-state density. Only for local kernels.
430+
if (LR_Util::has_local_xc(this->xc_kernel))
431+
{
432+
PotGradXCLR pot_grad(this->pot_hxc_gs->xc_kernel_components(), this->pot_hxc_gs->get_rho_basis(),
433+
(*this->ucell_), this->pot_hxc_gs->nrxx, /*triplet=*/false);
434+
ModuleBase::matrix force_gxc_dmtrans =
435+
lr_force.cal_force_gxc_dmtrans_openshell(dm_trans_real, dm_gs, pot_grad);
436+
if (PARAM.inp.test_force)
437+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "GXC DMTRANS FORCE (eV/Angstrom)", force_gxc_dmtrans, false);
438+
force_hxc_dmtrans += force_gxc_dmtrans;
439+
}
440+
441+
ModuleBase::matrix force_hamiltgs_relaxed_diff = lr_force.cal_force_hamilt_gs_dm_relaxed_diff(
442+
relaxed_diff_dm_real, dm_gs, false, this->pot_hxc_gs.get());
443+
if (PARAM.inp.test_force)
444+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "H_GS-(T+Z) FORCE (without EXX) (eV/Angstrom)", force_hamiltgs_relaxed_diff, false);
445+
446+
ModuleBase::matrix force_overlap_edm = lr_force.cal_force_overlap_edm(edm_real);
447+
if (PARAM.inp.test_force)
448+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "OVERLAP-EDM FORCE (eV/Angstrom)", force_overlap_edm, false);
449+
450+
#ifdef __EXX
451+
const double& alpha = this->exx_info.info_global.hybrid_alpha;
452+
// Exchange is spin-diagonal, so each channel is done independently and summed.
453+
// `get_exx_Ds_gs` returns the channels unscaled (SPIN_multiple = 1 at nspin=2), unlike
454+
// the closed-shell `get_exx_Ds_spin1` which returns 0.5*D. Counting the closed-shell
455+
// `alpha*4.0` back down for both terms:
456+
// $D^XD^X$: each slot goes 0.5*D^X_tot -> D^X_is, i.e. x2 each, and the explicit
457+
// sum over is adds another x2 -- but $D^X_\text{tot}=\sqrt2 D^X_\sigma$ eats one,
458+
// so 4/(2*2) * ... = `alpha`.
459+
// $D^\text{gs}(T{+}D^Z)$: the left slot goes 0.5*D_up -> D_is (x2); the right slot
460+
// goes 0.5*(T+Z)_tot = (T+Z)_up -> (T+Z)_is (x1, no sqrt2 here); the explicit sum
461+
// over is adds x2. So 4/(2*1*2) = `alpha` as well -- NOT `2*alpha`: the earlier
462+
// comment forgot that the closed-shell right slot is already the spin SUM, which is
463+
// exactly what the `for (is)` loop below now supplies.
464+
if (LR::exx_kernel_list().count(this->xc_kernel))
465+
{
466+
const auto& Ds_trans = LR_Util::get_exx_Ds_gs(dm_trans, (*this->ucell_), this->kv, this->paraMat_);
467+
ModuleBase::matrix force_exx_dmtrans(this->ucell_->nat, 3);
468+
for (int is : {0, 1})
469+
{
470+
force_exx_dmtrans += lr_force.cal_force_exx_dm_trans(Ds_trans[is], alpha, std::to_string(is));
471+
}
472+
if (PARAM.inp.test_force)
473+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "EXX DMTRANS FORCE (eV/Angstrom)", force_exx_dmtrans, false);
474+
force_hxc_dmtrans += force_exx_dmtrans;
475+
}
476+
if (LR::exx_kernel_list().count(PARAM.inp.dft_functional))
477+
{
478+
const auto& Ds_gs = LR_Util::get_exx_Ds_gs(dm_gs, (*this->ucell_), this->kv, this->paraMat_);
479+
const auto& Ds_relaxed_diff = LR_Util::get_exx_Ds_gs(relaxed_diff_dm, (*this->ucell_), this->kv, this->paraMat_);
480+
ModuleBase::matrix force_exx_gs_relaxed_diff(this->ucell_->nat, 3);
481+
for (int is : {0, 1})
482+
{
483+
force_exx_gs_relaxed_diff += lr_force.cal_force_exx_gs_dm_relaxed_diff(
484+
Ds_gs[is], Ds_relaxed_diff[is], alpha, std::to_string(is));
485+
}
486+
if (PARAM.inp.test_force)
487+
ModuleIO::print_force(GlobalV::ofs_running, (*this->ucell_), "EXX GS-(T+Z) FORCE (eV/Angstrom)", force_exx_gs_relaxed_diff, false);
488+
force_hamiltgs_relaxed_diff += force_exx_gs_relaxed_diff;
489+
}
490+
#endif
491+
forces[istate] = force_hxc_dmtrans + force_hamiltgs_relaxed_diff + force_overlap_edm;
492+
}
493+
ModuleBase::timer::end("ESolver_LR", "cal_force");
494+
print_force(forces, std::cout);
495+
print_force(forces, GlobalV::ofs_running);
496+
return forces;
497+
}
498+
330499
template<typename T, typename TR>
331500
elecstate::DensityMatrix<T, double> ModuleESolver::ESolver_LR<T, TR>::cal_dm_gs()
332501
{

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

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
// #include "source_lcao/module_lr/utils/lr_util_hcontainer.h"
88
namespace LR
99
{
10-
/// `dm_gs` carries the ground-state occupations, at nspin=1 they are 2 for fully occupied bands.
11-
inline double gs_dm_channel_factor() { return (PARAM.inp.nspin == 1) ? 0.5 : 1.0; }
10+
/// The LR density matrices ($D^X$, $T+D^Z$, EDM) carry one channel in the closed-shell
11+
/// singlet/triplet algorithm and two independent channels in the open-shell one.
12+
template<typename TK>
13+
inline bool is_openshell_dm(const elecstate::DensityMatrix<TK, double>& dm)
14+
{
15+
return dm.get_DMR_vector().size() == 2;
16+
}
1217

1318
template<typename TK>
1419
Charge LR_Force<TK>::dm_to_charge(const elecstate::DensityMatrix<TK, double>& dm)
@@ -58,6 +63,10 @@ namespace LR
5863
const PotHxcLR* pot_hxc_gs)
5964
{
6065
const bool with_ewald = reproduce_gs;
66+
// Two independent spin channels in `relax_diff_dm` <=> open-shell (spin-unrestricted) LR.
67+
// The closed-shell singlet/triplet algorithm always builds a single-channel LR density
68+
// matrix, even at nspin=2.
69+
const bool openshell = is_openshell_dm(relax_diff_dm);
6170
const Charge chr_diff_relaxed = dm_to_charge(relax_diff_dm);
6271

6372
// 1. local pp (Hellmann-Feynman)(fvl_dvl) + ewald + core correction (+ self-consistent charge)
@@ -122,6 +131,27 @@ namespace LR
122131
//`cal_pulay_fs` calculates only one spin channel because `relax_diff_dm` has only one.
123132
PulayForceStress::cal_pulay_fs(1/*nspin*/, fhxc_dvhxc, stress_tmp,
124133
dm_gs, this->ucell_, &pot_hxc_relaxed_diff, true, false);
134+
fhxc_dvhxc *= gs_dm_channel_factor();
135+
}
136+
else if (openshell)
137+
{
138+
// $v_\sigma=\sum_{\sigma'}f^{\sigma\sigma'}\rho^{T+Z}_{\sigma'}$ (+ the full Hartree),
139+
// contracted with $D^\text{gs}_\sigma$. No factor 2 and no `gs_dm_channel_factor`:
140+
// the two ground-state channels are summed explicitly by `cal_gint_fvl` below, and
141+
// each carries occupation 1 rather than 2.
142+
constexpr int nspin_dm = 2;
143+
std::vector<ModuleBase::matrix> v_lin(nspin_dm, ModuleBase::matrix(1, this->rhopw_.nrxx));
144+
for (int sl = 0; sl < nspin_dm; ++sl)
145+
{
146+
for (int sr = 0; sr < nspin_dm; ++sr)
147+
{
148+
double* rho_in[1] = { const_cast<double*>(chr_diff_relaxed.rho[sr]) };
149+
pot_hxc_gs->cal_v_eff(rho_in, this->ucell_, v_lin[sl], { sl, sr });
150+
}
151+
}
152+
std::vector<const double*> vr_eff(nspin_dm);
153+
for (int is = 0; is < nspin_dm; ++is) { vr_eff[is] = v_lin[is].c; }
154+
ModuleGint::cal_gint_fvl(nspin_dm, vr_eff, dm_gs.get_DMR_vector(), true, false, &fhxc_dvhxc, &stress_tmp);
125155
}
126156
else
127157
{
@@ -130,9 +160,9 @@ namespace LR
130160
pot_hxc_gs->cal_v_eff(rho_in, this->ucell_, v_lin);
131161
std::vector<const double*> vr_eff = { v_lin.c };
132162
ModuleGint::cal_gint_fvl(1, vr_eff, dm_gs.get_DMR_vector(), true, false, &fhxc_dvhxc, &stress_tmp);
163+
fhxc_dvhxc *= 2; // for the two channels of the ground-state dm.
164+
fhxc_dvhxc *= gs_dm_channel_factor();
133165
}
134-
if(!reproduce_gs) {fhxc_dvhxc *= 2;} // for the two channels of the ground-state dm.
135-
fhxc_dvhxc *= gs_dm_channel_factor();
136166

137167
// 4. kinetic (Pulay)
138168
std::vector<hamilt::HContainer<double>> dT = cal_hs_grad('T', this->ucell_, this->pv_, this->gd_, this->two_center_bundle_);
@@ -165,6 +195,13 @@ namespace LR
165195
// Verified on H2/SZ against the analytic 4-center derivative: 4*sum D^sym P = 16.8653548
166196
// vs 2*d(ai|ia)/dz = 16.865355 eV/Ang (7 digits).
167197
const double pulay_to_total_sym = 2.0;
198+
// Open shell: the kernel couples the channels, so the density has to be built per channel
199+
// and the potential accumulated over the summed spin before contracting with $D^X_\sigma$.
200+
// `pulay_to_total_sym` is a Pulay -> Pulay+Hellmann-Feynman factor and is spin-independent.
201+
if (is_openshell_dm(dm_trans))
202+
{
203+
return PulayForceStress::cal_pulay_fs_openshell(dm_trans, this->ucell_, &pot_hxc) * pulay_to_total_sym;
204+
}
168205
return PulayForceStress::cal_pulay_fs(dm_trans, this->ucell_, &pot_hxc) * pulay_to_total_sym;
169206
}
170207

@@ -201,6 +238,31 @@ namespace LR
201238
return f;
202239
}
203240

241+
template<typename TK>
242+
ModuleBase::matrix LR_Force<TK>::cal_force_gxc_dmtrans_openshell(
243+
const elecstate::DensityMatrix<TK, double>& dm_trans,
244+
const elecstate::DensityMatrix<TK, double>& dm_gs, const PotGradXCLR& pot_grad)
245+
{
246+
// Same term as `cal_force_gxc_dmtrans`, spin-resolved: the free index $\tau$ (spin channel)
247+
// of $v^{(2)}_\tau$ is contracted with $D^\text{gs}_\tau$, and `cal_gint_fvl` does the
248+
// $\sum_\tau$. No `gs_dm_channel_factor` here -- both ground-state channels are summed
249+
// explicitly and each carries occupation 1.
250+
constexpr int nspin_dm = 2;
251+
assert(dm_trans.get_DMR_vector().size() == nspin_dm);
252+
const Charge chr_x = dm_to_charge(dm_trans);
253+
const double* rho_in[nspin_dm] = { chr_x.rho[0], chr_x.rho[1] };
254+
255+
std::vector<ModuleBase::matrix> v2(nspin_dm, ModuleBase::matrix(1, this->rhopw_.nrxx));
256+
for (int tau = 0; tau < nspin_dm; ++tau) { pot_grad.cal_v_eff_openshell(rho_in, this->ucell_, v2[tau], tau); }
257+
258+
ModuleBase::matrix f(this->ucell_.nat, 3);
259+
ModuleBase::matrix stress_tmp;
260+
std::vector<const double*> vr_eff(nspin_dm);
261+
for (int is = 0; is < nspin_dm; ++is) { vr_eff[is] = v2[is].c; }
262+
ModuleGint::cal_gint_fvl(nspin_dm, vr_eff, dm_gs.get_DMR_vector(), true, false, &f, &stress_tmp);
263+
return f;
264+
}
265+
204266
#ifdef __EXX
205267
template<typename TK>
206268
ModuleBase::matrix LR_Force<TK>::cal_force_exx_dm_trans(

0 commit comments

Comments
 (0)