99#include " source_hamilt/module_hcontainer/read_hcontainer.h"
1010#include " source_lcao/module_ri/exx_lri_interface.h"
1111#include " source_lcao/module_ri/ri_2d_comm.h"
12- #include " source_lcao/module_rt/td_info.h"
1312
1413namespace hamilt
1514{
@@ -312,11 +311,15 @@ OperatorEXX<OperatorLCAO<TK, TR>>::OperatorEXX(HS_Matrix_K<TK>* hsk_in,
312311 if (this ->add_hexx_type == Add_Hexx_Type::R)
313312 {
314313 // if k points has no shift, use cell_nearest to reduce the memory cost
315- this ->use_cell_nearest = (ModuleBase::Vector3<double >(std::fmod (this ->kv .get_koffset (0 ), 1.0 ),
316- std::fmod (this ->kv .get_koffset (1 ), 1.0 ),
317- std::fmod (this ->kv .get_koffset (2 ), 1.0 ))
318- .norm ()
319- < 1e-10 );
314+ // In the hybrid gauge, BvK-equivalent cells can carry different
315+ // finite-field phases, so preserve the original cell indices.
316+ const bool hybrid_gauge_rt = PARAM .inp .esolver_type == " tddft" && PARAM .inp .td_stype == 2 ;
317+ this ->use_cell_nearest = !hybrid_gauge_rt
318+ && (ModuleBase::Vector3<double >(std::fmod (this ->kv .get_koffset (0 ), 1.0 ),
319+ std::fmod (this ->kv .get_koffset (1 ), 1.0 ),
320+ std::fmod (this ->kv .get_koffset (2 ), 1.0 ))
321+ .norm ()
322+ < 1e-10 );
320323
321324 const std::array<int , 3 > Rs_period = {this ->kv .nmp [0 ], this ->kv .nmp [1 ], this ->kv .nmp [2 ]};
322325 if (this ->use_cell_nearest )
@@ -460,14 +463,23 @@ void OperatorEXX<OperatorLCAO<TK, TR>>::contributeHR()
460463 const int two_level_step
461464 = exx_info_ptr->info_ri .real_number ? this ->exd ->get_two_level_step () : this ->exc ->get_two_level_step ();
462465
466+ // Remember that the initial GGA-only stage has completed. In
467+ // RT-TDDFT (and in subsequent ionic steps) LibRI may reset
468+ // two_level_step to zero; without this persistent state the HR path
469+ // would incorrectly skip EXX again.
470+ if (two_level_step > 0 )
471+ {
472+ this ->initial_gga_done = true ;
473+ }
474+
463475 // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop)
464476 bool in_gga_pre_loop = (two_level_step == 0 );
465477
466478 // Check if a high-quality initial guess is missing (neither reading wavefunctions from a file nor restarting)
467479 bool lacks_good_guess = (PARAM .inp .init_wfc != " file" && !this ->restart );
468480
469481 // If in the pre-convergence loop and lacking a good initial guess, skip adding the EXX contribution
470- if (in_gga_pre_loop && lacks_good_guess)
482+ if (in_gga_pre_loop && lacks_good_guess && ! this -> initial_gga_done )
471483 {
472484 return ; // In the non-EXX loop, skip adding EXX contribution
473485 }
@@ -513,52 +525,25 @@ template <typename TK, typename TR>
513525void OperatorEXX<OperatorLCAO<TK , TR >>::contributeHk(int ik)
514526{
515527 ModuleBase::TITLE (" OperatorEXX" , " constributeHk" );
516- const bool has_workflow = exx_info_ptr->info_ri .real_number ? (this ->exd != nullptr ) : (this ->exc != nullptr );
517- int two_level_step = 0 ;
518- if (has_workflow)
519- {
520- two_level_step
521- = exx_info_ptr->info_ri .real_number ? this ->exd ->get_two_level_step () : this ->exc ->get_two_level_step ();
522- }
523-
524- // Peize Lin add 2016-12-03
525528
526- // Taoni Bao add 2026-05-15
527- // In RT-TDDFT, contributeHk is used, but two_level_step is reset to 0 at each ionic step.
528- // In order to add EXX correctly in for istep > 0, this->istep == 0 is needed to avoid skipping EXX calculation.
529- // 1. For NSCF
530- if (PARAM .inp .calculation == " nscf" || !has_workflow)
529+ // The main LCAO path stores EXX in H(R) and lets the final base operator
530+ // fold H(R) into H(k). Keep this override only for one-shot k-space EXX
531+ // operators used by write_Vxc and RDMFT.
532+ if (this ->add_hexx_type == Add_Hexx_Type::R)
531533 {
532- // Do nothing here, allow the code to proceed and calculate EXX.
534+ return ;
533535 }
534- // 2. For the first ionic step:
535- else if (this ->istep == 0 )
536- {
537- // If EXX is once turned on (two_level_step > 0), let OperatorEXX remember this
538- if (two_level_step > 0 )
539- {
540- this ->initial_gga_done = true ;
541- }
542536
543- // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop)
544- bool in_gga_pre_loop = (two_level_step == 0 );
545-
546- // Check if a high-quality initial guess is missing
547- bool lacks_good_guess = (!this ->restart );
548-
549- // If in the pre-convergence loop and lacking a good initial guess, skip adding the EXX contribution
550- // Taoni Bao add 2026-05-18, only skip EXX if initial GGA loop is not done
551- // Fix RT-TDDFT EXX missing problem in the evolution
552- if (in_gga_pre_loop && lacks_good_guess && !this ->initial_gga_done )
553- {
554- return ; // In the non-EXX loop, skip adding EXX contribution
555- }
537+ // The restart path may still use a full EXX workflow. For one-shot
538+ // operators exd/exc are null and the value remains zero.
539+ int two_level_step = 0 ;
540+ if (exx_info_ptr->info_ri .real_number && this ->exd != nullptr )
541+ {
542+ two_level_step = this ->exd ->get_two_level_step ();
556543 }
557- // 3. For subsequent ionic steps (istep > 0), add EXX normally
558-
559- if (this ->add_hexx_type == Add_Hexx_Type::R)
544+ else if (!exx_info_ptr->info_ri .real_number && this ->exc != nullptr )
560545 {
561- OperatorLCAO< TK , TR >:: contributeHk (ik );
546+ two_level_step = this -> exc -> get_two_level_step ( );
562547 }
563548
564549 if (XC_Functional::get_func_type () == 4 || XC_Functional::get_func_type () == 5 )
@@ -584,41 +569,25 @@ void OperatorEXX<OperatorLCAO<TK, TR>>::contributeHk(int ik)
584569 }
585570 }
586571 }
587- // cal H(k) from H(R) normally
588- if (PARAM .inp .esolver_type == " tddft" && PARAM .inp .td_stype == 2 )
572+ if (exx_info_ptr->info_ri .real_number )
589573 {
590- RI_2D_Comm::add_Hexx_td (ucell,
591- this ->kv ,
592- ik,
593- exx_info_ptr->info_global .hybrid_alpha ,
594- *this ->Hexxc ,
595- *this ->hR ->get_paraV (),
596- TD_info::td_vel_op->cart_At ,
597- TD_info::td_vel_op->get_phase_hybrid (),
598- this ->hsk ->get_hk ());
574+ RI_2D_Comm::add_Hexx (ucell,
575+ this ->kv ,
576+ ik,
577+ exx_info_ptr->info_global .hybrid_alpha ,
578+ *this ->Hexxd ,
579+ *this ->hR ->get_paraV (),
580+ this ->hsk ->get_hk ());
599581 }
600582 else
601583 {
602- if (exx_info_ptr->info_ri .real_number )
603- {
604- RI_2D_Comm::add_Hexx (ucell,
605- this ->kv ,
606- ik,
607- exx_info_ptr->info_global .hybrid_alpha ,
608- *this ->Hexxd ,
609- *this ->hR ->get_paraV (),
610- this ->hsk ->get_hk ());
611- }
612- else
613- {
614- RI_2D_Comm::add_Hexx (ucell,
615- this ->kv ,
616- ik,
617- exx_info_ptr->info_global .hybrid_alpha ,
618- *this ->Hexxc ,
619- *this ->hR ->get_paraV (),
620- this ->hsk ->get_hk ());
621- }
584+ RI_2D_Comm::add_Hexx (ucell,
585+ this ->kv ,
586+ ik,
587+ exx_info_ptr->info_global .hybrid_alpha ,
588+ *this ->Hexxc ,
589+ *this ->hR ->get_paraV (),
590+ this ->hsk ->get_hk ());
622591 }
623592 }
624593}
@@ -748,4 +717,4 @@ template void reallocate_hcontainer<std::complex<double>>(
748717} // namespace hamilt
749718
750719// End content migrated from op_exx_lcao.hpp
751- #endif
720+ #endif
0 commit comments