The idea is:
- cmake generates arpackdef.h from arpackdef.cmake.h.in
- autoheader generates arpackdef.h from arpackdef.autotools.h[.in]
- arpack includes arpackdef.h when/where needed:
- #define provide c_int/a_int according to architecture.
- all f90 who need to include "arpackdef.h" must be moved to F90.
Note: by convention, F90 are preprocessed (f90 are not).
- MPI does not support ILP64: integer*4 must be imposed in all
calls involving MPI (f90 example/test code).
To enable ILP64 users to compile/link, arpackdef.h is added in
the arpack installation (make install).
228 lines
6.9 KiB
C++
228 lines
6.9 KiB
C++
/*
|
|
* This example demonstrates the use of ISO_C_BINDING to call parpack
|
|
* (portability). IMPORTANT: MPI communicators MUST be passed from C to Fortran
|
|
* using MPI_Comm_c2f.
|
|
*
|
|
* Just use arpack as you would have normally done but use [ae]upd instead
|
|
* of *[ae]upd_. The main advantage is that checks of the arguments are
|
|
* performed at compile time. Note: to debug parpack, call debug_c.
|
|
* This test program solves for the 9 largest eigenvalues of
|
|
* A*x = lambda*x where A is the diagonal matrix
|
|
* with entries 1000, 999, ... , 2, 1 on the diagonal.
|
|
*/
|
|
|
|
#include "parpack.hpp"
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "debug_c.hpp" // debug parpack.
|
|
#include "stat_c.hpp" // arpack statistics.
|
|
|
|
void diagonal_matrix_vector_product(float const* const x, float* const y) {
|
|
for (int i = 0; i < 1000; ++i) {
|
|
y[i] = static_cast<float>(i + 1) * x[i];
|
|
}
|
|
}
|
|
|
|
void real_symmetric_runner() {
|
|
a_int N = 1000;
|
|
a_int nev = 3;
|
|
a_int ncv = 2 * nev + 1;
|
|
a_int ldz = N + 1;
|
|
a_int lworkl = 3 * (ncv * ncv) + 6 * ncv;
|
|
a_int ldv = N;
|
|
|
|
bool rvec = true;
|
|
float tol = 0.0f;
|
|
float sigma = 0.0f;
|
|
|
|
std::array<a_int, 14> ipntr;
|
|
|
|
std::vector<float> workd(3 * N, 0.0f);
|
|
std::vector<float> workl(3 * (ncv * ncv) + 6 * ncv, 0.0f);
|
|
std::vector<float> V(ncv * N);
|
|
std::vector<float> d(nev + 1);
|
|
std::vector<float> z((N + 1) * (nev + 1));
|
|
std::vector<float> resid(N);
|
|
std::vector<a_int> select(ncv);
|
|
|
|
a_int info = 0;
|
|
|
|
int rank;
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
|
|
std::array<a_int, 11> iparam;
|
|
iparam[0] = 1;
|
|
iparam[2] = 10 * N;
|
|
iparam[3] = 1;
|
|
iparam[4] = 0; // number of ev found by arpack.
|
|
iparam[6] = 1;
|
|
|
|
MPI_Fint MCW = MPI_Comm_c2f(MPI_COMM_WORLD);
|
|
|
|
a_int ido = 0;
|
|
|
|
while (ido != 99) {
|
|
arpack::saupd(MCW, ido, arpack::bmat::identity, N,
|
|
arpack::which::largest_magnitude, nev, tol, resid.data(), ncv,
|
|
V.data(), ldv, iparam.data(), ipntr.data(), workd.data(),
|
|
workl.data(), lworkl, info);
|
|
|
|
diagonal_matrix_vector_product(&(workd[ipntr[0] - 1]),
|
|
&(workd[ipntr[1] - 1]));
|
|
}
|
|
// check number of ev found by arpack.
|
|
if (iparam[4] != nev || info != 0) {
|
|
throw std::domain_error("Error inside ARPACK routines");
|
|
}
|
|
|
|
arpack::seupd(MCW, rvec, arpack::howmny::ritz_vectors, select.data(),
|
|
d.data(), z.data(), ldz, sigma, arpack::bmat::identity, N,
|
|
arpack::which::largest_magnitude, nev, tol, resid.data(), ncv,
|
|
V.data(), ldv, iparam.data(), ipntr.data(), workd.data(),
|
|
workl.data(), lworkl, info);
|
|
|
|
for (int i = 0; i < nev; ++i) {
|
|
std::cout << "rank " << rank << " - " << d[i] << std::endl;
|
|
if (std::abs(d[i] - static_cast<float>(1000 - (nev - 1) + i)) > 1e-1) {
|
|
throw std::domain_error("Correct eigenvalues not computed");
|
|
}
|
|
}
|
|
}
|
|
|
|
void diagonal_matrix_vector_product(std::complex<float> const* const x,
|
|
std::complex<float>* const y) {
|
|
for (int i = 0; i < 1000; ++i) {
|
|
y[i] = x[i] * std::complex<float>{i + 1.0f, i + 1.0f};
|
|
}
|
|
}
|
|
|
|
void complex_symmetric_runner() {
|
|
a_int N = 1000;
|
|
a_int nev = 1;
|
|
a_int ncv = 2 * nev + 1;
|
|
a_int ldv = N;
|
|
a_int ldz = N + 1;
|
|
|
|
float tol = 0.0f;
|
|
bool rvec = true;
|
|
std::complex<float> sigma(0.0f, 0.0f);
|
|
|
|
std::vector<std::complex<float>> resid(N);
|
|
std::vector<std::complex<float>> V(ncv * N);
|
|
std::vector<std::complex<float>> workd(3 * N);
|
|
std::vector<std::complex<float>> d(nev + 1);
|
|
std::vector<std::complex<float>> z((N + 1) * (nev + 1));
|
|
std::vector<a_int> select(ncv);
|
|
|
|
a_int lworkl = 3 * (ncv * ncv) + 6 * ncv;
|
|
std::vector<std::complex<float>> workl(lworkl);
|
|
|
|
std::vector<std::complex<float>> rwork(ncv);
|
|
std::vector<std::complex<float>> workev(2 * ncv);
|
|
|
|
a_int info = 0;
|
|
|
|
int rank;
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
|
|
std::array<a_int, 11> iparam;
|
|
iparam[0] = 1;
|
|
iparam[2] = 10 * N;
|
|
iparam[3] = 1;
|
|
iparam[4] = 0; // number of ev found by arpack.
|
|
iparam[6] = 1;
|
|
|
|
std::array<a_int, 14> ipntr;
|
|
|
|
MPI_Fint MCW = MPI_Comm_c2f(MPI_COMM_WORLD);
|
|
|
|
a_int ido = 0;
|
|
|
|
while (ido != 99) {
|
|
arpack::naupd(MCW, ido, arpack::bmat::identity, N,
|
|
arpack::which::largest_magnitude, nev, tol, resid.data(), ncv,
|
|
V.data(), ldv, iparam.data(), ipntr.data(), workd.data(),
|
|
workl.data(), lworkl, rwork.data(), info);
|
|
|
|
diagonal_matrix_vector_product(&(workd[ipntr[0] - 1]),
|
|
&(workd[ipntr[1] - 1]));
|
|
}
|
|
|
|
// check number of ev found by arpack
|
|
if (iparam[4] != nev || info != 0) {
|
|
throw std::domain_error("Error inside ARPACK routines");
|
|
}
|
|
|
|
arpack::neupd(MCW, rvec, arpack::howmny::ritz_vectors, select.data(),
|
|
d.data(), z.data(), ldz, sigma, workev.data(),
|
|
arpack::bmat::identity, N, arpack::which::largest_magnitude,
|
|
nev, tol, resid.data(), ncv, V.data(), ldv, iparam.data(),
|
|
ipntr.data(), workd.data(), workl.data(), lworkl, rwork.data(),
|
|
info);
|
|
|
|
for (int i = 0; i < nev; ++i) {
|
|
std::cout << "rank " << rank << " - " << std::real(d[i]) << " "
|
|
<< std::imag(d[i]) << '\n';
|
|
if (std::abs(std::real(d[i]) - static_cast<float>(1000 - i)) > 1e-1 ||
|
|
std::abs(std::imag(d[i]) - static_cast<float>(1000 - i)) > 1e-1) {
|
|
throw std::domain_error("Correct eigenvalues not computed");
|
|
}
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
MPI_Init(NULL, NULL);
|
|
|
|
sstats_c();
|
|
|
|
try {
|
|
// parpack without debug
|
|
real_symmetric_runner();
|
|
} catch (std::domain_error& e) {
|
|
std::cout << e.what() << '\n';
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
|
|
int nopx_c, nbx_c, nrorth_c, nitref_c, nrstrt_c;
|
|
float tsaupd_c, tsaup2_c, tsaitr_c, tseigt_c, tsgets_c, tsapps_c, tsconv_c;
|
|
float tnaupd_c, tnaup2_c, tnaitr_c, tneigt_c, tngets_c, tnapps_c, tnconv_c;
|
|
float tcaupd_c, tcaup2_c, tcaitr_c, tceigt_c, tcgets_c, tcapps_c, tcconv_c;
|
|
float tmvopx_c, tmvbx_c, tgetv0_c, titref_c, trvec_c;
|
|
|
|
stat_c(nopx_c, nbx_c, nrorth_c, nitref_c, nrstrt_c, tsaupd_c, tsaup2_c,
|
|
tsaitr_c, tseigt_c, tsgets_c, tsapps_c, tsconv_c, tnaupd_c, tnaup2_c,
|
|
tnaitr_c, tneigt_c, tngets_c, tnapps_c, tnconv_c, tcaupd_c, tcaup2_c,
|
|
tcaitr_c, tceigt_c, tcgets_c, tcapps_c, tcconv_c, tmvopx_c, tmvbx_c,
|
|
tgetv0_c, titref_c, trvec_c);
|
|
|
|
std::cout << "Timers : nopx " << nopx_c << ", tmvopx " << tmvopx_c;
|
|
std::cout << " - nbx " << nbx_c << ", tmvbx " << tmvbx_c << std::endl;
|
|
|
|
int rank = 0;
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
if (rank == 0) std::cout << "------" << std::endl;
|
|
|
|
// set debug flags.
|
|
debug_c(6, -6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1);
|
|
|
|
try {
|
|
complex_symmetric_runner();
|
|
} catch (std::domain_error& e) {
|
|
std::cout << e.what() << '\n';
|
|
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
}
|
|
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
|
|
MPI_Finalize();
|
|
|
|
return 0;
|
|
}
|