ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
op_exx_lcao.hpp
Go to the documentation of this file.
1#ifndef OPEXXLCAO_HPP
2#define OPEXXLCAO_HPP
3#ifdef __EXX
4
5#include "op_exx_lcao.h"
13
14namespace hamilt
15{
16using TAC = std::pair<int, std::array<int, 3>>;
17
18// allocate according to the read-in HexxR, used in nscf
19template <typename Tdata, typename TR>
20void reallocate_hcontainer(const std::vector<std::map<int, std::map<TAC, RI::Tensor<Tdata>>>>& Hexxs,
21 HContainer<TR>* hR,
22 const RI::Cell_Nearest<int, int, 3, double, 3>* const cell_nearest)
23{
24 auto* pv = hR->get_paraV();
25 bool need_allocate = false;
26 for (auto& Htmp1: Hexxs[0])
27 {
28 const int& iat0 = Htmp1.first;
29 for (auto& Htmp2: Htmp1.second)
30 {
31 const int& iat1 = Htmp2.first.first;
32 if (pv->get_row_size(iat0) > 0 && pv->get_col_size(iat1) > 0)
33 {
35 (cell_nearest ? cell_nearest->get_cell_nearest_discrete(iat0, iat1, Htmp2.first.second)
36 : Htmp2.first.second));
37 BaseMatrix<TR>* HlocR = hR->find_matrix(iat0, iat1, R.x, R.y, R.z);
38 if (HlocR == nullptr)
39 { // add R to HContainer
40 need_allocate = true;
41 AtomPair<TR> tmp(iat0, iat1, R.x, R.y, R.z, pv);
42 hR->insert_pair(tmp);
43 }
44 }
45 }
46 }
47 if (need_allocate)
48 {
49 hR->allocate(nullptr, true);
50 }
51}
52
54template <typename TR>
55void reallocate_hcontainer(const int nat,
56 HContainer<TR>* hR,
57 const std::array<int, 3>& Rs_period,
58 const RI::Cell_Nearest<int, int, 3, double, 3>* const cell_nearest)
59{
60 auto* pv = hR->get_paraV();
61 auto Rs = RI_Util::get_Born_von_Karmen_cells(Rs_period);
62 bool need_allocate = false;
63 for (int iat0 = 0; iat0 < nat; ++iat0)
64 {
65 for (int iat1 = 0; iat1 < nat; ++iat1)
66 {
67 // complete the atom pairs that has orbitals in this processor but not in hR due to the adj_list
68 // but adj_list is not enought for EXX, which is more nonlocal than Nonlocal
69 if (pv->get_row_size(iat0) > 0 && pv->get_col_size(iat1) > 0)
70 {
71 for (auto& cell: Rs)
72 {
74 (cell_nearest ? cell_nearest->get_cell_nearest_discrete(iat0, iat1, cell) : cell));
75 BaseMatrix<TR>* HlocR = hR->find_matrix(iat0, iat1, R.x, R.y, R.z);
76
77 if (HlocR == nullptr)
78 { // add R to HContainer
79 need_allocate = true;
80 AtomPair<TR> tmp(iat0, iat1, R.x, R.y, R.z, pv);
81 hR->insert_pair(tmp);
82 }
83 }
84 }
85 }
86 }
87 if (need_allocate)
88 {
89 hR->allocate(nullptr, true);
90 }
91}
92
93template <typename TK, typename TR>
94OperatorEXX<OperatorLCAO<TK, TR>>::OperatorEXX(
95 HS_Matrix_K<TK>* hsk_in,
96 HContainer<TR>* hR_in,
97 const UnitCell& ucell_in,
98 const K_Vectors& kv_in,
99 std::vector<std::map<int, std::map<TAC, RI::Tensor<double>>>>* Hexxd_in,
100 std::vector<std::map<int, std::map<TAC, RI::Tensor<std::complex<double>>>>>* Hexxc_in,
101 Add_Hexx_Type add_hexx_type_in,
102 const int istep,
103 int* two_level_step_in,
104 const bool restart_in)
105 : OperatorLCAO<TK, TR>(hsk_in, kv_in.kvec_d, hR_in), ucell(ucell_in), kv(kv_in), Hexxd(Hexxd_in), Hexxc(Hexxc_in),
106 add_hexx_type(add_hexx_type_in), istep(istep), two_level_step(two_level_step_in), restart(restart_in)
107{
108 ModuleBase::TITLE("OperatorEXX", "OperatorEXX");
109 this->cal_type = calculation_type::lcao_exx;
110 const Parallel_Orbitals* const pv = hR_in->get_paraV();
111
113 { // if nscf, read HexxR first and reallocate hR according to the read-in HexxR
114 auto file_name_list_csr = []() -> std::vector<std::string> {
115 std::vector<std::string> file_name_list;
116 for (int irank = 0; irank < PARAM.globalv.nproc; ++irank)
117 {
118 for (int is = 0; is < PARAM.inp.nspin; ++is)
119 {
120 file_name_list.push_back(PARAM.globalv.global_readin_dir + "HexxR" + std::to_string(irank) + "_"
121 + std::to_string(is) + ".csr");
122 }
123 }
124 return file_name_list;
125 };
126 auto file_name_list_cereal = []() -> std::vector<std::string> {
127 std::vector<std::string> file_name_list;
128 for (int irank = 0; irank < PARAM.globalv.nproc; ++irank)
129 {
130 file_name_list.push_back("HexxR_" + std::to_string(irank));
131 }
132 return file_name_list;
133 };
134 auto check_exist = [](const std::vector<std::string>& file_name_list) -> bool {
135 for (const std::string& file_name: file_name_list)
136 {
137 std::ifstream ifs(file_name);
138 if (!ifs.is_open())
139 {
140 return false;
141 }
142 }
143 return true;
144 };
145
146 std::cout << " Attention: The number of MPI processes must be strictly identical between SCF and NSCF when computing exact-exchange." << std::endl;
147 if (check_exist(file_name_list_csr()))
148 {
149 const std::string file_name_exx_csr
150 = PARAM.globalv.global_readin_dir + "HexxR" + std::to_string(PARAM.globalv.myrank);
151 // Read HexxR in CSR format
152 if (GlobalC::exx_info.info_ri.real_number)
153 {
154 ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd);
155 if (this->add_hexx_type == Add_Hexx_Type::R)
156 {
157 reallocate_hcontainer(*Hexxd, this->hR);
158 }
159 }
160 else
161 {
162 ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc);
163 if (this->add_hexx_type == Add_Hexx_Type::R)
164 {
165 reallocate_hcontainer(*Hexxc, this->hR);
166 }
167 }
168 }
169 else if (check_exist(file_name_list_cereal()))
170 {
171 // Read HexxR in binary format (old version)
172 const std::string file_name_exx_cereal
173 = PARAM.globalv.global_readin_dir + "HexxR_" + std::to_string(PARAM.globalv.myrank);
174 std::ifstream ifs(file_name_exx_cereal, std::ios::binary);
175 if (!ifs)
176 {
177 ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file < " + file_name_exx_cereal + " >.");
178 }
179 if (GlobalC::exx_info.info_ri.real_number)
180 {
181 ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxd);
182 if (this->add_hexx_type == Add_Hexx_Type::R)
183 {
184 reallocate_hcontainer(*Hexxd, this->hR);
185 }
186 }
187 else
188 {
189 ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxc);
190 if (this->add_hexx_type == Add_Hexx_Type::R)
191 {
192 reallocate_hcontainer(*Hexxc, this->hR);
193 }
194 }
195 }
196 else
197 {
198 ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file in " + PARAM.globalv.global_readin_dir);
199 }
200 this->use_cell_nearest = false;
201 }
202 else
203 { // if scf and Add_Hexx_Type::R, init cell_nearest and reallocate hR according to BvK cells
204 if (this->add_hexx_type == Add_Hexx_Type::R)
205 {
206 // if k points has no shift, use cell_nearest to reduce the memory cost
207 this->use_cell_nearest = (ModuleBase::Vector3<double>(std::fmod(this->kv.get_koffset(0), 1.0),
208 std::fmod(this->kv.get_koffset(1), 1.0),
209 std::fmod(this->kv.get_koffset(2), 1.0))
210 .norm()
211 < 1e-10);
212
213 const std::array<int, 3> Rs_period = {this->kv.nmp[0], this->kv.nmp[1], this->kv.nmp[2]};
214 if (this->use_cell_nearest)
215 {
216 this->cell_nearest = init_cell_nearest(ucell, Rs_period);
217 reallocate_hcontainer(ucell.nat, this->hR, Rs_period, &this->cell_nearest);
218 }
219 else
220 {
221 reallocate_hcontainer(ucell.nat, this->hR, Rs_period);
222 }
223 }
224
225 if (this->restart)
226 {
229 assert(this->two_level_step != nullptr);
230
231 if (this->add_hexx_type == Add_Hexx_Type::k)
232 {
234 if (std::is_same<TK, double>::value)
235 {
236 this->Hexxd_k_load.resize(this->kv.get_nks());
237 for (int ik = 0; ik < this->kv.get_nks(); ik++)
238 {
239 this->Hexxd_k_load[ik].resize(pv->get_local_size(), 0.0);
240 this->restart = GlobalC::restart.load_disk("Hexx",
241 ik,
242 pv->get_local_size(),
243 this->Hexxd_k_load[ik].data(),
244 false);
245 if (!this->restart)
246 {
247 break;
248 }
249 }
250 }
251 else
252 {
253 this->Hexxc_k_load.resize(this->kv.get_nks());
254 for (int ik = 0; ik < this->kv.get_nks(); ik++)
255 {
256 this->Hexxc_k_load[ik].resize(pv->get_local_size(), 0.0);
257 this->restart = GlobalC::restart.load_disk("Hexx",
258 ik,
259 pv->get_local_size(),
260 this->Hexxc_k_load[ik].data(),
261 false);
262 if (!this->restart)
263 {
264 break;
265 }
266 }
267 }
268 }
269 else if (this->add_hexx_type == Add_Hexx_Type::R)
270 {
271 // read in Hexx(R)
272 const std::string restart_HR_path
273 = GlobalC::restart.folder + "HexxR" + std::to_string(PARAM.globalv.myrank);
274 int all_exist = 1;
275 for (int is = 0; is < PARAM.inp.nspin; ++is)
276 {
277 std::ifstream ifs(restart_HR_path + "_" + std::to_string(is) + ".csr");
278 if (!ifs)
279 {
280 all_exist = 0;
281 break;
282 }
283 }
284 // Add MPI communication to synchronize all_exist across processes
285#ifdef __MPI
287#endif
288 if (all_exist)
289 {
290 // Read HexxR in CSR format
291 if (GlobalC::exx_info.info_ri.real_number)
292 {
293 ModuleIO::read_Hexxs_csr(restart_HR_path, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd);
294 }
295 else
296 {
297 ModuleIO::read_Hexxs_csr(restart_HR_path, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc);
298 }
299 }
300 else
301 {
302 // Read HexxR in binary format (old version)
303 const std::string restart_HR_path_cereal
304 = GlobalC::restart.folder + "HexxR_" + std::to_string(PARAM.globalv.myrank);
305 std::ifstream ifs(restart_HR_path_cereal, std::ios::binary);
306 int all_exist_cereal = ifs ? 1 : 0;
307#ifdef __MPI
308 Parallel_Reduce::reduce_min(all_exist_cereal);
309#endif
310 if (!all_exist_cereal)
311 {
312 // no HexxR file in CSR or binary format
313 this->restart = false;
314 }
315 else
316 {
317 if (GlobalC::exx_info.info_ri.real_number)
318 {
319 ModuleIO::read_Hexxs_cereal(restart_HR_path_cereal, *Hexxd);
320 }
321 else
322 {
323 ModuleIO::read_Hexxs_cereal(restart_HR_path_cereal, *Hexxc);
324 }
325 }
326 }
327 }
328
329 if (!this->restart)
330 {
331 std::cout << "WARNING: Hexx not found, restart from the non-exx loop." << std::endl
332 << "If the loaded charge density is EXX-solved, this may lead to poor convergence."
333 << std::endl;
334 }
336 }
337 }
338}
339
340template <typename TK, typename TR>
341void OperatorEXX<OperatorLCAO<TK, TR>>::contributeHR()
342{
343 ModuleBase::TITLE("OperatorEXX", "contributeHR");
344 // Peize Lin add 2016-12-03
345
346 // 1. For NSCF
347 if (PARAM.inp.calculation == "nscf")
348 {
349 // Do nothing here, allow the code to proceed and calculate EXX.
350 }
351 // 2. For the first ionic step of SCF, relaxation, or MD:
352 else if (this->istep == 0)
353 {
354 // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop)
355 bool in_gga_pre_loop = (this->two_level_step != nullptr && *this->two_level_step == 0);
356
357 // Check if a high-quality initial guess is missing (neither reading wavefunctions from a file nor restarting)
358 bool lacks_good_guess = (PARAM.inp.init_wfc != "file" && !this->restart);
359
360 // If in the pre-convergence loop and lacking a good initial guess, skip adding the EXX contribution
361 if (in_gga_pre_loop && lacks_good_guess)
362 {
363 return; // In the non-EXX loop, skip adding EXX contribution
364 }
365 }
366 // 3. For subsequent ionic steps (istep > 0), add EXX normally
367
368 if (this->add_hexx_type == Add_Hexx_Type::k)
369 {
370 return;
371 }
372
374 {
375 // add H(R) normally
376 if (GlobalC::exx_info.info_ri.real_number)
377 {
378 RI_2D_Comm::add_HexxR(this->current_spin,
379 GlobalC::exx_info.info_global.hybrid_alpha,
380 *this->Hexxd,
381 *this->hR->get_paraV(),
383 *this->hR,
384 this->use_cell_nearest ? &this->cell_nearest : nullptr);
385 }
386 else
387 {
388 RI_2D_Comm::add_HexxR(this->current_spin,
389 GlobalC::exx_info.info_global.hybrid_alpha,
390 *this->Hexxc,
391 *this->hR->get_paraV(),
393 *this->hR,
394 this->use_cell_nearest ? &this->cell_nearest : nullptr);
395 }
396 }
397 if (PARAM.inp.nspin == 2)
398 {
399 this->current_spin = 1 - this->current_spin;
400 }
401}
402
403template <typename TK, typename TR>
404void OperatorEXX<OperatorLCAO<TK, TR>>::contributeHk(int ik)
405{
406 ModuleBase::TITLE("OperatorEXX", "constributeHk");
407 // Peize Lin add 2016-12-03
408
409 // Taoni Bao add 2026-05-15
410 // In RT-TDDFT, contributeHk is used, but two_level_step is reset to 0 at each ionic step.
411 // In order to add EXX correctly in for istep > 0, this->istep == 0 is needed to avoid skipping EXX calculation.
412 // 1. For NSCF
413 if (PARAM.inp.calculation == "nscf")
414 {
415 // Do nothing here, allow the code to proceed and calculate EXX.
416 }
417 // 2. For the first ionic step:
418 else if (this->istep == 0)
419 {
420 // If EXX is once turned on (two_level_step > 0), let OperatorEXX remember this
421 if (this->two_level_step != nullptr && *this->two_level_step > 0)
422 {
423 this->initial_gga_done = true;
424 }
425
426 // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop)
427 bool in_gga_pre_loop = (this->two_level_step != nullptr && *this->two_level_step == 0);
428
429 // Check if a high-quality initial guess is missing
430 bool lacks_good_guess = (!this->restart);
431
432 // If in the pre-convergence loop and lacking a good initial guess, skip adding the EXX contribution
433 // Taoni Bao add 2026-05-18, only skip EXX if initial GGA loop is not done
434 // Fix RT-TDDFT EXX missing problem in the evolution
435 if (in_gga_pre_loop && lacks_good_guess && !this->initial_gga_done)
436 {
437 return; // In the non-EXX loop, skip adding EXX contribution
438 }
439 }
440 // 3. For subsequent ionic steps (istep > 0), add EXX normally
441
442 if (this->add_hexx_type == Add_Hexx_Type::R)
443 {
444 throw std::invalid_argument("Set Add_Hexx_Type::k to call OperatorEXX::contributeHk().");
445 }
446
448 {
449 if (this->restart && this->two_level_step != nullptr)
450 {
451 if (*this->two_level_step == 0)
452 {
453 this->add_loaded_Hexx(ik);
454 return;
455 }
456 else // clear loaded Hexx and release memory
457 {
458 if (this->Hexxd_k_load.size() > 0)
459 {
460 this->Hexxd_k_load.clear();
461 this->Hexxd_k_load.shrink_to_fit();
462 }
463 else if (this->Hexxc_k_load.size() > 0)
464 {
465 this->Hexxc_k_load.clear();
466 this->Hexxc_k_load.shrink_to_fit();
467 }
468 }
469 }
470 // cal H(k) from H(R) normally
471 if (PARAM.inp.esolver_type == "tddft" && PARAM.inp.td_stype == 2)
472 {
474 this->kv,
475 ik,
476 GlobalC::exx_info.info_global.hybrid_alpha,
477 *this->Hexxc,
478 *this->hR->get_paraV(),
480 this->hsk->get_hk());
481 }
482 else
483 {
484 if (GlobalC::exx_info.info_ri.real_number)
485 {
487 this->kv,
488 ik,
489 GlobalC::exx_info.info_global.hybrid_alpha,
490 *this->Hexxd,
491 *this->hR->get_paraV(),
492 this->hsk->get_hk());
493 }
494 else
495 {
497 this->kv,
498 ik,
499 GlobalC::exx_info.info_global.hybrid_alpha,
500 *this->Hexxc,
501 *this->hR->get_paraV(),
502 this->hsk->get_hk());
503 }
504 }
505 }
506}
507
508} // namespace hamilt
509#endif // __EXX
510#endif // OPEXXLCAO_HPP
Definition abfs-vector3_order.h:16
Definition klist.h:12
3 elements vector
Definition vector3.h:24
T x
Definition vector3.h:26
T norm(void) const
Get the norm of a Vector3.
Definition vector3.h:216
T y
Definition vector3.h:27
T z
Definition vector3.h:28
int64_t get_local_size() const
number of local matrix elements
Definition parallel_2d.h:39
Definition parallel_orbitals.h:9
const Input_para & inp
Definition parameter.h:26
const System_para & globalv
Definition parameter.h:30
std::string folder
Definition restart.h:30
Info_Load info_load
Definition restart.h:28
bool load_disk(const std::string label, const int index, const int size, T *data, const bool error_quit=true) const
Definition restart.h:42
static TD_info * td_vel_op
pointer to the only TD_info object itself
Definition mock_tdinfo.cpp:13
static ModuleBase::Vector3< double > cart_At
Store the vector potential for tddft calculation.
Definition mock_tdinfo.cpp:12
Definition unitcell.h:15
static int get_func_type()
Definition xc_functional.h:65
Exx_Info exx_info
Definition exx_info.cpp:8
Restart restart
Definition restart.cpp:47
int istep
Definition ions_move_basic.cpp:12
void WARNING_QUIT(const std::string &, const std::string &)
Combine the functions of WARNING and QUIT.
Definition test_delley.cpp:14
void TITLE(const std::string &class_name, const std::string &function_name, const bool disable)
Definition tool_title.cpp:18
void read_Hexxs_cereal(const std::string &file_name, std::vector< std::map< int, std::map< TAC, RI::Tensor< Tdata > > > > &Hexxs)
read Hexxs in cereal format
Definition restart_exx_csr.hpp:64
void read_Hexxs_csr(const std::string &file_name, const UnitCell &ucell, const int nspin, const int nbasis, std::vector< std::map< int, std::map< TAC, RI::Tensor< Tdata > > > > &Hexxs)
read Hexxs in CSR format
Definition restart_exx_csr.hpp:13
void reduce_min(T &v)
void add_Hexx_td(const UnitCell &ucell, const K_Vectors &kv, const int ik, const double alpha, const std::vector< std::map< TA, std::map< TAC, RI::Tensor< Tdata > > > > &Hs, const Parallel_Orbitals &pv, const ModuleBase::Vector3< double > &At, TK *hk)
Definition RI_2D_Comm.hpp:316
void add_HexxR(const int current_spin, const double alpha, const std::vector< std::map< TA, std::map< TAC, RI::Tensor< Tdata > > > > &Hs, const Parallel_Orbitals &pv, const int npol, hamilt::HContainer< TR > &HlocR, const RI::Cell_Nearest< int, int, 3, double, 3 > *const cell_nearest=nullptr)
Definition RI_2D_Comm.hpp:445
void add_Hexx(const UnitCell &ucell, const K_Vectors &kv, const int ik, const double alpha, const std::vector< std::map< TA, std::map< TAC, RI::Tensor< Tdata > > > > &Hs, const Parallel_Orbitals &pv, TK *hk)
Definition RI_2D_Comm.hpp:267
std::vector< std::array< Tcell, Ndim > > get_Born_von_Karmen_cells(const std::array< Tcell, Ndim > &Born_von_Karman_period)
Definition RI_Util.hpp:34
ModuleBase::Vector3< Tcell > array3_to_Vector3(const std::array< Tcell, 3 > &v)
Definition RI_Util.h:38
Definition hamilt.h:13
Parameter PARAM
Definition parameter.cpp:3
std::pair< int, TC > TAC
Definition ri_cv_io_test.cpp:10
bool cal_exx
Definition exx_info.h:14
Exx_Info_Global info_global
Definition exx_info.h:37
std::string calculation
Definition input_parameter.h:19
std::string init_wfc
"file","atomic","random"
Definition input_parameter.h:47
int nspin
LDA ; LSDA ; non-linear spin.
Definition input_parameter.h:88
int td_stype
type of space domain 0 : length gauge 1: velocity gauge
Definition input_parameter.h:309
std::string esolver_type
the energy solver: ksdft, sdft, ofdft, tddft, lj, dp
Definition input_parameter.h:22
bool load_H_finish
Definition restart.h:25
std::string global_readin_dir
global readin directory
Definition system_parameter.h:43
int npol
number of polarization
Definition system_parameter.h:52
int nlocal
total number of local basis.
Definition system_parameter.h:23
int myrank
Definition system_parameter.h:11
int nproc
Definition system_parameter.h:12