43 #include "abstract/sparse_solver.hpp"
45 #include <mpl/mpl.hpp>
48 enum matrix_type : std::int8_t {
49 real_and_symmetric_positive_definite = 2,
50 real_and_symmetric_indefinite = -2,
51 real_and_structurally_symmetric = 1,
52 real_and_nonsymmetric = 11,
53 complex_and_hermitian_positive_definite = 4,
54 complex_and_hermitian_indefinite = -4,
55 complex_and_structurally_symmetric = 3,
56 complex_and_symmetric = 6,
57 complex_and_nonsymmetric = 13
60 enum message_level : std::int8_t {
62 print_statistical_information = 1
65 template<data_t DT, index_t IT>
class pardiso final {
66 static constexpr IT one{1}, negone{-1}, PARDISO_ANA_FACT{12}, PARDISO_SOLVE{33}, PARDISO_RELEASE{-1};
68 std::int64_t pt[64]{};
72 sparse_csr_mat<DT, IT> a_mat{};
74 const mpl::communicator& comm_world{mpl::environment::comm_world()};
76 const int comm = MPI_Comm_c2f(comm_world.native_handle());
78 const IT mtype, msglvl;
80 bool is_allocated{
false};
82 auto alloc(sparse_csr_mat<DT, IT>&& A) {
87 if constexpr(
sizeof(IT) == 4) cluster_sparse_solver(pt, &one, &one, &mtype, &PARDISO_ANA_FACT, &a_mat.n, a_mat.data, a_mat.row_ptr, a_mat.col_idx,
nullptr, &negone, iparm, &msglvl,
nullptr,
nullptr, &comm, &error);
88 else if constexpr(sizeof(IT) == 8) cluster_sparse_solver_64(pt, &one, &one, &mtype, &PARDISO_ANA_FACT, &a_mat.n, a_mat.data, a_mat.row_ptr, a_mat.col_idx,
nullptr, &negone, iparm, &msglvl,
nullptr,
nullptr, &comm, &error);
89 return sync_error(error);
93 if(!is_allocated)
return;
96 if constexpr(
sizeof(IT) == 4) cluster_sparse_solver(pt, &one, &one, &mtype, &PARDISO_RELEASE, &negone,
nullptr,
nullptr,
nullptr,
nullptr, &negone, iparm, &msglvl,
nullptr,
nullptr, &comm, &error);
97 else if constexpr(sizeof(IT) == 8) cluster_sparse_solver_64(pt, &one, &one, &mtype, &PARDISO_RELEASE, &negone,
nullptr,
nullptr,
nullptr,
nullptr, &negone, iparm, &msglvl,
nullptr,
nullptr, &comm, &error);
98 for(auto& i : pt) i = 0;
101 auto sync_error(IT error) {
102 comm_world.allreduce(mpl::min<IT>(), error);
107 explicit pardiso(
const IT mtype,
const IT msglvl = 0)
108 :
pardiso(matrix_type{static_cast<std::int8_t>(mtype)}, message_level{static_cast<std::int8_t>(msglvl)}) {}
110 explicit pardiso(
const matrix_type mtype,
const message_level msglvl = no_output)
113 if constexpr(floating_t<DT>) {
114 if(mtype != real_and_symmetric_positive_definite && mtype != real_and_symmetric_indefinite && mtype != real_and_structurally_symmetric && mtype != real_and_nonsymmetric)
throw std::invalid_argument(
"matrix type does not match the data type");
117 if(mtype != complex_and_hermitian_positive_definite && mtype != complex_and_hermitian_indefinite && mtype != complex_and_structurally_symmetric && mtype != complex_and_symmetric && mtype != complex_and_nonsymmetric)
throw std::invalid_argument(
"matrix type does not match the data type");
124 , msglvl(other.msglvl) { std::copy_n(other.iparm, 64, iparm); }
131 auto& operator()(
const IT index) {
return iparm[index]; }
133 auto& iparm_default_value(
const auto config) {
137 auto& iparm_reducing_ordering(
const auto config) {
141 auto& iparm_user_permutation(
const auto config) {
145 auto& iparm_iterative_refinement(
const auto config) {
149 auto& iparm_pivoting_perturbation(
const auto config) {
153 auto& iparm_scaling(
const auto config) {
157 auto& iparm_transpose_matrix(
const auto config) {
161 auto& iparm_weighted_matching(
const auto config) {
165 auto& iparm_nnz_factor(
const auto config) {
169 auto& iparm_pivoting_type(
const auto config) {
173 auto& iparm_matrix_checker(
const auto config) {
177 auto& iparm_precision(
const auto config) {
181 auto& iparm_partial_solve(
const auto config) {
185 auto& iparm_zero_based_indexing(
const auto config) {
189 auto& iparm_schur_complement(
const auto config) {
193 auto& iparm_out_of_core(
const auto config) {
198 IT solve(sparse_csr_mat<DT, IT>&& A, full_mat<DT, IT>&& B) {
199 if(A.n != B.n_rows)
return -1;
203 if constexpr(std::is_same_v<DT, double> || std::is_same_v<DT, complex16>) iparm[27] = 0;
204 else if constexpr(std::is_same_v<DT, float> || std::is_same_v<DT, complex8>) iparm[27] = 1;
206 auto error = sync_error(alloc(std::move(A)));
207 if(error < 0)
return error;
209 return solve(std::move(B));
212 IT solve(full_mat<DT, IT>&& B) {
213 if(a_mat.n != B.n_rows)
return -1;
215 std::vector<DT> b_ref;
216 if(0 == comm_world.rank()) b_ref.resize(B.n_rows * B.n_cols);
220 if(0 == iparm[0] || 0 == iparm[5]) {
222 if(0 == comm_world.rank()) std::copy_n(B.data, b_ref.size(), b_ref.data());
223 b_ptr = b_ref.data();
229 x_ptr = b_ref.data();
233 if constexpr(
sizeof(IT) == 4) cluster_sparse_solver(pt, &one, &one, &mtype, &PARDISO_SOLVE, &a_mat.n, a_mat.data, a_mat.row_ptr, a_mat.col_idx,
nullptr, &B.n_cols, iparm, &msglvl, b_ptr, x_ptr, &comm, &error);
234 else if constexpr(sizeof(IT) == 8) cluster_sparse_solver_64(pt, &one, &one, &mtype, &PARDISO_SOLVE, &a_mat.n, a_mat.data, a_mat.row_ptr, a_mat.col_idx,
nullptr, &B.n_cols, iparm, &msglvl, b_ptr, x_ptr, &comm, &error);
236 return sync_error(error);
Solver for general sparse matrices.