22#if MFEM_MUMPS_VERSION >= 530
24#error "Full 64-bit MUMPS is not yet supported"
28#error "Full 64-bit MUMPS is not yet supported"
33#define MUMPS_ICNTL(I) icntl[(I) -1]
34#define MUMPS_CNTL(I) cntl[(I) -1]
35#define MUMPS_INFO(I) info[(I) -1]
36#define MUMPS_INFOG(I) infog[(I) -1]
49 MFEM_VERIFY(APtr,
"Not a compatible matrix type");
50 Init(APtr->GetComm());
54void MUMPSSolver::Init(MPI_Comm comm_)
58 MPI_Comm_size(comm, &numProcs);
59 MPI_Comm_rank(comm, &myid);
64 reorder_reuse =
false;
67#if MFEM_MUMPS_VERSION >= 530
73 recv_counts =
nullptr;
81#if MFEM_MUMPS_VERSION >= 530
87 delete [] recv_counts;
106 MFEM_VERIFY(APtr,
"Not a compatible matrix type");
111 auto parcsr_op = (hypre_ParCSRMatrix *)
const_cast<HypreParMatrix &
>(*APtr);
113 hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
115 HYPRE_Int *Iptr = csr_op->i;
116#if MFEM_HYPRE_VERSION >= 21600
119 HYPRE_Int *Jptr = csr_op->j;
122 int n_loc = internal::to_int(csr_op->num_rows);
123 row_start = internal::to_int(parcsr_op->first_row_index);
125 MUMPS_INT8 nnz = 0, k = 0;
129 for (
int i = 0; i < n_loc; i++)
131 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
133 int ii = row_start + i + 1;
134#if MFEM_HYPRE_VERSION >= 21600
137 HYPRE_Int jj = Jptr[k] + 1;
139 if (ii >= jj) { nnz++; }
146 nnz = csr_op->num_nonzeros;
148 int *I =
new int[nnz];
149 int *J =
new int[nnz];
159 for (
int i = 0; i < n_loc; i++)
161 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
163 int ii = row_start + i + 1;
164#if MFEM_HYPRE_VERSION >= 21600
167 HYPRE_Int jj = Jptr[k] + 1;
172 J[l] = internal::to_int(jj);
173 data[l++] = csr_op->data[k];
181 for (
int i = 0; i < n_loc; i++)
183 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
185 I[k] = row_start + i + 1;
186 J[k] = internal::to_int(Jptr[k] + 1);
194 if (!
id || !reorder_reuse)
199#ifdef MFEM_USE_SINGLE
206#ifdef MFEM_USE_SINGLE
207 id =
new SMUMPS_STRUC_C;
209 id =
new DMUMPS_STRUC_C;
214 id->comm_fortran = (MUMPS_INT)MPI_Comm_c2f(comm);
221#ifdef MFEM_USE_SINGLE
230 id->n = internal::to_int(parcsr_op->global_num_rows);
238#ifdef MFEM_USE_SINGLE
254 const int mem_relax_lim = 200;
257#ifdef MFEM_USE_SINGLE
262 if (id->MUMPS_INFOG(1) < 0)
264 if (id->MUMPS_INFOG(1) == -8 || id->MUMPS_INFOG(1) == -9)
266 id->MUMPS_ICNTL(14) += 20;
267 MFEM_VERIFY(id->MUMPS_ICNTL(14) <= mem_relax_lim,
268 "Memory relaxation limit reached for MUMPS factorization");
269 if (myid == 0 && print_level > 0)
271 mfem::out <<
"Re-running MUMPS factorization with memory relaxation "
272 <<
id->MUMPS_ICNTL(14) <<
'\n';
277 MFEM_ABORT(
"Error during MUMPS numerical factorization");
284 hypre_CSRMatrixDestroy(csr_op);
287 if (mat_type) {
delete [] data; }
290#if MFEM_MUMPS_VERSION >= 530
293 id->nloc_rhs = n_loc;
294 id->lrhs_loc = n_loc;
295 id->lsol_loc =
id->MUMPS_INFO(23);
296 irhs_loc =
new int[
id->lrhs_loc];
297 isol_loc =
new int[
id->lsol_loc];
298 for (
int i = 0; i < n_loc; i++)
300 irhs_loc[i] = row_start + i + 1;
302 id->irhs_loc = irhs_loc;
303 id->isol_loc = isol_loc;
306 MPI_Allgather(&row_start, 1, MPI_INT, row_starts, 1, MPI_INT, comm);
311 delete [] recv_counts;
313 recv_counts =
new int[numProcs];
314 displs =
new int[numProcs];
316 MPI_Gather(&n_loc, 1, MPI_INT, recv_counts, 1, MPI_INT, 0, comm);
321 for (
int k = 0; k < numProcs-1; k++)
330void MUMPSSolver::InitRhsSol(
int nrhs)
const
332 if (id->nrhs != nrhs)
334#if MFEM_MUMPS_VERSION >= 530
337 rhs_loc = (nrhs > 1) ?
new real_t[nrhs * id->lrhs_loc] : nullptr;
338 sol_loc =
new real_t[nrhs *
id->lsol_loc];
339 id->rhs_loc = rhs_loc;
340 id->sol_loc = sol_loc;
345 rhs_glob =
new real_t[nrhs *
id->lrhs];
366 "Number of columns mismatch in MUMPSSolver::Mult!");
367 InitRhsSol(X.
Size());
368#if MFEM_MUMPS_VERSION >= 530
371 MFEM_ASSERT(X.
Size() == 1 && X[0],
"Missing Vector in MUMPSSolver::Mult!");
377 for (
int i = 0; i <
id->nrhs; i++)
379 MFEM_ASSERT(X[i],
"Missing Vector in MUMPSSolver::Mult!");
381 std::copy(X[i]->GetData(), X[i]->GetData() + X[i]->Size(),
382 id->rhs_loc + i * id->lrhs_loc);
388#ifdef MFEM_USE_SINGLE
394 RedistributeSol(id->isol_loc, id->sol_loc, id->lsol_loc, Y);
396 for (
int i = 0; i <
id->nrhs; i++)
398 MFEM_ASSERT(X[i],
"Missing Vector in MUMPSSolver::Mult!");
407#ifdef MFEM_USE_SINGLE
413 for (
int i = 0; i <
id->nrhs; i++)
415 MFEM_ASSERT(Y[i],
"Missing Vector in MUMPSSolver::Mult!");
417 MPI_Scatterv(id->rhs + i * id->lrhs, recv_counts, displs,
427 id->MUMPS_ICNTL(9) = 0;
431 id->MUMPS_ICNTL(9) = 1;
438 id->MUMPS_ICNTL(9) = 0;
442 id->MUMPS_ICNTL(9) = 1;
447 print_level = print_lvl;
457 reorder_method = method;
462 reorder_reuse = reuse;
465#if MFEM_MUMPS_VERSION >= 510
472void MUMPSSolver::SetParameters()
475 id->MUMPS_ICNTL(1) = 6;
477 id->MUMPS_ICNTL(2) = 0;
479 id->MUMPS_ICNTL(3) = 6;
481 id->MUMPS_ICNTL(4) = print_level;
483 id->MUMPS_ICNTL(5) = 0;
485 id->MUMPS_ICNTL(9) = 1;
487 id->MUMPS_ICNTL(10) = 0;
489 id->MUMPS_ICNTL(11) = 0;
491 id->MUMPS_ICNTL(13) = 0;
493 id->MUMPS_ICNTL(14) = 20;
495 id->MUMPS_ICNTL(16) = 0;
497 id->MUMPS_ICNTL(18) = 3;
499 id->MUMPS_ICNTL(19) = 0;
500#if MFEM_MUMPS_VERSION >= 530
502 id->MUMPS_ICNTL(20) = 10;
504 id->MUMPS_ICNTL(21) = 1;
507 id->MUMPS_ICNTL(20) = 0;
509 id->MUMPS_ICNTL(21) = 0;
512 id->MUMPS_ICNTL(22) = 0;
514 id->MUMPS_ICNTL(23) = 0;
516 switch (reorder_method)
519 id->MUMPS_ICNTL(28) = 0;
520 id->MUMPS_ICNTL(7) = 7;
521 id->MUMPS_ICNTL(29) = 0;
524 id->MUMPS_ICNTL(28) = 1;
525 id->MUMPS_ICNTL(7) = 0;
528 id->MUMPS_ICNTL(28) = 1;
529 id->MUMPS_ICNTL(7) = 2;
532 id->MUMPS_ICNTL(28) = 1;
533 id->MUMPS_ICNTL(7) = 4;
536 id->MUMPS_ICNTL(28) = 1;
537 id->MUMPS_ICNTL(7) = 5;
540 id->MUMPS_ICNTL(28) = 2;
541 id->MUMPS_ICNTL(29) = 2;
544 id->MUMPS_ICNTL(28) = 1;
545 id->MUMPS_ICNTL(7) = 3;
548 id->MUMPS_ICNTL(28) = 2;
549 id->MUMPS_ICNTL(29) = 1;
555#if MFEM_MUMPS_VERSION >= 510
558 id->MUMPS_ICNTL(35) = 1;
559 id->MUMPS_CNTL(7) = blr_tol;
564#if MFEM_MUMPS_VERSION >= 530
565int MUMPSSolver::GetRowRank(
int i,
const Array<int> &row_starts_)
const
567 if (row_starts_.Size() == 1)
571 auto up = std::upper_bound(row_starts_.begin(), row_starts_.end(), i);
572 return std::distance(row_starts_.begin(), up) - 1;
575void MUMPSSolver::RedistributeSol(
const int *rmap,
const real_t *x,
576 const int lx_loc, Array<Vector *> &Y)
const
578 int *send_count =
new int[numProcs]();
579 for (
int i = 0; i < lx_loc; i++)
582 int row_rank = GetRowRank(j, row_starts);
583 if (myid == row_rank) {
continue; }
584 send_count[row_rank]++;
587 int *recv_count =
new int[numProcs];
588 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
590 int *send_displ =
new int[numProcs]; send_displ[0] = 0;
591 int *recv_displ =
new int[numProcs]; recv_displ[0] = 0;
592 int sbuff_size = send_count[numProcs-1];
593 int rbuff_size = recv_count[numProcs-1];
594 for (
int k = 0; k < numProcs - 1; k++)
596 send_displ[k + 1] = send_displ[k] + send_count[k];
597 recv_displ[k + 1] = recv_displ[k] + recv_count[k];
598 sbuff_size += send_count[k];
599 rbuff_size += recv_count[k];
602 int *sendbuf_index =
new int[sbuff_size];
604 int *recvbuf_index =
new int[rbuff_size];
606 int *soffs =
new int[numProcs]();
608 for (
int i = 0; i < lx_loc; i++)
611 int row_rank = GetRowRank(j, row_starts);
612 if (myid != row_rank)
614 int k = send_displ[row_rank] + soffs[row_rank];
615 sendbuf_index[k] = j;
620 MPI_Alltoallv(sendbuf_index, send_count, send_displ, MPI_INT,
621 recvbuf_index, recv_count, recv_displ, MPI_INT, comm);
623 for (
int rhs = 0; rhs < Y.Size(); rhs++)
625 MFEM_ASSERT(Y[rhs],
"Missing Vector in MUMPSSolver::Mult!");
628 std::fill(soffs, soffs + numProcs, 0);
629 for (
int i = 0; i < lx_loc; i++)
632 int row_rank = GetRowRank(j, row_starts);
633 if (myid == row_rank)
635 int local_index = j - row_start;
636 (*Y[rhs])(local_index) = x[rhs * lx_loc + i];
640 int k = send_displ[row_rank] + soffs[row_rank];
641 sendbuf_values[k] = x[rhs * lx_loc + i];
646 MPI_Alltoallv(sendbuf_values, send_count, send_displ,
647 MPITypeMap<real_t>::mpi_type,
648 recvbuf_values, recv_count, recv_displ, MPITypeMap<real_t>::mpi_type, comm);
651 for (
int i = 0; i < rbuff_size; i++)
653 int local_index = recvbuf_index[i] - row_start;
654 (*Y[rhs])(local_index) = recvbuf_values[i];
658 delete [] recvbuf_values;
659 delete [] recvbuf_index;
661 delete [] sendbuf_values;
662 delete [] sendbuf_index;
663 delete [] recv_displ;
664 delete [] send_displ;
665 delete [] recv_count;
666 delete [] send_count;
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
T * GetData()
Returns the data.
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Wrapper for hypre's ParCSR matrix class.
void HostRead() const
Update the internal hypre_ParCSRMatrix object, A, to be on host.
A class to initialize the size of a Tensor.
ReorderingStrategy
Specify the reordering strategy for the MUMPS solver.
@ AMD
Approximate Minimum Degree with auto quasi-dense row detection is used.
@ METIS
The METIS library will be used.
@ PARMETIS
The ParMETIS library will be used.
@ AMF
Approximate Minimum Fill method will be used.
@ PORD
The PORD library will be used.
@ AUTOMATIC
Let MUMPS automatically decide the reording strategy.
@ PTSCOTCH
The PTScotch library will be used.
@ SCOTCH
The Scotch library will be used.
MUMPSSolver(MPI_Comm comm_)
Constructor with MPI_Comm parameter.
void MultTranspose(const Vector &x, Vector &y) const
Transpose Solve .
void SetBLRTol(double tol)
Set the tolerance for activating block low-rank (BLR) approximate factorization.
void SetPrintLevel(int print_lvl)
Set the error print level for MUMPS.
void Mult(const Vector &x, Vector &y) const
Solve .
void SetReorderingStrategy(ReorderingStrategy method)
Set the reordering strategy.
void ArrayMultTranspose(const Array< const Vector * > &X, Array< Vector * > &Y) const
Transpose Solve .
MatType
Specify the type of matrix we are applying the solver to.
@ UNSYMMETRIC
General sparse matrix, no symmetry is assumed.
void SetMatrixSymType(MatType mtype)
Set the matrix type.
void SetReorderingReuse(bool reuse)
Set the flag controlling reuse of the symbolic factorization for multiple operators.
void SetOperator(const Operator &op)
Set the Operator and perform factorization.
void ArrayMult(const Array< const Vector * > &X, Array< Vector * > &Y) const
Solve .
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Helper struct to convert a C++ type to an MPI type.