Skip to content

Commit 5c47e1a

Browse files
committed
Add pw_diag_rr_step to decouple the PPCG Rayleigh-Ritz interval from the block size
1 parent b08abd6 commit 5c47e1a

9 files changed

Lines changed: 63 additions & 9 deletions

File tree

docs/advanced/input_files/input-main.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
- [use\_k\_continuity](#use_k_continuity)
6767
- [pw\_diag\_nmax](#pw_diag_nmax)
6868
- [pw\_diag\_ndim](#pw_diag_ndim)
69+
- [pw\_diag\_rr\_step](#pw_diag_rr_step)
6970
- [diago\_cg\_prec](#diago_cg_prec)
7071
- [Numerical atomic orbitals related variables](#numerical-atomic-orbitals-related-variables)
7172
- [lmaxmax](#lmaxmax)
@@ -1085,9 +1086,15 @@
10851086

10861087
- **Type**: Integer
10871088
- **Availability**: *[`basis_type`](#basis_type)==pw and [`ks_solver`](#ks_solver) in [dav, dav_subspace, ppcg]*
1088-
- **Description**: Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the PPCG block size/Rayleigh-Ritz interval for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.
1089+
- **Description**: Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the block size for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.
10891090
- **Default**: 4
10901091

1092+
### pw_diag_rr_step
1093+
1094+
- **Type**: Integer
1095+
- **Availability**: *[`basis_type`](#basis_type)==pw and [`ks_solver`](#ks_solver) == ppcg*- **Description**: Only useful when you use ks_solver = ppcg. It controls how often (in subspace iterations) H and S are re-applied to reset the accumulated rounding drift after the Rayleigh-Ritz rotation. A larger value reduces the number of H/S applications and thus the wall time without changing the iteration count in well-conditioned cases; a smaller value is more robust against rounding drift in ill-conditioned problems.
1096+
- **Default**: 16
1097+
10911098
### diago_cg_prec
10921099

10931100
- **Type**: Integer

docs/parameters.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,10 +1009,18 @@ parameters:
10091009
category: Plane wave related variables
10101010
type: Integer
10111011
description: |
1012-
Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the PPCG block size/Rayleigh-Ritz interval for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.
1012+
Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the block size for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.
10131013
default_value: "4"
10141014
unit: ""
10151015
availability: "basis_type==pw and ks_solver in [dav, dav_subspace, ppcg]"
1016+
- name: pw_diag_rr_step
1017+
category: Plane wave related variables
1018+
type: Integer
1019+
description: |
1020+
Only useful when you use ks_solver = ppcg. It controls how often (in subspace iterations) H and S are re-applied to reset the accumulated rounding drift after the Rayleigh-Ritz rotation. A larger value reduces the number of H/S applications and thus the wall time without changing the iteration count in well-conditioned cases; a smaller value is more robust against rounding drift in ill-conditioned problems.
1021+
default_value: "16"
1022+
unit: ""
1023+
availability: "basis_type==pw and ks_solver==ppcg"
10161024
- name: diago_cg_prec
10171025
category: Plane wave related variables
10181026
type: Integer

source/source_hsolver/diago_iter_assist.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class DiagoIterAssist
2222
static Real PW_DIAG_THR;
2323
static int PW_DIAG_NMAX;
2424
static int PW_DIAG_NDIM;
25+
static int PW_DIAG_RR_STEP;
2526

2627
static Real LCAO_DIAG_THR;
2728
static int LCAO_DIAG_NMAX;
@@ -161,6 +162,9 @@ int DiagoIterAssist<T, Device>::PW_DIAG_NMAX = 30;
161162
template <typename T, typename Device>
162163
int DiagoIterAssist<T, Device>::PW_DIAG_NDIM = 4;
163164

165+
template <typename T, typename Device>
166+
int DiagoIterAssist<T, Device>::PW_DIAG_RR_STEP = 16;
167+
164168
template <typename T, typename Device>
165169
typename DiagoIterAssist<T, Device>::Real DiagoIterAssist<T, Device>::PW_DIAG_THR = 1.0e-2;
166170

source/source_hsolver/diago_params.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ void setup_diago_params_pw(const int istep,
1616
DiagoIterAssist<T, Device>::SCF_ITER = iter;
1717
DiagoIterAssist<T, Device>::PW_DIAG_THR = ethr;
1818
DiagoIterAssist<T, Device>::PW_DIAG_NDIM = inp.pw_diag_ndim;
19+
DiagoIterAssist<T, Device>::PW_DIAG_RR_STEP = inp.pw_diag_rr_step;
1920

2021
if (inp.calculation != "nscf")
2122
{
@@ -43,6 +44,7 @@ void setup_diago_params_sdft(const int istep,
4344
DiagoIterAssist<T, Device>::PW_DIAG_THR = ethr;
4445
DiagoIterAssist<T, Device>::PW_DIAG_NMAX = inp.pw_diag_nmax;
4546
DiagoIterAssist<T, Device>::PW_DIAG_NDIM = inp.pw_diag_ndim;
47+
DiagoIterAssist<T, Device>::PW_DIAG_RR_STEP = inp.pw_diag_rr_step;
4648
}
4749

4850
/// Template instantiation for CPU

source/source_hsolver/hsolver_pw.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ double run_ppcg_pw(const HPsiFunc& hpsi_func,
4040
const double diag_thr,
4141
const int diag_iter_max,
4242
const int pw_diag_ndim,
43+
const int rr_step,
4344
const bool gamma_only,
4445
std::true_type)
4546
{
4647
const int sbsize = std::max(1, std::min(nband, pw_diag_ndim));
47-
const int rr_step = std::max(1, pw_diag_ndim);
48+
const int rr_step_safe = std::max(1, rr_step);
4849

4950
DiagoPPCG<T, Device> ppcg(Real(diag_thr),
5051
diag_iter_max,
5152
sbsize,
52-
rr_step,
53+
rr_step_safe,
5354
gamma_only,
5455
PpcgStrategy::BLOCK_SUBSPACE);
5556

@@ -77,11 +78,12 @@ double run_ppcg_pw(const HPsiFunc& hpsi_func,
7778
const double diag_thr,
7879
const int diag_iter_max,
7980
const int pw_diag_ndim,
81+
const int rr_step,
8082
const bool gamma_only,
8183
std::false_type)
8284
{
8385
const int sbsize = std::max(1, std::min(nband, pw_diag_ndim));
84-
const int rr_step = std::max(1, pw_diag_ndim);
86+
const int rr_step_safe = std::max(1, rr_step);
8587
const int nelem = ld_psi * nband;
8688

8789
// Transitional GPU path: keep PPCG's control logic and small dense solves
@@ -128,7 +130,7 @@ double run_ppcg_pw(const HPsiFunc& hpsi_func,
128130
DiagoPPCG<T, base_device::DEVICE_CPU> ppcg(Real(diag_thr),
129131
diag_iter_max,
130132
sbsize,
131-
rr_step,
133+
rr_step_safe,
132134
gamma_only,
133135
PpcgStrategy::BLOCK_SUBSPACE);
134136
const double avg_iter = ppcg.diag(bridge_hpsi,
@@ -518,6 +520,7 @@ void HSolverPW<T, Device>::hamiltSolvePsiK(hamilt::Hamilt<T, Device>* hm,
518520
this->diag_thr,
519521
this->diag_iter_max,
520522
DiagoIterAssist<T, Device>::PW_DIAG_NDIM,
523+
DiagoIterAssist<T, Device>::PW_DIAG_RR_STEP,
521524
this->wfc_basis->gamma_only,
522525
std::is_same<Device, base_device::DEVICE_CPU>());
523526
}

source/source_hsolver/test/diago_compare_test.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
using T = std::complex<double>;
4141
using Real = double;
4242

43+
// Optional PPCG parameter overrides (set from argv) for exploring the block
44+
// size (sbsize) and Rayleigh-Ritz frequency (rr_step). A negative value keeps
45+
// the default used by the comparison benchmark (sbsize = nband, rr_step = 16).
46+
static int g_sbsize = -1;
47+
static int g_rr_step = -1;
48+
4349
// Total heap memory currently allocated (bytes). Used to compare the peak
4450
// working memory of the solvers: PPCG keeps a bounded subspace, while
4551
// Davidson grows its basis with the number of iterations.
@@ -217,7 +223,9 @@ static Result run_ppcg(const std::vector<T>& H, int n, int nband, const std::vec
217223
std::vector<T> psi = psi0;
218224
std::vector<Real> eval(nband, 0.0);
219225
long mem0 = heap_bytes();
220-
hsolver::DiagoPPCG<T, hsolver::base_device::DEVICE_CPU> solver(1e-8, 500, nband, std::min(nband, 4), false,
226+
const int sbsize = (g_sbsize > 0) ? g_sbsize : nband;
227+
const int rr_step = (g_rr_step > 0) ? g_rr_step : 16;
228+
hsolver::DiagoPPCG<T, hsolver::base_device::DEVICE_CPU> solver(1e-8, 500, sbsize, rr_step, false,
221229
hsolver::PpcgStrategy::BLOCK_SUBSPACE);
222230
auto h_op = [&H, n](T* in, T* out, int ld, int nc) { dense_h_multiply(H.data(), n, in, out, ld, nc); };
223231
auto t0 = std::chrono::high_resolution_clock::now();
@@ -339,7 +347,7 @@ int main(int argc, char** argv)
339347
int sparsity;
340348
};
341349
// Without arguments a small default grid is used. To benchmark a single
342-
// (possibly large) problem, pass: <n> <nband> <sparsity_pct>
350+
// (possibly large) problem, pass: <n> <nband> <sparsity_pct> [sbsize] [rr_step]
343351
std::vector<Case> cases;
344352
if (argc >= 4)
345353
{
@@ -351,6 +359,14 @@ int main(int argc, char** argv)
351359
{50, 10, 0}, {50, 10, 60}, {100, 10, 60}, {200, 10, 80}, {500, 10, 80},
352360
};
353361
}
362+
if (argc >= 5)
363+
{
364+
g_sbsize = std::atoi(argv[4]);
365+
}
366+
if (argc >= 6)
367+
{
368+
g_rr_step = std::atoi(argv[5]);
369+
}
354370

355371
std::printf("\n=== Solver comparison (identical H, psi0, ethr) ===\n");
356372
std::printf("%-5s %-5s %-6s %-10s %-14s %-12s %-10s %-12s\n", "n", "nband", "spars", "solver", "wall_time(s)", "avg_iter",

source/source_io/module_parameter/input_parameter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct Input_para
9191
double pw_diag_thr = 0.01; ///< used in cg method
9292
bool diago_smooth_ethr = false; ///< smooth ethr for iter methods
9393
int pw_diag_ndim = 4; ///< dimension of workspace for Davidson diagonalization
94+
int pw_diag_rr_step = 16; ///< Rayleigh-Ritz re-application interval for PPCG diagonalization
9495
int diago_cg_prec = 1; ///< mohan add 2012-03-31
9596
int diag_subspace = 0; // 0: Lapack, 1: elpa, 2: scalapack
9697
bool use_k_continuity = false; ///< whether to use k-point continuity for initializing wave functions

source/source_io/module_parameter/read_inp_estruc.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,13 +1104,25 @@ Use case: When experimental or high-level theoretical results suggest that the S
11041104
item.annotation = "dimension of workspace for iterative PW diagonalization";
11051105
item.category = "Plane wave related variables";
11061106
item.type = "Integer";
1107-
item.description = "Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the PPCG block size/Rayleigh-Ritz interval for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.";
1107+
item.description = "Only useful when you use ks_solver = dav, dav_subspace, or ppcg. It indicates dimension of workspace(number of wavefunction packets, at least 2 needed) for the Davidson method, and the block size for the PPCG method. A larger value may yield a smaller number of iterations in the algorithm but uses more memory and more CPU time in subspace diagonalization.";
11081108
item.default_value = "4";
11091109
item.unit = "";
11101110
item.set_availability("basis_type==pw and ks_solver in [dav, dav_subspace, ppcg]");
11111111
read_sync_int(input.pw_diag_ndim);
11121112
this->add_item(item);
11131113
}
1114+
{
1115+
Input_Item item("pw_diag_rr_step");
1116+
item.annotation = "Rayleigh-Ritz re-application interval for PPCG";
1117+
item.category = "Plane wave related variables";
1118+
item.type = "Integer";
1119+
item.description = "Only useful when you use ks_solver = ppcg. It controls how often (in subspace iterations) H and S are re-applied to reset the accumulated rounding drift after the Rayleigh-Ritz rotation. A larger value reduces the number of H/S applications and thus the wall time without changing the iteration count in well-conditioned cases; a smaller value is more robust against rounding drift in ill-conditioned problems.";
1120+
item.default_value = "16";
1121+
item.unit = "";
1122+
item.set_availability("basis_type==pw and ks_solver==ppcg");
1123+
read_sync_int(input.pw_diag_rr_step);
1124+
this->add_item(item);
1125+
}
11141126
{
11151127
Input_Item item("diago_cg_prec");
11161128
item.annotation = "diago_cg_prec";

source/source_io/test/read_input_ptest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ TEST_F(InputParaTest, ParaRead)
152152
EXPECT_EQ(param.inp.pw_diag_nmax, 50);
153153
EXPECT_EQ(param.inp.diago_cg_prec, 1);
154154
EXPECT_EQ(param.inp.pw_diag_ndim, 4);
155+
EXPECT_EQ(param.inp.pw_diag_rr_step, 16);
155156
EXPECT_DOUBLE_EQ(param.inp.pw_diag_thr, 1.0e-2);
156157
EXPECT_FALSE(param.inp.diago_smooth_ethr);
157158
EXPECT_EQ(param.inp.nb2d, 0);

0 commit comments

Comments
 (0)