@@ -607,32 +607,6 @@ void DiagoPPCG<T, Device>::lock_epairs(
607607 }
608608}
609609
610- // ---------------------------------------------------------------------------
611- // Compute the residual w_i = H|psi_i> - eps_i * S|psi_i> from the current
612- // (already updated) hpsi_/spsi_ and lock converged eigenpairs. Used on the
613- // block-update iterations where a full Rayleigh-Ritz rotation is skipped.
614- // ---------------------------------------------------------------------------
615- template <typename T, typename Device>
616- void DiagoPPCG<T, Device>::compute_residual_and_lock(
617- Real* eigenvalue,
618- std::vector<int >& active_cols,
619- const std::vector<double >& ethr_band)
620- {
621- set_zero (w_);
622- #ifdef _OPENMP
623- #pragma omp parallel for collapse(2) schedule(static) if (n_dim_ * n_band_ > ppcg_openmp_work_threshold)
624- #endif
625- for (int j = 0 ; j < n_band_; ++j)
626- {
627- for (int ig = 0 ; ig < n_dim_; ++ig)
628- {
629- w_[idx (ig, j, ld_psi_)] = hpsi_[idx (ig, j, ld_psi_)]
630- - spsi_[idx (ig, j, ld_psi_)] * eigenvalue[j];
631- }
632- }
633- lock_epairs (eval_prev_.data (), eigenvalue, ethr_band, active_cols);
634- }
635-
636610// ---------------------------------------------------------------------------
637611// Build K = V^H H V and M = V^H S V where V = [psi, w]
638612// ---------------------------------------------------------------------------
@@ -969,9 +943,13 @@ template <typename T, typename Device>
969943void DiagoPPCG<T, Device>::rayleigh_ritz(
970944 T* psi, Real* eigenvalue,
971945 std::vector<int >& active_cols,
972- const std::vector<double >& ethr_band,
973- bool rotate)
946+ const std::vector<double >& ethr_band)
974947{
948+ // Remember the eigenvalues of the previous step; convergence is measured
949+ // as the eigenvalue change between successive Rayleigh-Ritz steps.
950+ eval_prev_.resize (n_band_);
951+ std::copy (eigenvalue, eigenvalue + n_band_, eval_prev_.begin ());
952+
975953 gram (psi, hpsi_.data (), n_band_, n_band_, rr_hsub_, n_band_);
976954 gram (psi, spsi_.data (), n_band_, n_band_, rr_ssub_, n_band_);
977955
@@ -999,59 +977,56 @@ void DiagoPPCG<T, Device>::rayleigh_ritz(
999977
1000978 if (sygvd_ok)
1001979 {
1002- if (rotate)
1003- {
1004- const int sz = ld_psi_ * n_band_;
1005- std::copy (psi, psi + sz, rr_psi_.begin ());
1006- std::copy (spsi_.begin (), spsi_.end (), rr_spsi_.begin ());
1007- std::copy (hpsi_.begin (), hpsi_.end (), rr_hpsi_.begin ());
1008-
1009- std::fill (psi, psi + ld_psi_ * n_band_, T (0 ));
1010- set_zero (spsi_);
1011- set_zero (hpsi_);
1012-
1013- const T one = T (1 );
1014- const T zero = T (0 );
1015- ModuleBase::gemm_op<T, Device>()(' N' ,
1016- ' N' ,
1017- n_dim_,
1018- n_band_,
1019- n_band_,
1020- &one,
1021- rr_psi_.data (),
1022- ld_psi_,
1023- rr_hsub_.data (),
1024- n_band_,
1025- &zero,
1026- psi,
1027- ld_psi_);
1028- ModuleBase::gemm_op<T, Device>()(' N' ,
1029- ' N' ,
1030- n_dim_,
1031- n_band_,
1032- n_band_,
1033- &one,
1034- rr_spsi_.data (),
1035- ld_psi_,
1036- rr_hsub_.data (),
1037- n_band_,
1038- &zero,
1039- spsi_.data (),
1040- ld_psi_);
1041- ModuleBase::gemm_op<T, Device>()(' N' ,
1042- ' N' ,
1043- n_dim_,
1044- n_band_,
1045- n_band_,
1046- &one,
1047- rr_hpsi_.data (),
1048- ld_psi_,
1049- rr_hsub_.data (),
1050- n_band_,
1051- &zero,
1052- hpsi_.data (),
1053- ld_psi_);
1054- }
980+ const int sz = ld_psi_ * n_band_;
981+ std::copy (psi, psi + sz, rr_psi_.begin ());
982+ std::copy (spsi_.begin (), spsi_.end (), rr_spsi_.begin ());
983+ std::copy (hpsi_.begin (), hpsi_.end (), rr_hpsi_.begin ());
984+
985+ std::fill (psi, psi + ld_psi_ * n_band_, T (0 ));
986+ set_zero (spsi_);
987+ set_zero (hpsi_);
988+
989+ const T one = T (1 );
990+ const T zero = T (0 );
991+ ModuleBase::gemm_op<T, Device>()(' N' ,
992+ ' N' ,
993+ n_dim_,
994+ n_band_,
995+ n_band_,
996+ &one,
997+ rr_psi_.data (),
998+ ld_psi_,
999+ rr_hsub_.data (),
1000+ n_band_,
1001+ &zero,
1002+ psi,
1003+ ld_psi_);
1004+ ModuleBase::gemm_op<T, Device>()(' N' ,
1005+ ' N' ,
1006+ n_dim_,
1007+ n_band_,
1008+ n_band_,
1009+ &one,
1010+ rr_spsi_.data (),
1011+ ld_psi_,
1012+ rr_hsub_.data (),
1013+ n_band_,
1014+ &zero,
1015+ spsi_.data (),
1016+ ld_psi_);
1017+ ModuleBase::gemm_op<T, Device>()(' N' ,
1018+ ' N' ,
1019+ n_dim_,
1020+ n_band_,
1021+ n_band_,
1022+ &one,
1023+ rr_hpsi_.data (),
1024+ ld_psi_,
1025+ rr_hsub_.data (),
1026+ n_band_,
1027+ &zero,
1028+ hpsi_.data (),
1029+ ld_psi_);
10551030
10561031 for (int j = 0 ; j < n_band_; ++j)
10571032 {
@@ -1068,7 +1043,20 @@ void DiagoPPCG<T, Device>::rayleigh_ritz(
10681043 }
10691044
10701045 // Compute residual: w_i = H|psi_i> - eps_i * S|psi_i>
1071- compute_residual_and_lock (eigenvalue, active_cols, ethr_band);
1046+ set_zero (w_);
1047+ #ifdef _OPENMP
1048+ #pragma omp parallel for collapse(2) schedule(static) if (n_dim_ * n_band_ > ppcg_openmp_work_threshold)
1049+ #endif
1050+ for (int j = 0 ; j < n_band_; ++j)
1051+ {
1052+ for (int ig = 0 ; ig < n_dim_; ++ig)
1053+ {
1054+ w_[idx (ig, j, ld_psi_)] = hpsi_[idx (ig, j, ld_psi_)]
1055+ - spsi_[idx (ig, j, ld_psi_)] * eigenvalue[j];
1056+ }
1057+ }
1058+
1059+ lock_epairs (eval_prev_.data (), eigenvalue, ethr_band, active_cols);
10721060}
10731061
10741062} // namespace hsolver
@@ -1537,8 +1525,6 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
15371525 rr_hsub_.resize (ncol * ncol);
15381526 rr_ssub_.resize (ncol * ncol);
15391527 rr_eval_.resize (ncol);
1540- eval_prev_.resize (ncol);
1541- std::copy (eigenvalue_in, eigenvalue_in + ncol, eval_prev_.begin ());
15421528
15431529 std::vector<int > all_cols (ncol);
15441530 std::iota (all_cols.begin (), all_cols.end (), 0 );
@@ -1585,9 +1571,7 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
15851571 if (strategy_ == PpcgStrategy::BLOCK_SUBSPACE )
15861572 {
15871573 // Initialize with Rayleigh-Ritz.
1588- eval_prev_.resize (ncol);
1589- std::copy (eigenvalue_in, eigenvalue_in + ncol, eval_prev_.begin ());
1590- rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band, true );
1574+ rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band);
15911575 // Recompute to keep hpsi/spi consistent with rotated psi.
15921576 apply_h (hpsi_func, psi_in, hpsi_.data (), ncol);
15931577 apply_s_current (psi_in, spsi_.data (), ncol);
@@ -1608,11 +1592,6 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
16081592 const int nact = static_cast <int >(active_cols.size ());
16091593 const int nsb = std::max (1 , (nact + sbsize_ - 1 ) / sbsize_);
16101594
1611- // Save the previous eigenvalues so that the convergence check can
1612- // compare the eigenvalue change between successive iterations.
1613- eval_prev_.resize (ncol);
1614- std::copy (eigenvalue_in, eigenvalue_in + ncol, eval_prev_.begin ());
1615-
16161595 // Precondition the residual.
16171596 divide_by_preconditioner (active_cols, prec, w_);
16181597 copy_cols (w_.data (), active_cols, w_active);
@@ -1652,19 +1631,14 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
16521631 update_one_block (psi_in, cols, l, subspace);
16531632 }
16541633
1655- // Convergence check. The Ritz values are computed from a full
1656- // subspace diagonalization every iteration; the Ritz rotation (and
1657- // the H/S re-application it requires) is only done every rr_step_
1658- // iterations to keep the basis numerically clean, because the block
1659- // update already maintains a consistent H|psi>/S|psi>.
1660- const bool do_rr = (iter % rr_step_) == 0 ;
1661- rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band, do_rr);
1662- if (do_rr)
1663- {
1664- apply_h (hpsi_func, psi_in, hpsi_.data (), ncol);
1665- apply_s_current (psi_in, spsi_.data (), ncol);
1666- }
1667- record_residual (iter, do_rr ? " rayleigh_ritz" : " block_update" );
1634+ // Rayleigh-Ritz after each block update keeps the global subspace
1635+ // synchronized with the updated active vectors. The block update
1636+ // can otherwise drift into an ill-conditioned basis before the next
1637+ // Ritz rotation.
1638+ rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band);
1639+ apply_h (hpsi_func, psi_in, hpsi_.data (), ncol);
1640+ apply_s_current (psi_in, spsi_.data (), ncol);
1641+ record_residual (iter, " rayleigh_ritz" );
16681642
16691643 ++iter;
16701644 }
@@ -1680,7 +1654,7 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
16801654 // Diagonal Rayleigh quotients are poor approximations for random
16811655 // initial guesses; starting the CG loop with them produces wrong
16821656 // gradients that drive the search toward high-energy bands.
1683- rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band, true );
1657+ rayleigh_ritz (psi_in, eigenvalue_in, active_cols, ethr_band);
16841658 apply_h (hpsi_func, psi_in, hpsi_.data (), ncol);
16851659 apply_s_current (psi_in, spsi_.data (), ncol);
16861660 record_residual (0 , " initial_rr" );
@@ -1725,7 +1699,7 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
17251699 apply_s_current (psi_in, spsi_.data (), ncol);
17261700
17271701 std::vector<int > dummy_active;
1728- rayleigh_ritz (psi_in, eigenvalue_in, dummy_active, ethr_band, true );
1702+ rayleigh_ritz (psi_in, eigenvalue_in, dummy_active, ethr_band);
17291703
17301704 // Sync hpsi/spi to the rotated wavefunctions.
17311705 apply_h (hpsi_func, psi_in, hpsi_.data (), ncol);
0 commit comments