12 #include "../config/config.hpp" 21 #if MFEM_MUMPS_VERSION >= 530 22 #ifdef MUMPS_INTSIZE64 23 #error "Full 64-bit MUMPS is not yet supported" 27 #error "Full 64-bit MUMPS is not yet supported" 32 #define MUMPS_ICNTL(I) icntl[(I) -1] 33 #define MUMPS_CNTL(I) cntl[(I) -1] 34 #define MUMPS_INFO(I) info[(I) -1] 35 #define MUMPS_INFOG(I) infog[(I) -1] 48 MFEM_VERIFY(APtr,
"Not a compatible matrix type");
49 Init(APtr->GetComm());
53 void MUMPSSolver::Init(MPI_Comm comm_)
57 MPI_Comm_size(comm, &numProcs);
58 MPI_Comm_rank(comm, &myid);
60 mat_type = MatType::UNSYMMETRIC;
62 reorder_method = ReorderingStrategy::AUTOMATIC;
63 reorder_reuse =
false;
66 #if MFEM_MUMPS_VERSION >= 530 72 recv_counts =
nullptr;
80 #if MFEM_MUMPS_VERSION >= 530 86 delete [] recv_counts;
101 MFEM_VERIFY(APtr,
"Not a compatible matrix type");
106 auto parcsr_op = (hypre_ParCSRMatrix *)const_cast<HypreParMatrix &>(*APtr);
108 hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
110 HYPRE_Int *Iptr = csr_op->i;
111 #if MFEM_HYPRE_VERSION >= 21600 114 HYPRE_Int *Jptr = csr_op->j;
120 MUMPS_INT8 nnz = 0, k = 0;
124 for (
int i = 0; i < n_loc; i++)
126 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
128 int ii = row_start + i + 1;
129 #if MFEM_HYPRE_VERSION >= 21600 132 HYPRE_Int jj = Jptr[k] + 1;
134 if (ii >= jj) { nnz++; }
141 nnz = csr_op->num_nonzeros;
143 int *I =
new int[nnz];
144 int *J =
new int[nnz];
153 data =
new double[nnz];
154 for (
int i = 0; i < n_loc; i++)
156 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
158 int ii = row_start + i + 1;
159 #if MFEM_HYPRE_VERSION >= 21600 162 HYPRE_Int jj = Jptr[k] + 1;
168 data[l++] = csr_op->data[k];
176 for (
int i = 0; i < n_loc; i++)
178 for (HYPRE_Int j = Iptr[i]; j < Iptr[i + 1]; j++)
180 I[k] = row_start + i + 1;
189 if (!
id || !reorder_reuse)
197 id =
new DMUMPS_STRUC_C;
201 id->comm_fortran = (MUMPS_INT)MPI_Comm_c2f(comm);
233 const int mem_relax_lim = 200;
237 if (id->MUMPS_INFOG(1) < 0)
239 if (id->MUMPS_INFOG(1) == -8 ||
id->MUMPS_INFOG(1) == -9)
241 id->MUMPS_ICNTL(14) += 20;
242 MFEM_VERIFY(id->MUMPS_ICNTL(14) <= mem_relax_lim,
243 "Memory relaxation limit reached for MUMPS factorization");
244 if (myid == 0 && print_level > 0)
246 mfem::out <<
"Re-running MUMPS factorization with memory relaxation " 247 <<
id->MUMPS_ICNTL(14) <<
'\n';
252 MFEM_ABORT(
"Error during MUMPS numerical factorization");
259 hypre_CSRMatrixDestroy(csr_op);
262 if (mat_type) {
delete [] data; }
265 #if MFEM_MUMPS_VERSION >= 530 268 id->nloc_rhs = n_loc;
269 id->lrhs_loc = n_loc;
270 id->lsol_loc =
id->MUMPS_INFO(23);
271 irhs_loc =
new int[
id->lrhs_loc];
272 isol_loc =
new int[
id->lsol_loc];
273 for (
int i = 0; i < n_loc; i++)
275 irhs_loc[i] = row_start + i + 1;
277 id->irhs_loc = irhs_loc;
278 id->isol_loc = isol_loc;
281 MPI_Allgather(&row_start, 1, MPI_INT, row_starts, 1, MPI_INT, comm);
286 delete [] recv_counts;
288 recv_counts =
new int[numProcs];
289 displs =
new int[numProcs];
291 MPI_Gather(&n_loc, 1, MPI_INT, recv_counts, 1, MPI_INT, 0, comm);
296 for (
int k = 0; k < numProcs-1; k++)
305 void MUMPSSolver::InitRhsSol(
int nrhs)
const 307 if (id->nrhs != nrhs)
309 #if MFEM_MUMPS_VERSION >= 530 312 rhs_loc = (nrhs > 1) ?
new double[nrhs * id->lrhs_loc] :
nullptr;
313 sol_loc =
new double[nrhs * id->lsol_loc];
314 id->rhs_loc = rhs_loc;
315 id->sol_loc = sol_loc;
320 rhs_glob =
new double[nrhs *
id->lrhs];
341 "Number of columns mismatch in MUMPSSolver::Mult!");
342 InitRhsSol(X.
Size());
343 #if MFEM_MUMPS_VERSION >= 530 346 MFEM_ASSERT(X.
Size() == 1 && X[0],
"Missing Vector in MUMPSSolver::Mult!");
352 for (
int i = 0; i <
id->nrhs; i++)
354 MFEM_ASSERT(X[i],
"Missing Vector in MUMPSSolver::Mult!");
356 std::copy(X[i]->GetData(), X[i]->GetData() + X[i]->Size(),
357 id->rhs_loc + i * id->lrhs_loc);
365 RedistributeSol(id->isol_loc, id->sol_loc, id->lsol_loc, Y);
367 for (
int i = 0; i <
id->nrhs; i++)
369 MFEM_ASSERT(X[i],
"Missing Vector in MUMPSSolver::Mult!");
371 MPI_Gatherv(X[i]->GetData(), X[i]->Size(), MPI_DOUBLE,
372 id->rhs + i * id->lrhs, recv_counts, displs, MPI_DOUBLE, 0, comm);
379 for (
int i = 0; i <
id->nrhs; i++)
381 MFEM_ASSERT(Y[i],
"Missing Vector in MUMPSSolver::Mult!");
383 MPI_Scatterv(id->rhs + i * id->lrhs, recv_counts, displs, MPI_DOUBLE,
384 Y[i]->
GetData(), Y[i]->
Size(), MPI_DOUBLE, 0, comm);
392 id->MUMPS_ICNTL(9) = 0;
396 id->MUMPS_ICNTL(9) = 1;
403 id->MUMPS_ICNTL(9) = 0;
407 id->MUMPS_ICNTL(9) = 1;
412 print_level = print_lvl;
422 reorder_method = method;
427 reorder_reuse = reuse;
430 #if MFEM_MUMPS_VERSION >= 510 437 void MUMPSSolver::SetParameters()
440 id->MUMPS_ICNTL(1) = 6;
442 id->MUMPS_ICNTL(2) = 0;
444 id->MUMPS_ICNTL(3) = 6;
446 id->MUMPS_ICNTL(4) = print_level;
448 id->MUMPS_ICNTL(5) = 0;
450 id->MUMPS_ICNTL(9) = 1;
452 id->MUMPS_ICNTL(10) = 0;
454 id->MUMPS_ICNTL(11) = 0;
456 id->MUMPS_ICNTL(13) = 0;
458 id->MUMPS_ICNTL(14) = 20;
460 id->MUMPS_ICNTL(16) = 0;
462 id->MUMPS_ICNTL(18) = 3;
464 id->MUMPS_ICNTL(19) = 0;
465 #if MFEM_MUMPS_VERSION >= 530 467 id->MUMPS_ICNTL(20) = 10;
469 id->MUMPS_ICNTL(21) = 1;
472 id->MUMPS_ICNTL(20) = 0;
474 id->MUMPS_ICNTL(21) = 0;
477 id->MUMPS_ICNTL(22) = 0;
479 id->MUMPS_ICNTL(23) = 0;
481 switch (reorder_method)
483 case ReorderingStrategy::AUTOMATIC:
484 id->MUMPS_ICNTL(28) = 0;
485 id->MUMPS_ICNTL(7) = 7;
486 id->MUMPS_ICNTL(29) = 0;
488 case ReorderingStrategy::AMD:
489 id->MUMPS_ICNTL(28) = 1;
490 id->MUMPS_ICNTL(7) = 0;
492 case ReorderingStrategy::AMF:
493 id->MUMPS_ICNTL(28) = 1;
494 id->MUMPS_ICNTL(7) = 2;
496 case ReorderingStrategy::PORD:
497 id->MUMPS_ICNTL(28) = 1;
498 id->MUMPS_ICNTL(7) = 4;
500 case ReorderingStrategy::METIS:
501 id->MUMPS_ICNTL(28) = 1;
502 id->MUMPS_ICNTL(7) = 5;
505 id->MUMPS_ICNTL(28) = 2;
506 id->MUMPS_ICNTL(29) = 2;
508 case ReorderingStrategy::SCOTCH:
509 id->MUMPS_ICNTL(28) = 1;
510 id->MUMPS_ICNTL(7) = 3;
512 case ReorderingStrategy::PTSCOTCH:
513 id->MUMPS_ICNTL(28) = 2;
514 id->MUMPS_ICNTL(29) = 1;
520 #if MFEM_MUMPS_VERSION >= 510 523 id->MUMPS_ICNTL(35) = 1;
524 id->MUMPS_CNTL(7) = blr_tol;
529 #if MFEM_MUMPS_VERSION >= 530 530 int MUMPSSolver::GetRowRank(
int i,
const Array<int> &row_starts_)
const 532 if (row_starts_.Size() == 1)
536 auto up = std::upper_bound(row_starts_.begin(), row_starts_.end(), i);
537 return std::distance(row_starts_.begin(), up) - 1;
540 void MUMPSSolver::RedistributeSol(
const int *rmap,
const double *x,
541 const int lx_loc, Array<Vector *> &Y)
const 543 int *send_count =
new int[numProcs]();
544 for (
int i = 0; i < lx_loc; i++)
547 int row_rank = GetRowRank(j, row_starts);
548 if (myid == row_rank) {
continue; }
549 send_count[row_rank]++;
552 int *recv_count =
new int[numProcs];
553 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
555 int *send_displ =
new int[numProcs]; send_displ[0] = 0;
556 int *recv_displ =
new int[numProcs]; recv_displ[0] = 0;
557 int sbuff_size = send_count[numProcs-1];
558 int rbuff_size = recv_count[numProcs-1];
559 for (
int k = 0; k < numProcs - 1; k++)
561 send_displ[k + 1] = send_displ[k] + send_count[k];
562 recv_displ[k + 1] = recv_displ[k] + recv_count[k];
563 sbuff_size += send_count[k];
564 rbuff_size += recv_count[k];
567 int *sendbuf_index =
new int[sbuff_size];
568 double *sendbuf_values =
new double[sbuff_size];
569 int *recvbuf_index =
new int[rbuff_size];
570 double *recvbuf_values =
new double[rbuff_size];
571 int *soffs =
new int[numProcs]();
573 for (
int i = 0; i < lx_loc; i++)
576 int row_rank = GetRowRank(j, row_starts);
577 if (myid != row_rank)
579 int k = send_displ[row_rank] + soffs[row_rank];
580 sendbuf_index[k] = j;
585 MPI_Alltoallv(sendbuf_index, send_count, send_displ, MPI_INT,
586 recvbuf_index, recv_count, recv_displ, MPI_INT, comm);
588 for (
int rhs = 0; rhs < Y.Size(); rhs++)
590 MFEM_ASSERT(Y[rhs],
"Missing Vector in MUMPSSolver::Mult!");
593 std::fill(soffs, soffs + numProcs, 0);
594 for (
int i = 0; i < lx_loc; i++)
597 int row_rank = GetRowRank(j, row_starts);
598 if (myid == row_rank)
600 int local_index = j - row_start;
601 (*Y[rhs])(local_index) = x[rhs * lx_loc + i];
605 int k = send_displ[row_rank] + soffs[row_rank];
606 sendbuf_values[k] = x[rhs * lx_loc + i];
611 MPI_Alltoallv(sendbuf_values, send_count, send_displ, MPI_DOUBLE,
612 recvbuf_values, recv_count, recv_displ, MPI_DOUBLE, comm);
615 for (
int i = 0; i < rbuff_size; i++)
617 int local_index = recvbuf_index[i] - row_start;
618 (*Y[rhs])(local_index) = recvbuf_values[i];
622 delete [] recvbuf_values;
623 delete [] recvbuf_index;
625 delete [] sendbuf_values;
626 delete [] sendbuf_index;
627 delete [] recv_displ;
628 delete [] send_displ;
629 delete [] recv_count;
630 delete [] send_count;
636 #endif // MFEM_USE_MPI 637 #endif // MFEM_USE_MUMPS void ArrayMultTranspose(const Array< const Vector *> &X, Array< Vector *> &Y) const
Action of the transpose operator on a matrix: Y=A^t(X).
void SetOperator(const Operator &op)
Set the Operator and perform factorization.
void SetPrintLevel(int print_lvl)
Set the error print level for MUMPS.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
T * GetData()
Returns the data.
MUMPSSolver(MPI_Comm comm_)
Constructor with MPI_Comm parameter.
void SetMatrixSymType(MatType mtype)
Set the matrix type.
int to_int(const std::string &str)
Convert a string to an int.
void Mult(const Vector &x, Vector &y) const
Solve y = Op^{-1} x.
void ArrayMult(const Array< const Vector *> &X, Array< Vector *> &Y) const
Operator application on a matrix: Y=A(X).
void SetReorderingStrategy(ReorderingStrategy method)
Set the reordering strategy.
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void SetBLRTol(double tol)
Set the tolerance for activating block low-rank (BLR) approximate factorization.
void SetReorderingReuse(bool reuse)
Set the flag controlling reuse of the symbolic factorization for multiple operators.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
A class to initialize the size of a Tensor.
int height
Dimension of the output / number of rows in the matrix.
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
void MultTranspose(const Vector &x, Vector &y) const
Transpose Solve y = Op^{-T} x.
int Size() const
Return the logical size of the array.
Wrapper for hypre's ParCSR matrix class.
int width
Dimension of the input / number of columns in the matrix.