@@ -212,6 +212,40 @@ void ESolver_KS_LCAO<TK, TR>::before_scf(UnitCell& ucell, const int istep)
212212 rdmft_solver.update_ion (ucell, *(this ->pw_rho ), this ->locpp .vloc , this ->sf .strucFac );
213213 }
214214
215+ // 18) Manage subspace solver cache for MD/relax acceleration
216+ if (PARAM .inp .lcao_subspace_persistent && istep > 0 )
217+ {
218+ // Check atomic displacement
219+ double max_disp = 0.0 ;
220+ for (int iat = 0 ; iat < ucell.nat ; iat++)
221+ {
222+ const auto & tau = ucell.get_tau (iat);
223+ double dx = tau.x - this ->last_atom_positions_ [iat].x ;
224+ double dy = tau.y - this ->last_atom_positions_ [iat].y ;
225+ double dz = tau.z - this ->last_atom_positions_ [iat].z ;
226+ double disp = std::sqrt (dx*dx + dy*dy + dz*dz) * ucell.lat0 ;
227+ if (disp > max_disp) max_disp = disp;
228+ }
229+
230+ // Clear cache if displacement exceeds threshold or cache is invalid
231+ if (this ->subspace_solver_ &&
232+ (PARAM .inp .lcao_subspace_clear_thr > 0.0 &&
233+ max_disp > PARAM .inp .lcao_subspace_clear_thr ))
234+ {
235+ this ->subspace_solver_ ->clear_subspace ();
236+ GlobalV::ofs_running << " >> Subspace cache cleared: max atomic displacement = "
237+ << max_disp << " Bohr (threshold: "
238+ << PARAM .inp .lcao_subspace_clear_thr << " Bohr)" << std::endl;
239+ }
240+ }
241+
242+ // Save current atom positions for next step comparison
243+ this ->last_atom_positions_ .resize (ucell.nat );
244+ for (int iat = 0 ; iat < ucell.nat ; iat++)
245+ {
246+ this ->last_atom_positions_ [iat] = ucell.get_tau (iat);
247+ }
248+
215249 ModuleBase::timer::end (" ESolver_KS_LCAO" , " before_scf" );
216250 return ;
217251}
@@ -404,9 +438,31 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
404438 // 3) run Hsolver
405439 if (!skip_solve)
406440 {
407- hsolver::HSolverLCAO<TK > hsolver_lcao_obj (&(this ->pv ), PARAM .inp .ks_solver );
408- hsolver_lcao_obj.solve (static_cast <hamilt::Hamilt<TK >*>(this ->p_hamilt ), this ->psi [0 ], this ->pelec , *this ->dmat .dm ,
409- this ->chr , PARAM .inp .nspin , skip_charge);
441+ // Try subspace solver first (for SCF acceleration after first step)
442+ bool subspace_used = false ;
443+ if constexpr (std::is_same_v<TK , std::complex <double >>)
444+ {
445+ if (this ->subspace_solver_ && this ->subspace_solver_ ->has_subspace ())
446+ {
447+ this ->subspace_solver_ ->solve (
448+ static_cast <hamilt::Hamilt<TK >*>(this ->p_hamilt ),
449+ this ->psi [0 ],
450+ this ->pelec ,
451+ *this ->dmat .dm ,
452+ this ->chr ,
453+ PARAM .inp .nspin ,
454+ skip_charge);
455+ subspace_used = true ;
456+ }
457+ }
458+
459+ // Fall back to standard HSolverLCAO if subspace not available
460+ if (!subspace_used)
461+ {
462+ hsolver::HSolverLCAO<TK > hsolver_lcao_obj (&(this ->pv ), PARAM .inp .ks_solver );
463+ hsolver_lcao_obj.solve (static_cast <hamilt::Hamilt<TK >*>(this ->p_hamilt ), this ->psi [0 ], this ->pelec , *this ->dmat .dm ,
464+ this ->chr , PARAM .inp .nspin , skip_charge);
465+ }
410466 }
411467
412468 // 4) EXX
@@ -484,6 +540,32 @@ void ESolver_KS_LCAO<TK, TR>::iter_finish(UnitCell& ucell, const int istep, int&
484540 this ->pv , this ->gd , this ->psi , this ->chr , this ->p_chgmix ,
485541 hamilt_lcao, this ->orb_ , this ->deepks ,
486542 this ->exx_nao , iter, istep, conv_esolver, this ->scf_ene_thr );
543+
544+ // Update subspace cache after each SCF iteration (for next iteration acceleration)
545+ // First SCF step (istep=0, iter=1): full diagonalization already done by HSolverLCAO
546+ // -> update_subspace_cache() uses the converged wavefunctions to build initial cache
547+ // Subsequent SCF steps: subspace solver used, then cache updated with new wavefunctions
548+ if constexpr (std::is_same_v<TK , std::complex <double >>)
549+ {
550+ if (PARAM .inp .lcao_subspace_persistent )
551+ {
552+ if (!this ->subspace_solver_ )
553+ {
554+ this ->subspace_solver_ .reset (
555+ new hsolver::HSolverLCAOSubspace (&(this ->pv ), PARAM .inp .ks_solver ));
556+ this ->subspace_solver_ ->set_persistent (true );
557+ }
558+
559+ // Update subspace cache using current wavefunctions
560+ // lambda_ref is zero because we don't use DeltaSpin perturbation here
561+ std::vector<ModuleBase::Vector3<double >> lambda_ref (ucell.nat , {0.0 , 0.0 , 0.0 });
562+ this ->subspace_solver_ ->update_subspace_cache (
563+ static_cast <hamilt::Hamilt<TK >*>(this ->p_hamilt ),
564+ this ->psi [0 ],
565+ this ->pelec ,
566+ lambda_ref);
567+ }
568+ }
487569}
488570
489571template <typename TK , typename TR >
0 commit comments