1+ #pragma once
2+ #include " module_hamilt_general/hamilt.h"
3+ #include " module_elecstate/module_dm/density_matrix.h"
4+ #include " module_lr/Grad/xc/pot_grad_xc.h"
5+ #include " module_lr/potentials/pot_hxc_lrtd.h"
6+ #include " module_lr/operator_casida/operator_lr_hxc.h"
7+ #include " module_basis/module_ao/parallel_orbitals.h"
8+ namespace LR
9+ {
10+ // $\sum_a (\Omega - \epsilon_a)\delta_{ij}$
11+ // !!! Not yet support multi-k
12+ template <typename T>
13+ void add_sum_eig_minus_evirt (T* const inout,
14+ const double eig_ext_istate,
15+ const double * const eig_ks,
16+ const int nocc,
17+ const int nvirt,
18+ const Parallel_2D& p_occ_occ)
19+ {
20+ for (int i = 0 ;i < nocc;++i)
21+ {
22+ if (p_occ_occ.in_this_processor (i, i)) // diagonal elements in this processor
23+ {
24+ const int lrow = p_occ_occ.global2local_row (i);
25+ const int lcol = p_occ_occ.global2local_col (i);
26+ for (int a = 0 ;a < nvirt;++i)
27+ {
28+ inout[lcol * p_occ_occ.get_row_size () + lrow] += (eig_ext_istate - eig_ks[/* *ik, */ nocc + i]);
29+ }
30+ }
31+ }
32+ }
33+
34+ template <typename T, typename TGint>
35+ void cal_W_from_Z (T* const W,
36+ const T* const Z,
37+ const T* const X,
38+ const double * const eig,
39+ const int & nspin,
40+ const int & naos,
41+ const std::vector<int >& nocc,
42+ const std::vector<int >& nvirt,
43+ const UnitCell& ucell_in,
44+ const std::vector<double >& orb_cutoff,
45+ const Grid_Driver& gd_in,
46+ const psi::Psi<T>& psi_ks_in,
47+ const ModuleBase::matrix& eig_ks,
48+ #ifdef __EXX
49+ std::weak_ptr<Exx_LRI<T>> exx_lri,
50+ const double & exx_alpha,
51+ #endif
52+ TGint* gint_in,
53+ std::weak_ptr<PotHxcLR> pot,
54+ const K_Vectors& kv,
55+ const std::vector<Parallel_2D>& px,
56+ const Parallel_2D& pc,
57+ const Parallel_2D& p_occ_occ, // < for W
58+ const Parallel_Orbitals& pmat,
59+ const std::string& spin_type = " singlet" )
60+ {
61+ ModuleBase::TITLE (" Z_vector_R" , " Z_vector_R" );
62+ using ATYPE = typename OperatorLRHxc<T>::MO_TO_AO_TYPE;
63+ const int nk = kv.get_nks () / nspin;
64+ // allocate memory for DMs
65+ elecstate::DensityMatrix<T, T> DM_trans (&pmat, 1 , kv.kvec_d , nk); // DX
66+ elecstate::DensityMatrix<T, T> DM_diff_relaxed (&pmat, 1 , kv.kvec_d , nk); // T+DZ
67+
68+ // / operators
69+ // 1. 0.5$H_{ia}[T]$, equals to $K_{ab}[T]$ when $T$ is symmetrized
70+ OperatorLRHxc<T> op_ht (nspin, naos, nocc, nvirt, psi_ks_in,
71+ DM_diff_relaxed, gint_in, pot, ucell_in, orb_cutoff, gd_in, kv, px, pc, pmat,
72+ { 0 }, T (1.0 ), ATYPE::CC_oo);
73+ // 2. $2\sum_{jb,kc} g^{xc}_{ia, jb, kc}X_{jb}X_{kc}$
74+ PotGradXCLR pot_grad (pot.lock ()->xc_kernel_components , pot.lock ()->rho_basis , ucell_in, pot.lock ()->nrxx );
75+ OperatorLRHxc<T> op_gxc (nspin, naos, nocc, nvirt, psi_ks_in,
76+ DM_trans, gint_in, pot_grad, ucell_in, orb_cutoff, gd_in, kv, px, pc, pmat,
77+ { 0 }, T (-2.0 ), ATYPE::CC_oo);
78+ #ifdef __EXX
79+ // add EXX operators here
80+ #endif
81+ auto cal_dm_trans = [&](const int is, const T* const x_ptr)->void // DX
82+ {
83+ const auto psi_ks_is = LR_Util::get_psi_spin (psi_ks_in, is, nk);
84+ #ifdef __MPI
85+ std::vector<ct::Tensor> dm_trans_2d = cal_dm_trans_pblas (x_ptr, px[is], psi_ks_is, pc, naos, nocc[is], nvirt[is], pmat);
86+ for (auto & t : dm_trans_2d) LR_Util::matsym (t.data <T>(), naos, pmat);
87+ #else
88+ std::vector<ct::Tensor> dm_trans_2d = cal_dm_trans_blas (x_ptr, psi_ks_is, nocc[is], nvirt[is]);
89+ for (auto & t : dm_trans_2d) LR_Util::matsym (t.data <T>(), naos);
90+ #endif
91+ for (int ik = 0 ;ik < nk;++ik) { DM_trans->set_DMK_pointer (ik, dm_trans_2d[ik].data <T>()); }
92+ };
93+
94+ auto cal_dm_diff_relaxed = [&](const int & is, const T* const x_ptr, const T* const z_ptr)->void // T+DZ
95+ {
96+ const auto psi_ks_is = LR_Util::get_psi_spin (psi_ks_in, is, nk);
97+ #ifdef __MPI
98+ std::vector<ct::Tensor> z_2d = cal_dm_trans_pblas (z_ptr, px[is], psi_ks_is, pc, naos, nocc[is], nvirt[is], pmat);
99+ for (auto & t : dm_trans_2d) LR_Util::matsym (t.data <T>(), naos, pmat);
100+ #else
101+ std::vector<ct::Tensor> z_2d = cal_dm_trans_blas (z_ptr, psi_ks_is, nocc[is], nvirt[is]);
102+ for (auto & t : dm_trans_2d) LR_Util::matsym (t.data <T>(), naos);
103+ #endif
104+
105+ #ifdef __MPI
106+ std::vector<ct::Tensor> dm_diff_2d = cal_dm_diff_pblas (x_ptr, px[is], psi_ks_is, pc, naos, nocc[is], nvirt[is], pmat);
107+ #else
108+ std::vector<ct::Tensor> dm_diff_2d = cal_dm_diff_blas (x_ptr, psi_ks_is, naos, nocc[is], nvirt[is]);
109+ #endif
110+ for (int ik = 0 ;ik < nk;++ik)
111+ {
112+ dm_diff_2d[i] += z_2d[i];
113+ DM_diff->set_DMK_pointer (ik, dm_diff_2d[ik].data <T>());
114+ }
115+ };
116+
117+ // act the operators onto each state
118+ const int ld_vo = nk * px[0 ].get_local_size ();
119+ const int ld_oo = nk * p_occ_occ.get_local_size ();
120+ for (int ib = 0 ;ib < nstates;++ib)
121+ {
122+ const int offset_vo = ib * ld_vo;
123+ const int offset_oo = ib * ld_oo;
124+ cal_dm_trans (0 , X + offset_vo, Z + offset_vo); // transition density matrix DX
125+ cal_dm_diff_relaxed (0 , X + offset_vo, Z + offset_vo); // relaxed difference density matrix T+DZ
126+ // the 3 terms
127+ op_ht.act (/* nband=*/ 1 , ld_vo, /* npol=*/ 1 , X + offset_vo, W + offset_oo);
128+ op_gxc.act (/* nband=*/ 1 , ld_vo, /* npol=*/ 1 , X + offset_vo, W + offset_oo);
129+ add_sum_eig_minus_evirt (W + offset_oo, eig[ib], eig_ks.data (), nocc[0 ], nvirt[0 ], p_occ_occ);
130+ }
131+ }
132+ }
0 commit comments