Skip to content

Commit a238aed

Browse files
committed
Reduce PPCG projection reductions
1 parent 7e2c8b5 commit a238aed

4 files changed

Lines changed: 100 additions & 54 deletions

File tree

source/source_hsolver/ppcg/diago_ppcg_cg.hpp

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,24 @@ void DiagoPPCG<T, Device>::orth_gradient(
3737
const T* psi, const T* spsi,
3838
std::vector<T>& grad) const
3939
{
40+
std::vector<T> coeff(n_band_ * n_band_, T(0));
41+
gram(psi, grad.data(), n_band_, n_band_, coeff, n_band_);
42+
43+
#ifdef _OPENMP
44+
#pragma omp parallel for schedule(static) if (n_dim_ * n_band_ > 4096)
45+
#endif
4046
for (int j = 0; j < n_band_; ++j)
4147
{
4248
for (int i = 0; i < n_band_; ++i)
4349
{
44-
// Full complex inner product <psi_i | grad_j>
45-
const T* pi = psi + i * ld_psi_;
46-
const T* gj = grad.data() + j * ld_psi_;
47-
const T coeff = complex_dot(pi, gj);
48-
if (std::abs(coeff) <= std::numeric_limits<Real>::epsilon())
50+
const T cproj = coeff[i + j * n_band_];
51+
if (std::abs(cproj) <= std::numeric_limits<Real>::epsilon())
4952
continue;
5053
// grad_j -= S|psi_i> * coeff
5154
const T* si = spsi + i * ld_psi_;
5255
T* gj_out = grad.data() + j * ld_psi_;
5356
for (int ig = 0; ig < n_dim_; ++ig)
54-
gj_out[ig] -= si[ig] * coeff;
57+
gj_out[ig] -= si[ig] * cproj;
5558
}
5659
}
5760
}
@@ -163,6 +166,58 @@ void DiagoPPCG<T, Device>::line_minimize(
163166
const T* p, const T* hp, const T* sp,
164167
int ncol) const
165168
{
169+
std::vector<double> h_ii_all(ncol, 0.0);
170+
std::vector<double> s_ii_all(ncol, 0.0);
171+
std::vector<double> h_pp_all(ncol, 0.0);
172+
std::vector<double> s_pp_all(ncol, 0.0);
173+
std::vector<T> h_ip_all(ncol, T(0));
174+
std::vector<T> s_ip_all(ncol, T(0));
175+
176+
#ifdef _OPENMP
177+
#pragma omp parallel for schedule(static) if (n_dim_ * ncol > 4096)
178+
#endif
179+
for (int j = 0; j < ncol; ++j)
180+
{
181+
const int off = j * ld_psi_;
182+
const T* pj = psi + off;
183+
const T* hj = hpsi + off;
184+
const T* sj = spsi + off;
185+
const T* pp = p + off;
186+
const T* hpp = hp + off;
187+
const T* spp = sp + off;
188+
189+
Real h_ii = 0;
190+
Real s_ii = 0;
191+
Real h_pp = 0;
192+
Real s_pp = 0;
193+
T h_ip = T(0);
194+
T s_ip = T(0);
195+
196+
for (int ig = 0; ig < n_dim_; ++ig)
197+
{
198+
h_ii += static_cast<Real>(std::real(std::conj(pj[ig]) * hj[ig]));
199+
s_ii += static_cast<Real>(std::real(std::conj(pj[ig]) * sj[ig]));
200+
h_ip += std::conj(pj[ig]) * hpp[ig];
201+
s_ip += std::conj(pj[ig]) * spp[ig];
202+
h_pp += static_cast<Real>(std::real(std::conj(pp[ig]) * hpp[ig]));
203+
s_pp += static_cast<Real>(std::real(std::conj(pp[ig]) * spp[ig]));
204+
}
205+
206+
h_ii_all[j] = static_cast<double>(h_ii);
207+
s_ii_all[j] = static_cast<double>(s_ii);
208+
h_ip_all[j] = h_ip;
209+
s_ip_all[j] = s_ip;
210+
h_pp_all[j] = static_cast<double>(h_pp);
211+
s_pp_all[j] = static_cast<double>(s_pp);
212+
}
213+
214+
reduce_pool_if_mpi_ready(h_ii_all.data(), ncol);
215+
reduce_pool_if_mpi_ready(s_ii_all.data(), ncol);
216+
reduce_pool_if_mpi_ready(h_ip_all.data(), ncol);
217+
reduce_pool_if_mpi_ready(s_ip_all.data(), ncol);
218+
reduce_pool_if_mpi_ready(h_pp_all.data(), ncol);
219+
reduce_pool_if_mpi_ready(s_pp_all.data(), ncol);
220+
166221
for (int j = 0; j < ncol; ++j)
167222
{
168223
const int off = j * ld_psi_;
@@ -173,12 +228,12 @@ void DiagoPPCG<T, Device>::line_minimize(
173228
const T* hpp = hp + off;
174229
const T* spp = sp + off;
175230

176-
Real h_ii = gamma_dot(pj, hj);
177-
Real s_ii = gamma_dot(pj, sj);
178-
const T h_ip_c = complex_dot(pj, hpp);
179-
const T s_ip_c = complex_dot(pj, spp);
180-
Real h_pp = gamma_dot(pp, hpp);
181-
Real s_pp = gamma_dot(pp, spp);
231+
Real h_ii = static_cast<Real>(h_ii_all[j]);
232+
Real s_ii = static_cast<Real>(s_ii_all[j]);
233+
const T h_ip_c = h_ip_all[j];
234+
const T s_ip_c = s_ip_all[j];
235+
Real h_pp = static_cast<Real>(h_pp_all[j]);
236+
Real s_pp = static_cast<Real>(s_pp_all[j]);
182237

183238
// Rotate the search direction so the first-order Rayleigh quotient
184239
// derivative is real. The scalar alpha solve below stays unchanged for
@@ -269,11 +324,8 @@ void DiagoPPCG<T, Device>::orth_cholesky(
269324
std::vector<T> spsi_orig(spsi, spsi + ld_psi_ * ncol);
270325

271326
// Gram matrix of S-orthonormality: J_{ij} = <psi_i | S | psi_j>
272-
std::vector<T> gram_s(ncol * ncol, T(0));
273-
for (int j = 0; j < ncol; ++j)
274-
for (int i = 0; i < ncol; ++i)
275-
gram_s[i + j * ncol] = complex_dot(psi + i * ld_psi_,
276-
spsi + j * ld_psi_);
327+
std::vector<T> gram_s;
328+
gram(psi, spsi, ncol, ncol, gram_s, ncol);
277329

278330
bool cholesky_ok = false;
279331
try

source/source_hsolver/ppcg/diago_ppcg_diag.hpp

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,8 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
224224
// so the Ritz values are exact for this subspace.
225225
std::vector<T> h_sub(ncol * ncol, T(0));
226226
std::vector<T> s_sub(ncol * ncol, T(0));
227-
for (int jj = 0; jj < ncol; ++jj)
228-
{
229-
for (int ii = 0; ii < ncol; ++ii)
230-
{
231-
h_sub[ii + jj * ncol]
232-
= complex_dot(psi_in + ii * ld_psi_,
233-
hpsi_.data() + jj * ld_psi_);
234-
s_sub[ii + jj * ncol]
235-
= complex_dot(psi_in + ii * ld_psi_,
236-
spsi_.data() + jj * ld_psi_);
237-
}
238-
}
227+
gram(psi_in, hpsi_.data(), ncol, ncol, h_sub, ncol);
228+
gram(psi_in, spsi_.data(), ncol, ncol, s_sub, ncol);
239229

240230
std::vector<Real> eval_cg(ncol, static_cast<Real>(0));
241231
try
@@ -248,18 +238,8 @@ double DiagoPPCG<T, Device>::diag(const HPsiFunc& hpsi_func,
248238
{
249239
// Fallback: diagonal Rayleigh quotients.
250240
// h_sub and s_sub may be corrupted by sygvd; re-form them.
251-
for (int jj = 0; jj < ncol; ++jj)
252-
{
253-
for (int ii = 0; ii < ncol; ++ii)
254-
{
255-
h_sub[ii + jj * ncol]
256-
= complex_dot(psi_in + ii * ld_psi_,
257-
hpsi_.data() + jj * ld_psi_);
258-
s_sub[ii + jj * ncol]
259-
= complex_dot(psi_in + ii * ld_psi_,
260-
spsi_.data() + jj * ld_psi_);
261-
}
262-
}
241+
gram(psi_in, hpsi_.data(), ncol, ncol, h_sub, ncol);
242+
gram(psi_in, spsi_.data(), ncol, ncol, s_sub, ncol);
263243
for (int ii = 0; ii < ncol; ++ii)
264244
eval_cg[ii] =
265245
static_cast<Real>(std::real(h_sub[ii + ii * ncol]))

source/source_hsolver/ppcg/diago_ppcg_ops.hpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,23 +194,36 @@ void DiagoPPCG<T, Device>::project_against(
194194
if (basis_cols.empty() || x_cols.empty())
195195
return;
196196

197-
for (const int c : x_cols)
197+
std::vector<T> basis_l;
198+
std::vector<T> sx_l;
199+
copy_cols(basis, basis_cols, basis_l);
200+
copy_cols(sx.data(), x_cols, sx_l);
201+
202+
const int nbasis = static_cast<int>(basis_cols.size());
203+
const int nx = static_cast<int>(x_cols.size());
204+
std::vector<T> coeff(nbasis * nx, T(0));
205+
gram(basis_l.data(), sx_l.data(), nbasis, nx, coeff, nbasis);
206+
207+
#ifdef _OPENMP
208+
#pragma omp parallel for schedule(static) if (n_dim_ * nx > 4096)
209+
#endif
210+
for (int jc = 0; jc < nx; ++jc)
198211
{
199-
for (const int bc : basis_cols)
212+
const int c = x_cols[jc];
213+
T* xc = x.data() + c * ld_psi_;
214+
T* sxc = sx.data() + c * ld_psi_;
215+
for (int ib = 0; ib < nbasis; ++ib)
200216
{
201-
// Full complex inner product <basis_bc | sx_c>
202-
const T* bb = basis + bc * ld_psi_;
203-
const T* sc = sx.data() + c * ld_psi_;
204-
const T coeff = complex_dot(bb, sc);
205-
if (std::abs(coeff) <= std::numeric_limits<Real>::epsilon())
217+
const int bc = basis_cols[ib];
218+
const T cproj = coeff[ib + jc * nbasis];
219+
if (std::abs(cproj) <= std::numeric_limits<Real>::epsilon())
206220
continue;
221+
const T* bb = basis + bc * ld_psi_;
207222
const T* sb = sbasis + bc * ld_psi_;
208-
T* xc = x.data() + c * ld_psi_;
209-
T* sxc = sx.data() + c * ld_psi_;
210223
for (int ig = 0; ig < n_dim_; ++ig)
211224
{
212-
xc[ig] -= bb[ig] * coeff;
213-
sxc[ig] -= sb[ig] * coeff;
225+
xc[ig] -= bb[ig] * cproj;
226+
sxc[ig] -= sb[ig] * cproj;
214227
}
215228
}
216229
}

source/source_hsolver/ppcg/diago_ppcg_orth.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ bool DiagoPPCG<T, Device>::is_s_orthonormal(
3232
{
3333
const Real orth_tol = static_cast<Real>(10)
3434
* std::sqrt(std::numeric_limits<Real>::epsilon());
35+
std::vector<T> gram_s;
36+
gram(psi, spsi, ncol, ncol, gram_s, ncol);
3537
for (int j = 0; j < ncol; ++j)
3638
{
3739
for (int i = 0; i < ncol; ++i)
3840
{
39-
const T sij = complex_dot(psi + i * ld_psi_,
40-
spsi + j * ld_psi_);
41+
const T sij = gram_s[i + j * ncol];
4142
const T target = (i == j) ? T(1) : T(0);
4243
if (std::abs(sij - target) > orth_tol)
4344
return false;

0 commit comments

Comments
 (0)