28class MPISubspaceDiagonalizer :
public SubspaceDiagonalizer {
30 explicit MPISubspaceDiagonalizer(
const execution::MPIExecutionPolicy& policy)
33 int solve(
int basis_size,
34 Complex* hamiltonian_matrix,
35 Complex* overlap_matrix,
37 Complex* eigenvector_matrix,
38 bool is_gamma_only =
false)
override {
42 MPI_Comm comm = policy_.get_group_communicator();
43 if (comm == MPI_COMM_NULL)
65 if (policy_.group_size() <= 1) {
66 SerialSubspaceDiagonalizer replicated_solver;
67 return replicated_solver.solve(basis_size,
75#ifdef Q3_WITH_SCALAPACK
77 MPI_Comm_rank(comm, &rank);
78 MPI_Comm_size(comm, &size);
84 int nprow =
static_cast<int>(std::sqrt(size));
85 while (size % nprow != 0)
87 int npcol = size / nprow;
103 int blacs_system_handle = scalapack::Csys2blacs_handle(comm);
104 int blacs_context = blacs_system_handle;
105 scalapack::Cblacs_gridinit(&blacs_context,
"R", nprow, npcol);
107 scalapack::Cblacs_gridinfo(blacs_context, &nprow, &npcol, &myrow, &mycol);
115 if (myrow < 0 || mycol < 0) {
116 scalapack::Cfree_blacs_system_handle(blacs_system_handle);
124 int lld = scalapack::numroc_(&basis_size, &nb, &myrow, &zero_, &nprow);
125 lld = std::max(1, lld);
126 scalapack::descinit_(
127 desc, &basis_size, &basis_size, &nb, &nb, &zero_, &zero_, &blacs_context, &lld, &info);
130 int local_rows = scalapack::numroc_(&basis_size, &nb, &myrow, &zero_, &nprow);
131 int local_cols = scalapack::numroc_(&basis_size, &nb, &mycol, &zero_, &npcol);
132 std::vector<Complex> local_h(
static_cast<size_t>(local_rows) * local_cols);
133 std::vector<Complex> local_s(
static_cast<size_t>(local_rows) * local_cols);
134 std::vector<Complex> local_z(
static_cast<size_t>(local_rows) * local_cols);
136 for (
int j_local = 0; j_local < local_cols; ++j_local) {
138 int j_global = (j_local / nb) * npcol * nb + mycol * nb + (j_local % nb);
139 for (
int i_local = 0; i_local < local_rows; ++i_local) {
140 int i_global = (i_local / nb) * nprow * nb + myrow * nb + (i_local % nb);
141 local_h[j_local * local_rows + i_local] =
142 hamiltonian_matrix[j_global * basis_size + i_global];
143 local_s[j_local * local_rows + i_local] =
144 overlap_matrix[j_global * basis_size + i_global];
166 double orfac = 1.0e-3;
167 int number_of_eigenvalues_found = 0;
168 int number_of_eigenvectors_computed = 0;
175 std::vector<int> ifail(
static_cast<size_t>(std::max(1, basis_size)));
176 std::vector<int> iclustr(
static_cast<size_t>(2 * std::max(1, nprow * npcol)));
177 std::vector<double> gap(
static_cast<size_t>(std::max(1, nprow * npcol)));
179 auto* cast_h =
reinterpret_cast<std::complex<double>*
>(local_h.data());
180 auto* cast_s =
reinterpret_cast<std::complex<double>*
>(local_s.data());
181 auto* cast_z =
reinterpret_cast<std::complex<double>*
>(local_z.data());
188 Real rwork_query = 0.0;
193 auto* cast_work_query =
reinterpret_cast<std::complex<double>*
>(&work_query);
195 scalapack::pzhegvx_(&ibtype,
213 &number_of_eigenvalues_found,
214 &number_of_eigenvectors_computed,
242 lwork = std::max(1,
static_cast<int>(work_query.real()));
243 lrwork = std::max(1,
static_cast<int>(rwork_query)) + basis_size * basis_size;
244 liwork = std::max(1, iwork_query);
246 std::vector<Complex> work(
static_cast<size_t>(lwork));
247 std::vector<Real> rwork(
static_cast<size_t>(lrwork));
248 std::vector<int> iwork(
static_cast<size_t>(liwork));
250 auto* cast_work =
reinterpret_cast<std::complex<double>*
>(work.data());
252 scalapack::pzhegvx_(&ibtype,
270 &number_of_eigenvalues_found,
271 &number_of_eigenvectors_computed,
297 if (info == 0 && (number_of_eigenvalues_found != basis_size ||
298 number_of_eigenvectors_computed != basis_size)) {
299 log::warn(
"ScaLAPACK subspace solve returned {} of {} eigenvalues and {} of {} "
300 "eigenvectors; treating as a failure so the caller can fall back.",
301 number_of_eigenvalues_found,
303 number_of_eigenvectors_computed,
313 std::vector<Complex> global_z(
static_cast<size_t>(basis_size) * basis_size,
315 for (
int j_local = 0; j_local < local_cols; ++j_local) {
316 int j_global = (j_local / nb) * npcol * nb + mycol * nb + (j_local % nb);
317 for (
int i_local = 0; i_local < local_rows; ++i_local) {
318 int i_global = (i_local / nb) * nprow * nb + myrow * nb + (i_local % nb);
319 global_z[j_global * basis_size + i_global] =
320 local_z[j_local * local_rows + i_local];
328 execution::sum_complex(global_z.data(), eigenvector_matrix, basis_size * basis_size, comm);
330 scalapack::Cblacs_gridexit(blacs_context);
331 scalapack::Cfree_blacs_system_handle(blacs_system_handle);
335 SerialSubspaceDiagonalizer serial_solver;
336 return serial_solver.solve(basis_size,
354 bool is_collective()
const override {
355#ifdef Q3_WITH_SCALAPACK
356 return policy_.group_size() > 1;
362 std::string name()
const override {
363 return "Parallel (ScaLAPACK)";
367 const execution::MPIExecutionPolicy& policy_;
void info(spdlog::format_string_t< Args... > fmt, Args &&... args)
std::complex< double > Complex