Actual source code: mumps.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      2: /*
      3:     Provides an interface to the MUMPS sparse solver
      4: */

      6:  #include <../src/mat/impls/aij/mpi/mpiaij.h>
      7:  #include <../src/mat/impls/sbaij/mpi/mpisbaij.h>
      8:  #include <../src/mat/impls/sell/mpi/mpisell.h>

     10: EXTERN_C_BEGIN
     11: #if defined(PETSC_USE_COMPLEX)
     12: #if defined(PETSC_USE_REAL_SINGLE)
     13: #include <cmumps_c.h>
     14: #else
     15: #include <zmumps_c.h>
     16: #endif
     17: #else
     18: #if defined(PETSC_USE_REAL_SINGLE)
     19: #include <smumps_c.h>
     20: #else
     21: #include <dmumps_c.h>
     22: #endif
     23: #endif
     24: EXTERN_C_END
     25: #define JOB_INIT -1
     26: #define JOB_FACTSYMBOLIC 1
     27: #define JOB_FACTNUMERIC 2
     28: #define JOB_SOLVE 3
     29: #define JOB_END -2

     31: /* calls to MUMPS */
     32: #if defined(PETSC_USE_COMPLEX)
     33: #if defined(PETSC_USE_REAL_SINGLE)
     34: #define MUMPS_c cmumps_c
     35: #else
     36: #define MUMPS_c zmumps_c
     37: #endif
     38: #else
     39: #if defined(PETSC_USE_REAL_SINGLE)
     40: #define MUMPS_c smumps_c
     41: #else
     42: #define MUMPS_c dmumps_c
     43: #endif
     44: #endif

     46: /* if using PETSc OpenMP support, we only call MUMPS on master ranks. Before/after the call, we change/restore CPUs the master ranks can run on */
     47: #if defined(PETSC_HAVE_OPENMP_SUPPORT)
     48: #define PetscMUMPS_c(mumps) \
     49:   do { \
     50:     if (mumps->use_petsc_omp_support) { \
     51:       if (mumps->is_omp_master) { \
     52:         PetscOmpCtrlOmpRegionOnMasterBegin(mumps->omp_ctrl); \
     53:         MUMPS_c(&mumps->id); \
     54:         PetscOmpCtrlOmpRegionOnMasterEnd(mumps->omp_ctrl); \
     55:       } \
     56:       PetscOmpCtrlBarrier(mumps->omp_ctrl); \
     57:     } else { \
     58:       MUMPS_c(&mumps->id); \
     59:     } \
     60:   } while(0)
     61: #else
     62: #define PetscMUMPS_c(mumps) \
     63:   do { MUMPS_c(&mumps->id); } while (0)
     64: #endif

     66: /* declare MumpsScalar */
     67: #if defined(PETSC_USE_COMPLEX)
     68: #if defined(PETSC_USE_REAL_SINGLE)
     69: #define MumpsScalar mumps_complex
     70: #else
     71: #define MumpsScalar mumps_double_complex
     72: #endif
     73: #else
     74: #define MumpsScalar PetscScalar
     75: #endif

     77: /* macros s.t. indices match MUMPS documentation */
     78: #define ICNTL(I) icntl[(I)-1]
     79: #define CNTL(I) cntl[(I)-1]
     80: #define INFOG(I) infog[(I)-1]
     81: #define INFO(I) info[(I)-1]
     82: #define RINFOG(I) rinfog[(I)-1]
     83: #define RINFO(I) rinfo[(I)-1]

     85: typedef struct {
     86: #if defined(PETSC_USE_COMPLEX)
     87: #if defined(PETSC_USE_REAL_SINGLE)
     88:   CMUMPS_STRUC_C id;
     89: #else
     90:   ZMUMPS_STRUC_C id;
     91: #endif
     92: #else
     93: #if defined(PETSC_USE_REAL_SINGLE)
     94:   SMUMPS_STRUC_C id;
     95: #else
     96:   DMUMPS_STRUC_C id;
     97: #endif
     98: #endif

    100:   MatStructure matstruc;
    101:   PetscMPIInt  myid,petsc_size;
    102:   PetscInt     *irn,*jcn,nz,sym;
    103:   PetscScalar  *val;
    104:   MPI_Comm     mumps_comm;
    105:   PetscInt     ICNTL9_pre;           /* check if ICNTL(9) is changed from previous MatSolve */
    106:   VecScatter   scat_rhs, scat_sol;   /* used by MatSolve() */
    107:   Vec          b_seq,x_seq;
    108:   PetscInt     ninfo,*info;          /* display INFO */
    109:   PetscInt     sizeredrhs;
    110:   PetscScalar  *schur_sol;
    111:   PetscInt     schur_sizesol;

    113:   PetscBool    use_petsc_omp_support;
    114:   PetscOmpCtrl omp_ctrl;             /* an OpenMP controler that blocked processes will release their CPU (MPI_Barrier does not have this guarantee) */
    115:   MPI_Comm     petsc_comm,omp_comm;  /* petsc_comm is petsc matrix's comm */
    116:   PetscMPIInt  mpinz;                /* on master rank, nz = sum(mpinz) over omp_comm; on other ranks, mpinz = nz*/
    117:   PetscMPIInt  omp_comm_size;
    118:   PetscBool    is_omp_master;        /* is this rank the master of omp_comm */
    119:   PetscMPIInt  *recvcount,*displs;

    121:   PetscErrorCode (*ConvertToTriples)(Mat, int, MatReuse, int*, int**, int**, PetscScalar**);
    122: } Mat_MUMPS;

    124: extern PetscErrorCode MatDuplicate_MUMPS(Mat,MatDuplicateOption,Mat*);

    126: static PetscErrorCode MatMumpsResetSchur_Private(Mat_MUMPS* mumps)
    127: {

    131:   PetscFree2(mumps->id.listvar_schur,mumps->id.schur);
    132:   PetscFree(mumps->id.redrhs);
    133:   PetscFree(mumps->schur_sol);
    134:   mumps->id.size_schur = 0;
    135:   mumps->id.schur_lld  = 0;
    136:   mumps->id.ICNTL(19)  = 0;
    137:   return(0);
    138: }

    140: /* solve with rhs in mumps->id.redrhs and return in the same location */
    141: static PetscErrorCode MatMumpsSolveSchur_Private(Mat F)
    142: {
    143:   Mat_MUMPS            *mumps=(Mat_MUMPS*)F->data;
    144:   Mat                  S,B,X;
    145:   MatFactorSchurStatus schurstatus;
    146:   PetscInt             sizesol;
    147:   PetscErrorCode       ierr;

    150:   MatFactorFactorizeSchurComplement(F);
    151:   MatFactorGetSchurComplement(F,&S,&schurstatus);
    152:   MatCreateSeqDense(PETSC_COMM_SELF,mumps->id.size_schur,mumps->id.nrhs,(PetscScalar*)mumps->id.redrhs,&B);
    153:   switch (schurstatus) {
    154:   case MAT_FACTOR_SCHUR_FACTORED:
    155:     MatCreateSeqDense(PETSC_COMM_SELF,mumps->id.size_schur,mumps->id.nrhs,(PetscScalar*)mumps->id.redrhs,&X);
    156:     if (!mumps->id.ICNTL(9)) { /* transpose solve */
    157:       MatMatSolveTranspose(S,B,X);
    158:     } else {
    159:       MatMatSolve(S,B,X);
    160:     }
    161:     break;
    162:   case MAT_FACTOR_SCHUR_INVERTED:
    163:     sizesol = mumps->id.nrhs*mumps->id.size_schur;
    164:     if (!mumps->schur_sol || sizesol > mumps->schur_sizesol) {
    165:       PetscFree(mumps->schur_sol);
    166:       PetscMalloc1(sizesol,&mumps->schur_sol);
    167:       mumps->schur_sizesol = sizesol;
    168:     }
    169:     MatCreateSeqDense(PETSC_COMM_SELF,mumps->id.size_schur,mumps->id.nrhs,mumps->schur_sol,&X);
    170:     if (!mumps->id.ICNTL(9)) { /* transpose solve */
    171:       MatTransposeMatMult(S,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&X);
    172:     } else {
    173:       MatMatMult(S,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&X);
    174:     }
    175:     MatCopy(X,B,SAME_NONZERO_PATTERN);
    176:     break;
    177:   default:
    178:     SETERRQ1(PetscObjectComm((PetscObject)F),PETSC_ERR_SUP,"Unhandled MatFactorSchurStatus %D",F->schur_status);
    179:     break;
    180:   }
    181:   MatFactorRestoreSchurComplement(F,&S,schurstatus);
    182:   MatDestroy(&B);
    183:   MatDestroy(&X);
    184:   return(0);
    185: }

    187: static PetscErrorCode MatMumpsHandleSchur_Private(Mat F, PetscBool expansion)
    188: {
    189:   Mat_MUMPS     *mumps=(Mat_MUMPS*)F->data;

    193:   if (!mumps->id.ICNTL(19)) { /* do nothing when Schur complement has not been computed */
    194:     return(0);
    195:   }
    196:   if (!expansion) { /* prepare for the condensation step */
    197:     PetscInt sizeredrhs = mumps->id.nrhs*mumps->id.size_schur;
    198:     /* allocate MUMPS internal array to store reduced right-hand sides */
    199:     if (!mumps->id.redrhs || sizeredrhs > mumps->sizeredrhs) {
    200:       PetscFree(mumps->id.redrhs);
    201:       mumps->id.lredrhs = mumps->id.size_schur;
    202:       PetscMalloc1(mumps->id.nrhs*mumps->id.lredrhs,&mumps->id.redrhs);
    203:       mumps->sizeredrhs = mumps->id.nrhs*mumps->id.lredrhs;
    204:     }
    205:     mumps->id.ICNTL(26) = 1; /* condensation phase */
    206:   } else { /* prepare for the expansion step */
    207:     /* solve Schur complement (this has to be done by the MUMPS user, so basically us) */
    208:     MatMumpsSolveSchur_Private(F);
    209:     mumps->id.ICNTL(26) = 2; /* expansion phase */
    210:     PetscMUMPS_c(mumps);
    211:     if (mumps->id.INFOG(1) < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",mumps->id.INFOG(1));
    212:     /* restore defaults */
    213:     mumps->id.ICNTL(26) = -1;
    214:     /* free MUMPS internal array for redrhs if we have solved for multiple rhs in order to save memory space */
    215:     if (mumps->id.nrhs > 1) {
    216:       PetscFree(mumps->id.redrhs);
    217:       mumps->id.lredrhs = 0;
    218:       mumps->sizeredrhs = 0;
    219:     }
    220:   }
    221:   return(0);
    222: }

    224: /*
    225:   MatConvertToTriples_A_B - convert Petsc matrix to triples: row[nz], col[nz], val[nz]

    227:   input:
    228:     A       - matrix in aij,baij or sbaij (bs=1) format
    229:     shift   - 0: C style output triple; 1: Fortran style output triple.
    230:     reuse   - MAT_INITIAL_MATRIX: spaces are allocated and values are set for the triple
    231:               MAT_REUSE_MATRIX:   only the values in v array are updated
    232:   output:
    233:     nnz     - dim of r, c, and v (number of local nonzero entries of A)
    234:     r, c, v - row and col index, matrix values (matrix triples)

    236:   The returned values r, c, and sometimes v are obtained in a single PetscMalloc(). Then in MatDestroy_MUMPS() it is
    237:   freed with PetscFree(mumps->irn);  This is not ideal code, the fact that v is ONLY sometimes part of mumps->irn means
    238:   that the PetscMalloc() cannot easily be replaced with a PetscMalloc3().

    240:  */

    242: PetscErrorCode MatConvertToTriples_seqaij_seqaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    243: {
    244:   const PetscInt *ai,*aj,*ajj,M=A->rmap->n;
    245:   PetscInt       nz,rnz,i,j;
    247:   PetscInt       *row,*col;
    248:   Mat_SeqAIJ     *aa=(Mat_SeqAIJ*)A->data;

    251:   *v=aa->a;
    252:   if (reuse == MAT_INITIAL_MATRIX) {
    253:     nz   = aa->nz;
    254:     ai   = aa->i;
    255:     aj   = aa->j;
    256:     *nnz = nz;
    257:     PetscMalloc1(2*nz, &row);
    258:     col  = row + nz;

    260:     nz = 0;
    261:     for (i=0; i<M; i++) {
    262:       rnz = ai[i+1] - ai[i];
    263:       ajj = aj + ai[i];
    264:       for (j=0; j<rnz; j++) {
    265:         row[nz] = i+shift; col[nz++] = ajj[j] + shift;
    266:       }
    267:     }
    268:     *r = row; *c = col;
    269:   }
    270:   return(0);
    271: }

    273: PetscErrorCode MatConvertToTriples_seqsell_seqaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    274: {
    275:   Mat_SeqSELL *a=(Mat_SeqSELL*)A->data;
    276:   PetscInt    *ptr;

    279:   *v = a->val;
    280:   if (reuse == MAT_INITIAL_MATRIX) {
    281:     PetscInt       nz,i,j,row;

    284:     nz   = a->sliidx[a->totalslices];
    285:     *nnz = nz;
    286:     PetscMalloc1(2*nz, &ptr);
    287:     *r   = ptr;
    288:     *c   = ptr + nz;

    290:     for (i=0; i<a->totalslices; i++) {
    291:       for (j=a->sliidx[i],row=0; j<a->sliidx[i+1]; j++,row=((row+1)&0x07)) {
    292:         *ptr++ = 8*i + row + shift;
    293:       }
    294:     }
    295:     for (i=0;i<nz;i++) *ptr++ = a->colidx[i] + shift;
    296:   }
    297:   return(0);
    298: }

    300: PetscErrorCode MatConvertToTriples_seqbaij_seqaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    301: {
    302:   Mat_SeqBAIJ    *aa=(Mat_SeqBAIJ*)A->data;
    303:   const PetscInt *ai,*aj,*ajj,bs2 = aa->bs2;
    304:   PetscInt       bs,M,nz,idx=0,rnz,i,j,k,m;
    306:   PetscInt       *row,*col;

    309:   MatGetBlockSize(A,&bs);
    310:   M = A->rmap->N/bs;
    311:   *v = aa->a;
    312:   if (reuse == MAT_INITIAL_MATRIX) {
    313:     ai   = aa->i; aj = aa->j;
    314:     nz   = bs2*aa->nz;
    315:     *nnz = nz;
    316:     PetscMalloc1(2*nz, &row);
    317:     col  = row + nz;

    319:     for (i=0; i<M; i++) {
    320:       ajj = aj + ai[i];
    321:       rnz = ai[i+1] - ai[i];
    322:       for (k=0; k<rnz; k++) {
    323:         for (j=0; j<bs; j++) {
    324:           for (m=0; m<bs; m++) {
    325:             row[idx]   = i*bs + m + shift;
    326:             col[idx++] = bs*(ajj[k]) + j + shift;
    327:           }
    328:         }
    329:       }
    330:     }
    331:     *r = row; *c = col;
    332:   }
    333:   return(0);
    334: }

    336: PetscErrorCode MatConvertToTriples_seqsbaij_seqsbaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    337: {
    338:   const PetscInt *ai, *aj,*ajj,M=A->rmap->n;
    339:   PetscInt       nz,rnz,i,j;
    341:   PetscInt       *row,*col;
    342:   Mat_SeqSBAIJ   *aa=(Mat_SeqSBAIJ*)A->data;

    345:   *v = aa->a;
    346:   if (reuse == MAT_INITIAL_MATRIX) {
    347:     nz   = aa->nz;
    348:     ai   = aa->i;
    349:     aj   = aa->j;
    350:     *v   = aa->a;
    351:     *nnz = nz;
    352:     PetscMalloc1(2*nz, &row);
    353:     col  = row + nz;

    355:     nz = 0;
    356:     for (i=0; i<M; i++) {
    357:       rnz = ai[i+1] - ai[i];
    358:       ajj = aj + ai[i];
    359:       for (j=0; j<rnz; j++) {
    360:         row[nz] = i+shift; col[nz++] = ajj[j] + shift;
    361:       }
    362:     }
    363:     *r = row; *c = col;
    364:   }
    365:   return(0);
    366: }

    368: PetscErrorCode MatConvertToTriples_seqaij_seqsbaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    369: {
    370:   const PetscInt    *ai,*aj,*ajj,*adiag,M=A->rmap->n;
    371:   PetscInt          nz,rnz,i,j;
    372:   const PetscScalar *av,*v1;
    373:   PetscScalar       *val;
    374:   PetscErrorCode    ierr;
    375:   PetscInt          *row,*col;
    376:   Mat_SeqAIJ        *aa=(Mat_SeqAIJ*)A->data;
    377:   PetscBool         missing;

    380:   ai    = aa->i; aj = aa->j; av = aa->a;
    381:   adiag = aa->diag;
    382:   MatMissingDiagonal_SeqAIJ(A,&missing,&i);
    383:   if (reuse == MAT_INITIAL_MATRIX) {
    384:     /* count nz in the upper triangular part of A */
    385:     nz = 0;
    386:     if (missing) {
    387:       for (i=0; i<M; i++) {
    388:         if (PetscUnlikely(adiag[i] >= ai[i+1])) {
    389:           for (j=ai[i];j<ai[i+1];j++) {
    390:             if (aj[j] < i) continue;
    391:             nz++;
    392:           }
    393:         } else {
    394:           nz += ai[i+1] - adiag[i];
    395:         }
    396:       }
    397:     } else {
    398:       for (i=0; i<M; i++) nz += ai[i+1] - adiag[i];
    399:     }
    400:     *nnz = nz;

    402:     PetscMalloc((2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar)), &row);
    403:     col  = row + nz;
    404:     val  = (PetscScalar*)(col + nz);

    406:     nz = 0;
    407:     if (missing) {
    408:       for (i=0; i<M; i++) {
    409:         if (PetscUnlikely(adiag[i] >= ai[i+1])) {
    410:           for (j=ai[i];j<ai[i+1];j++) {
    411:             if (aj[j] < i) continue;
    412:             row[nz] = i+shift;
    413:             col[nz] = aj[j]+shift;
    414:             val[nz] = av[j];
    415:             nz++;
    416:           }
    417:         } else {
    418:           rnz = ai[i+1] - adiag[i];
    419:           ajj = aj + adiag[i];
    420:           v1  = av + adiag[i];
    421:           for (j=0; j<rnz; j++) {
    422:             row[nz] = i+shift; col[nz] = ajj[j] + shift; val[nz++] = v1[j];
    423:           }
    424:         }
    425:       }
    426:     } else {
    427:       for (i=0; i<M; i++) {
    428:         rnz = ai[i+1] - adiag[i];
    429:         ajj = aj + adiag[i];
    430:         v1  = av + adiag[i];
    431:         for (j=0; j<rnz; j++) {
    432:           row[nz] = i+shift; col[nz] = ajj[j] + shift; val[nz++] = v1[j];
    433:         }
    434:       }
    435:     }
    436:     *r = row; *c = col; *v = val;
    437:   } else {
    438:     nz = 0; val = *v;
    439:     if (missing) {
    440:       for (i=0; i <M; i++) {
    441:         if (PetscUnlikely(adiag[i] >= ai[i+1])) {
    442:           for (j=ai[i];j<ai[i+1];j++) {
    443:             if (aj[j] < i) continue;
    444:             val[nz++] = av[j];
    445:           }
    446:         } else {
    447:           rnz = ai[i+1] - adiag[i];
    448:           v1  = av + adiag[i];
    449:           for (j=0; j<rnz; j++) {
    450:             val[nz++] = v1[j];
    451:           }
    452:         }
    453:       }
    454:     } else {
    455:       for (i=0; i <M; i++) {
    456:         rnz = ai[i+1] - adiag[i];
    457:         v1  = av + adiag[i];
    458:         for (j=0; j<rnz; j++) {
    459:           val[nz++] = v1[j];
    460:         }
    461:       }
    462:     }
    463:   }
    464:   return(0);
    465: }

    467: PetscErrorCode MatConvertToTriples_mpisbaij_mpisbaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    468: {
    469:   const PetscInt    *ai, *aj, *bi, *bj,*garray,m=A->rmap->n,*ajj,*bjj;
    470:   PetscErrorCode    ierr;
    471:   PetscInt          rstart,nz,i,j,jj,irow,countA,countB;
    472:   PetscInt          *row,*col;
    473:   const PetscScalar *av, *bv,*v1,*v2;
    474:   PetscScalar       *val;
    475:   Mat_MPISBAIJ      *mat = (Mat_MPISBAIJ*)A->data;
    476:   Mat_SeqSBAIJ      *aa  = (Mat_SeqSBAIJ*)(mat->A)->data;
    477:   Mat_SeqBAIJ       *bb  = (Mat_SeqBAIJ*)(mat->B)->data;

    480:   ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= A->rmap->rstart;
    481:   av=aa->a; bv=bb->a;

    483:   garray = mat->garray;

    485:   if (reuse == MAT_INITIAL_MATRIX) {
    486:     nz   = aa->nz + bb->nz;
    487:     *nnz = nz;
    488:     PetscMalloc((2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar)), &row);
    489:     col  = row + nz;
    490:     val  = (PetscScalar*)(col + nz);

    492:     *r = row; *c = col; *v = val;
    493:   } else {
    494:     row = *r; col = *c; val = *v;
    495:   }

    497:   jj = 0; irow = rstart;
    498:   for (i=0; i<m; i++) {
    499:     ajj    = aj + ai[i];                 /* ptr to the beginning of this row */
    500:     countA = ai[i+1] - ai[i];
    501:     countB = bi[i+1] - bi[i];
    502:     bjj    = bj + bi[i];
    503:     v1     = av + ai[i];
    504:     v2     = bv + bi[i];

    506:     /* A-part */
    507:     for (j=0; j<countA; j++) {
    508:       if (reuse == MAT_INITIAL_MATRIX) {
    509:         row[jj] = irow + shift; col[jj] = rstart + ajj[j] + shift;
    510:       }
    511:       val[jj++] = v1[j];
    512:     }

    514:     /* B-part */
    515:     for (j=0; j < countB; j++) {
    516:       if (reuse == MAT_INITIAL_MATRIX) {
    517:         row[jj] = irow + shift; col[jj] = garray[bjj[j]] + shift;
    518:       }
    519:       val[jj++] = v2[j];
    520:     }
    521:     irow++;
    522:   }
    523:   return(0);
    524: }

    526: PetscErrorCode MatConvertToTriples_mpiaij_mpiaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    527: {
    528:   const PetscInt    *ai, *aj, *bi, *bj,*garray,m=A->rmap->n,*ajj,*bjj;
    529:   PetscErrorCode    ierr;
    530:   PetscInt          rstart,nz,i,j,jj,irow,countA,countB;
    531:   PetscInt          *row,*col;
    532:   const PetscScalar *av, *bv,*v1,*v2;
    533:   PetscScalar       *val;
    534:   Mat_MPIAIJ        *mat = (Mat_MPIAIJ*)A->data;
    535:   Mat_SeqAIJ        *aa  = (Mat_SeqAIJ*)(mat->A)->data;
    536:   Mat_SeqAIJ        *bb  = (Mat_SeqAIJ*)(mat->B)->data;

    539:   ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= A->rmap->rstart;
    540:   av=aa->a; bv=bb->a;

    542:   garray = mat->garray;

    544:   if (reuse == MAT_INITIAL_MATRIX) {
    545:     nz   = aa->nz + bb->nz;
    546:     *nnz = nz;
    547:     PetscMalloc((2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar)), &row);
    548:     col  = row + nz;
    549:     val  = (PetscScalar*)(col + nz);

    551:     *r = row; *c = col; *v = val;
    552:   } else {
    553:     row = *r; col = *c; val = *v;
    554:   }

    556:   jj = 0; irow = rstart;
    557:   for (i=0; i<m; i++) {
    558:     ajj    = aj + ai[i];                 /* ptr to the beginning of this row */
    559:     countA = ai[i+1] - ai[i];
    560:     countB = bi[i+1] - bi[i];
    561:     bjj    = bj + bi[i];
    562:     v1     = av + ai[i];
    563:     v2     = bv + bi[i];

    565:     /* A-part */
    566:     for (j=0; j<countA; j++) {
    567:       if (reuse == MAT_INITIAL_MATRIX) {
    568:         row[jj] = irow + shift; col[jj] = rstart + ajj[j] + shift;
    569:       }
    570:       val[jj++] = v1[j];
    571:     }

    573:     /* B-part */
    574:     for (j=0; j < countB; j++) {
    575:       if (reuse == MAT_INITIAL_MATRIX) {
    576:         row[jj] = irow + shift; col[jj] = garray[bjj[j]] + shift;
    577:       }
    578:       val[jj++] = v2[j];
    579:     }
    580:     irow++;
    581:   }
    582:   return(0);
    583: }

    585: PetscErrorCode MatConvertToTriples_mpibaij_mpiaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    586: {
    587:   Mat_MPIBAIJ       *mat    = (Mat_MPIBAIJ*)A->data;
    588:   Mat_SeqBAIJ       *aa     = (Mat_SeqBAIJ*)(mat->A)->data;
    589:   Mat_SeqBAIJ       *bb     = (Mat_SeqBAIJ*)(mat->B)->data;
    590:   const PetscInt    *ai     = aa->i, *bi = bb->i, *aj = aa->j, *bj = bb->j,*ajj, *bjj;
    591:   const PetscInt    *garray = mat->garray,mbs=mat->mbs,rstart=A->rmap->rstart;
    592:   const PetscInt    bs2=mat->bs2;
    593:   PetscErrorCode    ierr;
    594:   PetscInt          bs,nz,i,j,k,n,jj,irow,countA,countB,idx;
    595:   PetscInt          *row,*col;
    596:   const PetscScalar *av=aa->a, *bv=bb->a,*v1,*v2;
    597:   PetscScalar       *val;

    600:   MatGetBlockSize(A,&bs);
    601:   if (reuse == MAT_INITIAL_MATRIX) {
    602:     nz   = bs2*(aa->nz + bb->nz);
    603:     *nnz = nz;
    604:     PetscMalloc((2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar)), &row);
    605:     col  = row + nz;
    606:     val  = (PetscScalar*)(col + nz);

    608:     *r = row; *c = col; *v = val;
    609:   } else {
    610:     row = *r; col = *c; val = *v;
    611:   }

    613:   jj = 0; irow = rstart;
    614:   for (i=0; i<mbs; i++) {
    615:     countA = ai[i+1] - ai[i];
    616:     countB = bi[i+1] - bi[i];
    617:     ajj    = aj + ai[i];
    618:     bjj    = bj + bi[i];
    619:     v1     = av + bs2*ai[i];
    620:     v2     = bv + bs2*bi[i];

    622:     idx = 0;
    623:     /* A-part */
    624:     for (k=0; k<countA; k++) {
    625:       for (j=0; j<bs; j++) {
    626:         for (n=0; n<bs; n++) {
    627:           if (reuse == MAT_INITIAL_MATRIX) {
    628:             row[jj] = irow + n + shift;
    629:             col[jj] = rstart + bs*ajj[k] + j + shift;
    630:           }
    631:           val[jj++] = v1[idx++];
    632:         }
    633:       }
    634:     }

    636:     idx = 0;
    637:     /* B-part */
    638:     for (k=0; k<countB; k++) {
    639:       for (j=0; j<bs; j++) {
    640:         for (n=0; n<bs; n++) {
    641:           if (reuse == MAT_INITIAL_MATRIX) {
    642:             row[jj] = irow + n + shift;
    643:             col[jj] = bs*garray[bjj[k]] + j + shift;
    644:           }
    645:           val[jj++] = v2[idx++];
    646:         }
    647:       }
    648:     }
    649:     irow += bs;
    650:   }
    651:   return(0);
    652: }

    654: PetscErrorCode MatConvertToTriples_mpiaij_mpisbaij(Mat A,int shift,MatReuse reuse,int *nnz,int **r, int **c, PetscScalar **v)
    655: {
    656:   const PetscInt    *ai, *aj,*adiag, *bi, *bj,*garray,m=A->rmap->n,*ajj,*bjj;
    657:   PetscErrorCode    ierr;
    658:   PetscInt          rstart,nz,nza,nzb,i,j,jj,irow,countA,countB;
    659:   PetscInt          *row,*col;
    660:   const PetscScalar *av, *bv,*v1,*v2;
    661:   PetscScalar       *val;
    662:   Mat_MPIAIJ        *mat =  (Mat_MPIAIJ*)A->data;
    663:   Mat_SeqAIJ        *aa  =(Mat_SeqAIJ*)(mat->A)->data;
    664:   Mat_SeqAIJ        *bb  =(Mat_SeqAIJ*)(mat->B)->data;

    667:   ai=aa->i; aj=aa->j; adiag=aa->diag;
    668:   bi=bb->i; bj=bb->j; garray = mat->garray;
    669:   av=aa->a; bv=bb->a;

    671:   rstart = A->rmap->rstart;

    673:   if (reuse == MAT_INITIAL_MATRIX) {
    674:     nza = 0;    /* num of upper triangular entries in mat->A, including diagonals */
    675:     nzb = 0;    /* num of upper triangular entries in mat->B */
    676:     for (i=0; i<m; i++) {
    677:       nza   += (ai[i+1] - adiag[i]);
    678:       countB = bi[i+1] - bi[i];
    679:       bjj    = bj + bi[i];
    680:       for (j=0; j<countB; j++) {
    681:         if (garray[bjj[j]] > rstart) nzb++;
    682:       }
    683:     }

    685:     nz   = nza + nzb; /* total nz of upper triangular part of mat */
    686:     *nnz = nz;
    687:     PetscMalloc((2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar)), &row);
    688:     col  = row + nz;
    689:     val  = (PetscScalar*)(col + nz);

    691:     *r = row; *c = col; *v = val;
    692:   } else {
    693:     row = *r; col = *c; val = *v;
    694:   }

    696:   jj = 0; irow = rstart;
    697:   for (i=0; i<m; i++) {
    698:     ajj    = aj + adiag[i];                 /* ptr to the beginning of the diagonal of this row */
    699:     v1     = av + adiag[i];
    700:     countA = ai[i+1] - adiag[i];
    701:     countB = bi[i+1] - bi[i];
    702:     bjj    = bj + bi[i];
    703:     v2     = bv + bi[i];

    705:     /* A-part */
    706:     for (j=0; j<countA; j++) {
    707:       if (reuse == MAT_INITIAL_MATRIX) {
    708:         row[jj] = irow + shift; col[jj] = rstart + ajj[j] + shift;
    709:       }
    710:       val[jj++] = v1[j];
    711:     }

    713:     /* B-part */
    714:     for (j=0; j < countB; j++) {
    715:       if (garray[bjj[j]] > rstart) {
    716:         if (reuse == MAT_INITIAL_MATRIX) {
    717:           row[jj] = irow + shift; col[jj] = garray[bjj[j]] + shift;
    718:         }
    719:         val[jj++] = v2[j];
    720:       }
    721:     }
    722:     irow++;
    723:   }
    724:   return(0);
    725: }

    727: PetscErrorCode MatDestroy_MUMPS(Mat A)
    728: {
    729:   Mat_MUMPS      *mumps=(Mat_MUMPS*)A->data;

    733:   PetscFree2(mumps->id.sol_loc,mumps->id.isol_loc);
    734:   VecScatterDestroy(&mumps->scat_rhs);
    735:   VecScatterDestroy(&mumps->scat_sol);
    736:   VecDestroy(&mumps->b_seq);
    737:   VecDestroy(&mumps->x_seq);
    738:   PetscFree(mumps->id.perm_in);
    739:   PetscFree(mumps->irn);
    740:   PetscFree(mumps->info);
    741:   MatMumpsResetSchur_Private(mumps);
    742:   mumps->id.job = JOB_END;
    743:   PetscMUMPS_c(mumps);
    744: #if defined(PETSC_HAVE_OPENMP_SUPPORT)
    745:   if (mumps->use_petsc_omp_support) { PetscOmpCtrlDestroy(&mumps->omp_ctrl); }
    746: #endif
    747:   PetscFree2(mumps->recvcount,mumps->displs);
    748:   PetscFree(A->data);

    750:   /* clear composed functions */
    751:   PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverType_C",NULL);
    752:   PetscObjectComposeFunction((PetscObject)A,"MatFactorSetSchurIS_C",NULL);
    753:   PetscObjectComposeFunction((PetscObject)A,"MatFactorCreateSchurComplement_C",NULL);
    754:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsSetIcntl_C",NULL);
    755:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetIcntl_C",NULL);
    756:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsSetCntl_C",NULL);
    757:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetCntl_C",NULL);
    758:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetInfo_C",NULL);
    759:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetInfog_C",NULL);
    760:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetRinfo_C",NULL);
    761:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetRinfog_C",NULL);
    762:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetInverse_C",NULL);
    763:   PetscObjectComposeFunction((PetscObject)A,"MatMumpsGetInverseTranspose_C",NULL);
    764:   return(0);
    765: }

    767: PetscErrorCode MatSolve_MUMPS(Mat A,Vec b,Vec x)
    768: {
    769:   Mat_MUMPS        *mumps=(Mat_MUMPS*)A->data;
    770:   PetscScalar      *array;
    771:   Vec              b_seq;
    772:   IS               is_iden,is_petsc;
    773:   PetscErrorCode   ierr;
    774:   PetscInt         i;
    775:   PetscBool        second_solve = PETSC_FALSE;
    776:   static PetscBool cite1 = PETSC_FALSE,cite2 = PETSC_FALSE;

    779:   PetscCitationsRegister("@article{MUMPS01,\n  author = {P.~R. Amestoy and I.~S. Duff and J.-Y. L'Excellent and J. Koster},\n  title = {A fully asynchronous multifrontal solver using distributed dynamic scheduling},\n  journal = {SIAM Journal on Matrix Analysis and Applications},\n  volume = {23},\n  number = {1},\n  pages = {15--41},\n  year = {2001}\n}\n",&cite1);
    780:   PetscCitationsRegister("@article{MUMPS02,\n  author = {P.~R. Amestoy and A. Guermouche and J.-Y. L'Excellent and S. Pralet},\n  title = {Hybrid scheduling for the parallel solution of linear systems},\n  journal = {Parallel Computing},\n  volume = {32},\n  number = {2},\n  pages = {136--156},\n  year = {2006}\n}\n",&cite2);

    782:   if (A->factorerrortype) {
    783:     PetscInfo2(A,"MatSolve is called with singular matrix factor, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    784:     VecSetInf(x);
    785:     return(0);
    786:   }

    788:   mumps->id.ICNTL(20)= 0; /* dense RHS */
    789:   mumps->id.nrhs     = 1;
    790:   b_seq          = mumps->b_seq;
    791:   if (mumps->petsc_size > 1) {
    792:     /* MUMPS only supports centralized rhs. Scatter b into a seqential rhs vector */
    793:     VecScatterBegin(mumps->scat_rhs,b,b_seq,INSERT_VALUES,SCATTER_FORWARD);
    794:     VecScatterEnd(mumps->scat_rhs,b,b_seq,INSERT_VALUES,SCATTER_FORWARD);
    795:     if (!mumps->myid) {VecGetArray(b_seq,&array);}
    796:   } else {  /* petsc_size == 1 */
    797:     VecCopy(b,x);
    798:     VecGetArray(x,&array);
    799:   }
    800:   if (!mumps->myid) { /* define rhs on the host */
    801:     mumps->id.nrhs = 1;
    802:     mumps->id.rhs = (MumpsScalar*)array;
    803:   }

    805:   /*
    806:      handle condensation step of Schur complement (if any)
    807:      We set by default ICNTL(26) == -1 when Schur indices have been provided by the user.
    808:      According to MUMPS (5.0.0) manual, any value should be harmful during the factorization phase
    809:      Unless the user provides a valid value for ICNTL(26), MatSolve and MatMatSolve routines solve the full system.
    810:      This requires an extra call to PetscMUMPS_c and the computation of the factors for S
    811:   */
    812:   if (mumps->id.size_schur > 0 && (mumps->id.ICNTL(26) < 0 || mumps->id.ICNTL(26) > 2)) {
    813:     if (mumps->petsc_size > 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Parallel Schur complements not yet supported from PETSc\n");
    814:     second_solve = PETSC_TRUE;
    815:     MatMumpsHandleSchur_Private(A,PETSC_FALSE);
    816:   }
    817:   /* solve phase */
    818:   /*-------------*/
    819:   mumps->id.job = JOB_SOLVE;
    820:   PetscMUMPS_c(mumps);
    821:   if (mumps->id.INFOG(1) < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",mumps->id.INFOG(1));

    823:   /* handle expansion step of Schur complement (if any) */
    824:   if (second_solve) {
    825:     MatMumpsHandleSchur_Private(A,PETSC_TRUE);
    826:   }

    828:   if (mumps->petsc_size > 1) { /* convert mumps distributed solution to petsc mpi x */
    829:     if (mumps->scat_sol && mumps->ICNTL9_pre != mumps->id.ICNTL(9)) {
    830:       /* when id.ICNTL(9) changes, the contents of lsol_loc may change (not its size, lsol_loc), recreates scat_sol */
    831:       VecScatterDestroy(&mumps->scat_sol);
    832:     }
    833:     if (!mumps->scat_sol) { /* create scatter scat_sol */
    834:       ISCreateStride(PETSC_COMM_SELF,mumps->id.lsol_loc,0,1,&is_iden); /* from */
    835:       for (i=0; i<mumps->id.lsol_loc; i++) {
    836:         mumps->id.isol_loc[i] -= 1; /* change Fortran style to C style */
    837:       }
    838:       ISCreateGeneral(PETSC_COMM_SELF,mumps->id.lsol_loc,mumps->id.isol_loc,PETSC_COPY_VALUES,&is_petsc);  /* to */
    839:       VecScatterCreate(mumps->x_seq,is_iden,x,is_petsc,&mumps->scat_sol);
    840:       ISDestroy(&is_iden);
    841:       ISDestroy(&is_petsc);

    843:       mumps->ICNTL9_pre = mumps->id.ICNTL(9); /* save current value of id.ICNTL(9) */
    844:     }

    846:     VecScatterBegin(mumps->scat_sol,mumps->x_seq,x,INSERT_VALUES,SCATTER_FORWARD);
    847:     VecScatterEnd(mumps->scat_sol,mumps->x_seq,x,INSERT_VALUES,SCATTER_FORWARD);
    848:   }
    849:   PetscLogFlops(2.0*mumps->id.RINFO(3));
    850:   return(0);
    851: }

    853: PetscErrorCode MatSolveTranspose_MUMPS(Mat A,Vec b,Vec x)
    854: {
    855:   Mat_MUMPS      *mumps=(Mat_MUMPS*)A->data;

    859:   mumps->id.ICNTL(9) = 0;
    860:   MatSolve_MUMPS(A,b,x);
    861:   mumps->id.ICNTL(9) = 1;
    862:   return(0);
    863: }

    865: PetscErrorCode MatMatSolve_MUMPS(Mat A,Mat B,Mat X)
    866: {
    868:   Mat            Bt = NULL;
    869:   PetscBool      flg, flgT;
    870:   Mat_MUMPS      *mumps=(Mat_MUMPS*)A->data;
    871:   PetscInt       i,nrhs,M;
    872:   PetscScalar    *array,*bray;
    873:   PetscInt       lsol_loc,nlsol_loc,*isol_loc,*idx,*iidx,*idxx,*isol_loc_save;
    874:   MumpsScalar    *sol_loc,*sol_loc_save;
    875:   IS             is_to,is_from;
    876:   PetscInt       k,proc,j,m;
    877:   const PetscInt *rstart;
    878:   Vec            v_mpi,b_seq,x_seq;
    879:   VecScatter     scat_rhs,scat_sol;
    880:   PetscScalar    *aa;
    881:   PetscInt       spnr,*ia,*ja;
    882:   Mat_MPIAIJ     *b = NULL;

    885:   PetscObjectTypeCompareAny((PetscObject)X,&flg,MATSEQDENSE,MATMPIDENSE,NULL);
    886:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONG,"Matrix X must be MATDENSE matrix");

    888:   PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQDENSE,MATMPIDENSE,NULL);
    889:   if (flg) { /* dense B */
    890:     if (B->rmap->n != X->rmap->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Matrix B and X must have same row distribution");
    891:     mumps->id.ICNTL(20)= 0; /* dense RHS */
    892:   } else { /* sparse B */
    893:     PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&flgT);
    894:     if (flgT) { /* input B is transpose of actural RHS matrix,
    895:                  because mumps requires sparse compressed COLUMN storage! See MatMatTransposeSolve_MUMPS() */
    896:       MatTransposeGetMat(B,&Bt);
    897:     } else SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONG,"Matrix B must be MATTRANSPOSEMAT matrix");
    898:     mumps->id.ICNTL(20)= 1; /* sparse RHS */
    899:   }

    901:   MatGetSize(B,&M,&nrhs);
    902:   mumps->id.nrhs = nrhs;
    903:   mumps->id.lrhs = M;
    904:   mumps->id.rhs  = NULL;

    906:   if (mumps->petsc_size == 1) {
    907:     PetscScalar *aa;
    908:     PetscInt    spnr,*ia,*ja;
    909:     PetscBool   second_solve = PETSC_FALSE;

    911:     MatDenseGetArray(X,&array);
    912:     mumps->id.rhs = (MumpsScalar*)array;

    914:     if (!Bt) { /* dense B */
    915:       /* copy B to X */
    916:       MatDenseGetArray(B,&bray);
    917:       PetscMemcpy(array,bray,M*nrhs*sizeof(PetscScalar));
    918:       MatDenseRestoreArray(B,&bray);
    919:     } else { /* sparse B */
    920:       MatSeqAIJGetArray(Bt,&aa);
    921:       MatGetRowIJ(Bt,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    922:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot get IJ structure");
    923:       /* mumps requires ia and ja start at 1! */
    924:       mumps->id.irhs_ptr    = ia;
    925:       mumps->id.irhs_sparse = ja;
    926:       mumps->id.nz_rhs      = ia[spnr] - 1;
    927:       mumps->id.rhs_sparse  = (MumpsScalar*)aa;
    928:     }
    929:     /* handle condensation step of Schur complement (if any) */
    930:     if (mumps->id.size_schur > 0 && (mumps->id.ICNTL(26) < 0 || mumps->id.ICNTL(26) > 2)) {
    931:       second_solve = PETSC_TRUE;
    932:       MatMumpsHandleSchur_Private(A,PETSC_FALSE);
    933:     }
    934:     /* solve phase */
    935:     /*-------------*/
    936:     mumps->id.job = JOB_SOLVE;
    937:     PetscMUMPS_c(mumps);
    938:     if (mumps->id.INFOG(1) < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",mumps->id.INFOG(1));

    940:     /* handle expansion step of Schur complement (if any) */
    941:     if (second_solve) {
    942:       MatMumpsHandleSchur_Private(A,PETSC_TRUE);
    943:     }
    944:     if (Bt) { /* sparse B */
    945:       MatSeqAIJRestoreArray(Bt,&aa);
    946:       MatRestoreRowIJ(Bt,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    947:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot restore IJ structure");
    948:     }
    949:     MatDenseRestoreArray(X,&array);
    950:     return(0);
    951:   }

    953:   /*--------- parallel case: MUMPS requires rhs B to be centralized on the host! --------*/
    954:   if (mumps->petsc_size > 1 && mumps->id.ICNTL(19)) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Parallel Schur complements not yet supported from PETSc\n");

    956:   /* create x_seq to hold mumps local solution */
    957:   isol_loc_save = mumps->id.isol_loc; /* save it for MatSovle() */
    958:   sol_loc_save  = mumps->id.sol_loc;

    960:   lsol_loc  = mumps->id.lsol_loc;
    961:   nlsol_loc = nrhs*lsol_loc;     /* length of sol_loc */
    962:   PetscMalloc2(nlsol_loc,&sol_loc,lsol_loc,&isol_loc);
    963:   mumps->id.sol_loc  = (MumpsScalar*)sol_loc;
    964:   mumps->id.isol_loc = isol_loc;

    966:   VecCreateSeqWithArray(PETSC_COMM_SELF,1,nlsol_loc,(PetscScalar*)sol_loc,&x_seq);

    968:   /* scatter v_mpi to b_seq because MUMPS only supports centralized rhs */
    969:   /* idx: maps from k-th index of v_mpi to (i,j)-th global entry of B;
    970:      iidx: inverse of idx, will be used by scattering mumps x_seq -> petsc X */
    971:   PetscMalloc1(nrhs*M,&idx);

    973:   if (!Bt) { /* dense B */
    974:     /* wrap dense rhs matrix B into a vector v_mpi */
    975:     MatGetLocalSize(B,&m,NULL);
    976:     MatDenseGetArray(B,&bray);
    977:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)B),1,nrhs*m,nrhs*M,(const PetscScalar*)bray,&v_mpi);
    978:     MatDenseRestoreArray(B,&bray);

    980:     /* scatter v_mpi to b_seq in proc[0]. MUMPS requires rhs to be centralized on the host! */
    981:     if (!mumps->myid) {
    982:       MatGetOwnershipRanges(B,&rstart);
    983:       k = 0;
    984:       for (proc=0; proc<mumps->petsc_size; proc++){
    985:         for (j=0; j<nrhs; j++){
    986:           for (i=rstart[proc]; i<rstart[proc+1]; i++){
    987:             idx[k++]      = j*M + i;
    988:           }
    989:         }
    990:       }

    992:       VecCreateSeq(PETSC_COMM_SELF,nrhs*M,&b_seq);
    993:       ISCreateGeneral(PETSC_COMM_SELF,nrhs*M,idx,PETSC_COPY_VALUES,&is_to);
    994:       ISCreateStride(PETSC_COMM_SELF,nrhs*M,0,1,&is_from);
    995:     } else {
    996:       VecCreateSeq(PETSC_COMM_SELF,0,&b_seq);
    997:       ISCreateStride(PETSC_COMM_SELF,0,0,1,&is_to);
    998:       ISCreateStride(PETSC_COMM_SELF,0,0,1,&is_from);
    999:     }
    1000:     VecScatterCreate(v_mpi,is_from,b_seq,is_to,&scat_rhs);
    1001:     VecScatterBegin(scat_rhs,v_mpi,b_seq,INSERT_VALUES,SCATTER_FORWARD);
    1002:     ISDestroy(&is_to);
    1003:     ISDestroy(&is_from);
    1004:     VecScatterEnd(scat_rhs,v_mpi,b_seq,INSERT_VALUES,SCATTER_FORWARD);

    1006:     if (!mumps->myid) { /* define rhs on the host */
    1007:       VecGetArray(b_seq,&bray);
    1008:       mumps->id.rhs = (MumpsScalar*)bray;
    1009:       VecRestoreArray(b_seq,&bray);
    1010:     }

    1012:   } else { /* sparse B */
    1013:     b = (Mat_MPIAIJ*)Bt->data;

    1015:     /* wrap dense X into a vector v_mpi */
    1016:     MatGetLocalSize(X,&m,NULL);
    1017:     MatDenseGetArray(X,&bray);
    1018:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)X),1,nrhs*m,nrhs*M,(const PetscScalar*)bray,&v_mpi);
    1019:     MatDenseRestoreArray(X,&bray);

    1021:     if (!mumps->myid) {
    1022:       MatSeqAIJGetArray(b->A,&aa);
    1023:       MatGetRowIJ(b->A,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    1024:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot get IJ structure");
    1025:       /* mumps requires ia and ja start at 1! */
    1026:       mumps->id.irhs_ptr    = ia;
    1027:       mumps->id.irhs_sparse = ja;
    1028:       mumps->id.nz_rhs      = ia[spnr] - 1;
    1029:       mumps->id.rhs_sparse  = (MumpsScalar*)aa;
    1030:     } else {
    1031:       mumps->id.irhs_ptr    = NULL;
    1032:       mumps->id.irhs_sparse = NULL;
    1033:       mumps->id.nz_rhs      = 0;
    1034:       mumps->id.rhs_sparse  = NULL;
    1035:     }
    1036:   }

    1038:   /* solve phase */
    1039:   /*-------------*/
    1040:   mumps->id.job = JOB_SOLVE;
    1041:   PetscMUMPS_c(mumps);
    1042:   if (mumps->id.INFOG(1) < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",mumps->id.INFOG(1));

    1044:   /* scatter mumps distributed solution to petsc vector v_mpi, which shares local arrays with solution matrix X */
    1045:   MatDenseGetArray(X,&array);
    1046:   VecPlaceArray(v_mpi,array);

    1048:   /* create scatter scat_sol */
    1049:   MatGetOwnershipRanges(X,&rstart);
    1050:   /* iidx: inverse of idx computed above, used for scattering mumps x_seq to petsc X */
    1051:   iidx = idx;
    1052:   k    = 0;
    1053:   for (proc=0; proc<mumps->petsc_size; proc++){
    1054:     for (j=0; j<nrhs; j++){
    1055:       for (i=rstart[proc]; i<rstart[proc+1]; i++) iidx[j*M + i] = k++;
    1056:     }
    1057:   }

    1059:   PetscMalloc1(nlsol_loc,&idxx);
    1060:   ISCreateStride(PETSC_COMM_SELF,nlsol_loc,0,1,&is_from);
    1061:   for (i=0; i<lsol_loc; i++) {
    1062:     isol_loc[i] -= 1; /* change Fortran style to C style */
    1063:     idxx[i] = iidx[isol_loc[i]];
    1064:     for (j=1; j<nrhs; j++){
    1065:       idxx[j*lsol_loc+i] = iidx[isol_loc[i]+j*M];
    1066:     }
    1067:   }
    1068:   ISCreateGeneral(PETSC_COMM_SELF,nlsol_loc,idxx,PETSC_COPY_VALUES,&is_to);
    1069:   VecScatterCreate(x_seq,is_from,v_mpi,is_to,&scat_sol);
    1070:   VecScatterBegin(scat_sol,x_seq,v_mpi,INSERT_VALUES,SCATTER_FORWARD);
    1071:   ISDestroy(&is_from);
    1072:   ISDestroy(&is_to);
    1073:   VecScatterEnd(scat_sol,x_seq,v_mpi,INSERT_VALUES,SCATTER_FORWARD);
    1074:   MatDenseRestoreArray(X,&array);

    1076:   /* free spaces */
    1077:   mumps->id.sol_loc  = sol_loc_save;
    1078:   mumps->id.isol_loc = isol_loc_save;

    1080:   PetscFree2(sol_loc,isol_loc);
    1081:   PetscFree(idx);
    1082:   PetscFree(idxx);
    1083:   VecDestroy(&x_seq);
    1084:   VecDestroy(&v_mpi);
    1085:   if (Bt) {
    1086:     if (!mumps->myid) {
    1087:       b = (Mat_MPIAIJ*)Bt->data;
    1088:       MatSeqAIJRestoreArray(b->A,&aa);
    1089:       MatRestoreRowIJ(b->A,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    1090:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot restore IJ structure");
    1091:     }
    1092:   } else {
    1093:     VecDestroy(&b_seq);
    1094:     VecScatterDestroy(&scat_rhs);
    1095:   }
    1096:   VecScatterDestroy(&scat_sol);
    1097:   PetscLogFlops(2.0*nrhs*mumps->id.RINFO(3));
    1098:   return(0);
    1099: }

    1101: PetscErrorCode MatMatTransposeSolve_MUMPS(Mat A,Mat Bt,Mat X)
    1102: {
    1104:   PetscBool      flg;
    1105:   Mat            B;

    1108:   PetscObjectTypeCompareAny((PetscObject)Bt,&flg,MATSEQAIJ,MATMPIAIJ,NULL);
    1109:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)Bt),PETSC_ERR_ARG_WRONG,"Matrix Bt must be MATAIJ matrix");

    1111:   /* Create B=Bt^T that uses Bt's data structure */
    1112:   MatCreateTranspose(Bt,&B);

    1114:   MatMatSolve_MUMPS(A,B,X);
    1115:   MatDestroy(&B);
    1116:   return(0);
    1117: }

    1119: #if !defined(PETSC_USE_COMPLEX)
    1120: /*
    1121:   input:
    1122:    F:        numeric factor
    1123:   output:
    1124:    nneg:     total number of negative pivots
    1125:    nzero:    total number of zero pivots
    1126:    npos:     (global dimension of F) - nneg - nzero
    1127: */
    1128: PetscErrorCode MatGetInertia_SBAIJMUMPS(Mat F,int *nneg,int *nzero,int *npos)
    1129: {
    1130:   Mat_MUMPS      *mumps =(Mat_MUMPS*)F->data;
    1132:   PetscMPIInt    size;

    1135:   MPI_Comm_size(PetscObjectComm((PetscObject)F),&size);
    1136:   /* MUMPS 4.3.1 calls ScaLAPACK when ICNTL(13)=0 (default), which does not offer the possibility to compute the inertia of a dense matrix. Set ICNTL(13)=1 to skip ScaLAPACK */
    1137:   if (size > 1 && mumps->id.ICNTL(13) != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"ICNTL(13)=%d. -mat_mumps_icntl_13 must be set as 1 for correct global matrix inertia\n",mumps->id.INFOG(13));

    1139:   if (nneg) *nneg = mumps->id.INFOG(12);
    1140:   if (nzero || npos) {
    1141:     if (mumps->id.ICNTL(24) != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"-mat_mumps_icntl_24 must be set as 1 for null pivot row detection");
    1142:     if (nzero) *nzero = mumps->id.INFOG(28);
    1143:     if (npos) *npos   = F->rmap->N - (mumps->id.INFOG(12) + mumps->id.INFOG(28));
    1144:   }
    1145:   return(0);
    1146: }
    1147: #endif

    1149: PetscErrorCode MatMumpsGatherNonzerosOnMaster(MatReuse reuse,Mat_MUMPS *mumps)
    1150: {
    1152:   PetscInt       i,nz=0,*irn,*jcn=0;
    1153:   PetscScalar    *val=0;
    1154:   PetscMPIInt    mpinz,*recvcount=NULL,*displs=NULL;

    1157:   if (mumps->omp_comm_size > 1) {
    1158:     if (reuse == MAT_INITIAL_MATRIX) {
    1159:       /* master first gathers counts of nonzeros to receive */
    1160:       if (mumps->is_omp_master) { PetscMalloc2(mumps->omp_comm_size,&recvcount,mumps->omp_comm_size,&displs); }
    1161:       PetscMPIIntCast(mumps->nz,&mpinz);
    1162:       MPI_Gather(&mpinz,1,MPI_INT,recvcount,1,MPI_INT,0/*root*/,mumps->omp_comm);

    1164:       /* master allocates memory to receive nonzeros */
    1165:       if (mumps->is_omp_master) {
    1166:         displs[0] = 0;
    1167:         for (i=1; i<mumps->omp_comm_size; i++) displs[i] = displs[i-1] + recvcount[i-1];
    1168:         nz   = displs[mumps->omp_comm_size-1] + recvcount[mumps->omp_comm_size-1];
    1169:         PetscMalloc(2*nz*sizeof(PetscInt)+nz*sizeof(PetscScalar),&irn);
    1170:         jcn  = irn + nz;
    1171:         val  = (PetscScalar*)(jcn + nz);
    1172:       }

    1174:       /* save the gatherv plan */
    1175:       mumps->mpinz     = mpinz; /* used as send count */
    1176:       mumps->recvcount = recvcount;
    1177:       mumps->displs    = displs;

    1179:       /* master gathers nonzeros */
    1180:       MPI_Gatherv(mumps->irn,mpinz,MPIU_INT,irn,mumps->recvcount,mumps->displs,MPIU_INT,0/*root*/,mumps->omp_comm);
    1181:       MPI_Gatherv(mumps->jcn,mpinz,MPIU_INT,jcn,mumps->recvcount,mumps->displs,MPIU_INT,0/*root*/,mumps->omp_comm);
    1182:       MPI_Gatherv(mumps->val,mpinz,MPIU_SCALAR,val,mumps->recvcount,mumps->displs,MPIU_SCALAR,0/*root*/,mumps->omp_comm);

    1184:       /* master frees its row/col/val and replaces them with bigger arrays */
    1185:       if (mumps->is_omp_master) {
    1186:         PetscFree(mumps->irn); /* irn/jcn/val are allocated together so free only irn */
    1187:         mumps->nz  = nz; /* it is a sum of mpinz over omp_comm */
    1188:         mumps->irn = irn;
    1189:         mumps->jcn = jcn;
    1190:         mumps->val = val;
    1191:       }
    1192:     } else {
    1193:       MPI_Gatherv((mumps->is_omp_master?MPI_IN_PLACE:mumps->val),mumps->mpinz,MPIU_SCALAR,mumps->val,mumps->recvcount,mumps->displs,MPIU_SCALAR,0/*root*/,mumps->omp_comm);
    1194:     }
    1195:   }
    1196:   return(0);
    1197: }

    1199: PetscErrorCode MatFactorNumeric_MUMPS(Mat F,Mat A,const MatFactorInfo *info)
    1200: {
    1201:   Mat_MUMPS      *mumps =(Mat_MUMPS*)(F)->data;
    1203:   PetscBool      isMPIAIJ;

    1206:   if (mumps->id.INFOG(1) < 0) {
    1207:     if (mumps->id.INFOG(1) == -6) {
    1208:       PetscInfo2(A,"MatFactorNumeric is called with singular matrix structure, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1209:     }
    1210:     PetscInfo2(A,"MatFactorNumeric is called after analysis phase fails, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1211:     return(0);
    1212:   }

    1214:   (*mumps->ConvertToTriples)(A, 1, MAT_REUSE_MATRIX, &mumps->nz, &mumps->irn, &mumps->jcn, &mumps->val);
    1215:   MatMumpsGatherNonzerosOnMaster(MAT_REUSE_MATRIX,mumps);

    1217:   /* numerical factorization phase */
    1218:   /*-------------------------------*/
    1219:   mumps->id.job = JOB_FACTNUMERIC;
    1220:   if (!mumps->id.ICNTL(18)) { /* A is centralized */
    1221:     if (!mumps->myid) {
    1222:       mumps->id.a = (MumpsScalar*)mumps->val;
    1223:     }
    1224:   } else {
    1225:     mumps->id.a_loc = (MumpsScalar*)mumps->val;
    1226:   }
    1227:   PetscMUMPS_c(mumps);
    1228:   if (mumps->id.INFOG(1) < 0) {
    1229:     if (A->erroriffailure) {
    1230:       SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in numerical factorization phase: INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1231:     } else {
    1232:       if (mumps->id.INFOG(1) == -10) { /* numerically singular matrix */
    1233:         PetscInfo2(F,"matrix is numerically singular, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1234:         F->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
    1235:       } else if (mumps->id.INFOG(1) == -13) {
    1236:         PetscInfo2(F,"MUMPS in numerical factorization phase: INFOG(1)=%d, cannot allocate required memory %d megabytes\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1237:         F->factorerrortype = MAT_FACTOR_OUTMEMORY;
    1238:       } else if (mumps->id.INFOG(1) == -8 || mumps->id.INFOG(1) == -9 || (-16 < mumps->id.INFOG(1) && mumps->id.INFOG(1) < -10) ) {
    1239:         PetscInfo2(F,"MUMPS in numerical factorization phase: INFOG(1)=%d, INFO(2)=%d, problem with workarray \n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1240:         F->factorerrortype = MAT_FACTOR_OUTMEMORY;
    1241:       } else {
    1242:         PetscInfo2(F,"MUMPS in numerical factorization phase: INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1243:         F->factorerrortype = MAT_FACTOR_OTHER;
    1244:       }
    1245:     }
    1246:   }
    1247:   if (!mumps->myid && mumps->id.ICNTL(16) > 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"  mumps->id.ICNTL(16):=%d\n",mumps->id.INFOG(16));

    1249:   F->assembled    = PETSC_TRUE;
    1250:   mumps->matstruc = SAME_NONZERO_PATTERN;
    1251:   if (F->schur) { /* reset Schur status to unfactored */
    1252:     if (mumps->id.ICNTL(19) == 1) { /* stored by rows */
    1253:       mumps->id.ICNTL(19) = 2;
    1254:       MatTranspose(F->schur,MAT_INPLACE_MATRIX,&F->schur);
    1255:     }
    1256:     MatFactorRestoreSchurComplement(F,NULL,MAT_FACTOR_SCHUR_UNFACTORED);
    1257:   }

    1259:   /* just to be sure that ICNTL(19) value returned by a call from MatMumpsGetIcntl is always consistent */
    1260:   if (!mumps->sym && mumps->id.ICNTL(19) && mumps->id.ICNTL(19) != 1) mumps->id.ICNTL(19) = 3;

    1262:   if (!mumps->is_omp_master) mumps->id.INFO(23) = 0;
    1263:   if (mumps->petsc_size > 1) {
    1264:     PetscInt    lsol_loc;
    1265:     PetscScalar *sol_loc;

    1267:     PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&isMPIAIJ);

    1269:     /* distributed solution; Create x_seq=sol_loc for repeated use */
    1270:     if (mumps->x_seq) {
    1271:       VecScatterDestroy(&mumps->scat_sol);
    1272:       PetscFree2(mumps->id.sol_loc,mumps->id.isol_loc);
    1273:       VecDestroy(&mumps->x_seq);
    1274:     }
    1275:     lsol_loc = mumps->id.INFO(23); /* length of sol_loc */
    1276:     PetscMalloc2(lsol_loc,&sol_loc,lsol_loc,&mumps->id.isol_loc);
    1277:     mumps->id.lsol_loc = lsol_loc;
    1278:     mumps->id.sol_loc = (MumpsScalar*)sol_loc;
    1279:     VecCreateSeqWithArray(PETSC_COMM_SELF,1,lsol_loc,sol_loc,&mumps->x_seq);
    1280:   }
    1281:   PetscLogFlops(mumps->id.RINFO(2));
    1282:   return(0);
    1283: }

    1285: /* Sets MUMPS options from the options database */
    1286: PetscErrorCode PetscSetMUMPSFromOptions(Mat F, Mat A)
    1287: {
    1288:   Mat_MUMPS      *mumps = (Mat_MUMPS*)F->data;
    1290:   PetscInt       icntl,info[40],i,ninfo=40;
    1291:   PetscBool      flg;

    1294:   PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"MUMPS Options","Mat");
    1295:   PetscOptionsInt("-mat_mumps_icntl_1","ICNTL(1): output stream for error messages","None",mumps->id.ICNTL(1),&icntl,&flg);
    1296:   if (flg) mumps->id.ICNTL(1) = icntl;
    1297:   PetscOptionsInt("-mat_mumps_icntl_2","ICNTL(2): output stream for diagnostic printing, statistics, and warning","None",mumps->id.ICNTL(2),&icntl,&flg);
    1298:   if (flg) mumps->id.ICNTL(2) = icntl;
    1299:   PetscOptionsInt("-mat_mumps_icntl_3","ICNTL(3): output stream for global information, collected on the host","None",mumps->id.ICNTL(3),&icntl,&flg);
    1300:   if (flg) mumps->id.ICNTL(3) = icntl;

    1302:   PetscOptionsInt("-mat_mumps_icntl_4","ICNTL(4): level of printing (0 to 4)","None",mumps->id.ICNTL(4),&icntl,&flg);
    1303:   if (flg) mumps->id.ICNTL(4) = icntl;
    1304:   if (mumps->id.ICNTL(4) || PetscLogPrintInfo) mumps->id.ICNTL(3) = 6; /* resume MUMPS default id.ICNTL(3) = 6 */

    1306:   PetscOptionsInt("-mat_mumps_icntl_6","ICNTL(6): permutes to a zero-free diagonal and/or scale the matrix (0 to 7)","None",mumps->id.ICNTL(6),&icntl,&flg);
    1307:   if (flg) mumps->id.ICNTL(6) = icntl;

    1309:   PetscOptionsInt("-mat_mumps_icntl_7","ICNTL(7): computes a symmetric permutation in sequential analysis (0 to 7). 3=Scotch, 4=PORD, 5=Metis","None",mumps->id.ICNTL(7),&icntl,&flg);
    1310:   if (flg) {
    1311:     if (icntl== 1 && mumps->petsc_size > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"pivot order be set by the user in PERM_IN -- not supported by the PETSc/MUMPS interface\n");
    1312:     else mumps->id.ICNTL(7) = icntl;
    1313:   }

    1315:   PetscOptionsInt("-mat_mumps_icntl_8","ICNTL(8): scaling strategy (-2 to 8 or 77)","None",mumps->id.ICNTL(8),&mumps->id.ICNTL(8),NULL);
    1316:   /* PetscOptionsInt("-mat_mumps_icntl_9","ICNTL(9): computes the solution using A or A^T","None",mumps->id.ICNTL(9),&mumps->id.ICNTL(9),NULL); handled by MatSolveTranspose_MUMPS() */
    1317:   PetscOptionsInt("-mat_mumps_icntl_10","ICNTL(10): max num of refinements","None",mumps->id.ICNTL(10),&mumps->id.ICNTL(10),NULL);
    1318:   PetscOptionsInt("-mat_mumps_icntl_11","ICNTL(11): statistics related to an error analysis (via -ksp_view)","None",mumps->id.ICNTL(11),&mumps->id.ICNTL(11),NULL);
    1319:   PetscOptionsInt("-mat_mumps_icntl_12","ICNTL(12): an ordering strategy for symmetric matrices (0 to 3)","None",mumps->id.ICNTL(12),&mumps->id.ICNTL(12),NULL);
    1320:   PetscOptionsInt("-mat_mumps_icntl_13","ICNTL(13): parallelism of the root node (enable ScaLAPACK) and its splitting","None",mumps->id.ICNTL(13),&mumps->id.ICNTL(13),NULL);
    1321:   PetscOptionsInt("-mat_mumps_icntl_14","ICNTL(14): percentage increase in the estimated working space","None",mumps->id.ICNTL(14),&mumps->id.ICNTL(14),NULL);
    1322:   PetscOptionsInt("-mat_mumps_icntl_19","ICNTL(19): computes the Schur complement","None",mumps->id.ICNTL(19),&mumps->id.ICNTL(19),NULL);
    1323:   if (mumps->id.ICNTL(19) <= 0 || mumps->id.ICNTL(19) > 3) { /* reset any schur data (if any) */
    1324:     MatDestroy(&F->schur);
    1325:     MatMumpsResetSchur_Private(mumps);
    1326:   }
    1327:   /* PetscOptionsInt("-mat_mumps_icntl_20","ICNTL(20): the format (dense or sparse) of the right-hand sides","None",mumps->id.ICNTL(20),&mumps->id.ICNTL(20),NULL); -- sparse rhs is not supported in PETSc API */
    1328:   /* PetscOptionsInt("-mat_mumps_icntl_21","ICNTL(21): the distribution (centralized or distributed) of the solution vectors","None",mumps->id.ICNTL(21),&mumps->id.ICNTL(21),NULL); we only use distributed solution vector */

    1330:   PetscOptionsInt("-mat_mumps_icntl_22","ICNTL(22): in-core/out-of-core factorization and solve (0 or 1)","None",mumps->id.ICNTL(22),&mumps->id.ICNTL(22),NULL);
    1331:   PetscOptionsInt("-mat_mumps_icntl_23","ICNTL(23): max size of the working memory (MB) that can allocate per processor","None",mumps->id.ICNTL(23),&mumps->id.ICNTL(23),NULL);
    1332:   PetscOptionsInt("-mat_mumps_icntl_24","ICNTL(24): detection of null pivot rows (0 or 1)","None",mumps->id.ICNTL(24),&mumps->id.ICNTL(24),NULL);
    1333:   if (mumps->id.ICNTL(24)) {
    1334:     mumps->id.ICNTL(13) = 1; /* turn-off ScaLAPACK to help with the correct detection of null pivots */
    1335:   }

    1337:   PetscOptionsInt("-mat_mumps_icntl_25","ICNTL(25): computes a solution of a deficient matrix and a null space basis","None",mumps->id.ICNTL(25),&mumps->id.ICNTL(25),NULL);
    1338:   PetscOptionsInt("-mat_mumps_icntl_26","ICNTL(26): drives the solution phase if a Schur complement matrix","None",mumps->id.ICNTL(26),&mumps->id.ICNTL(26),NULL);
    1339:   PetscOptionsInt("-mat_mumps_icntl_27","ICNTL(27): the blocking size for multiple right-hand sides","None",mumps->id.ICNTL(27),&mumps->id.ICNTL(27),NULL);
    1340:   PetscOptionsInt("-mat_mumps_icntl_28","ICNTL(28): use 1 for sequential analysis and ictnl(7) ordering, or 2 for parallel analysis and ictnl(29) ordering","None",mumps->id.ICNTL(28),&mumps->id.ICNTL(28),NULL);
    1341:   PetscOptionsInt("-mat_mumps_icntl_29","ICNTL(29): parallel ordering 1 = ptscotch, 2 = parmetis","None",mumps->id.ICNTL(29),&mumps->id.ICNTL(29),NULL);
    1342:   /* PetscOptionsInt("-mat_mumps_icntl_30","ICNTL(30): compute user-specified set of entries in inv(A)","None",mumps->id.ICNTL(30),&mumps->id.ICNTL(30),NULL); */ /* call MatMumpsGetInverse() directly */
    1343:   PetscOptionsInt("-mat_mumps_icntl_31","ICNTL(31): indicates which factors may be discarded during factorization","None",mumps->id.ICNTL(31),&mumps->id.ICNTL(31),NULL);
    1344:   /* PetscOptionsInt("-mat_mumps_icntl_32","ICNTL(32): performs the forward elemination of the right-hand sides during factorization","None",mumps->id.ICNTL(32),&mumps->id.ICNTL(32),NULL);  -- not supported by PETSc API */
    1345:   PetscOptionsInt("-mat_mumps_icntl_33","ICNTL(33): compute determinant","None",mumps->id.ICNTL(33),&mumps->id.ICNTL(33),NULL);
    1346:   PetscOptionsInt("-mat_mumps_icntl_35","ICNTL(35): activates Block Lock Rank (BLR) based factorization","None",mumps->id.ICNTL(35),&mumps->id.ICNTL(35),NULL);

    1348:   PetscOptionsReal("-mat_mumps_cntl_1","CNTL(1): relative pivoting threshold","None",mumps->id.CNTL(1),&mumps->id.CNTL(1),NULL);
    1349:   PetscOptionsReal("-mat_mumps_cntl_2","CNTL(2): stopping criterion of refinement","None",mumps->id.CNTL(2),&mumps->id.CNTL(2),NULL);
    1350:   PetscOptionsReal("-mat_mumps_cntl_3","CNTL(3): absolute pivoting threshold","None",mumps->id.CNTL(3),&mumps->id.CNTL(3),NULL);
    1351:   PetscOptionsReal("-mat_mumps_cntl_4","CNTL(4): value for static pivoting","None",mumps->id.CNTL(4),&mumps->id.CNTL(4),NULL);
    1352:   PetscOptionsReal("-mat_mumps_cntl_5","CNTL(5): fixation for null pivots","None",mumps->id.CNTL(5),&mumps->id.CNTL(5),NULL);
    1353:   PetscOptionsReal("-mat_mumps_cntl_7","CNTL(7): dropping parameter used during BLR","None",mumps->id.CNTL(7),&mumps->id.CNTL(7),NULL);

    1355:   PetscOptionsString("-mat_mumps_ooc_tmpdir", "out of core directory", "None", mumps->id.ooc_tmpdir, mumps->id.ooc_tmpdir, 256, NULL);

    1357:   PetscOptionsIntArray("-mat_mumps_view_info","request INFO local to each processor","",info,&ninfo,NULL);
    1358:   if (ninfo) {
    1359:     if (ninfo > 40) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"number of INFO %d must <= 40\n",ninfo);
    1360:     PetscMalloc1(ninfo,&mumps->info);
    1361:     mumps->ninfo = ninfo;
    1362:     for (i=0; i<ninfo; i++) {
    1363:       if (info[i] < 0 || info[i]>40) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"index of INFO %d must between 1 and 40\n",ninfo);
    1364:       else  mumps->info[i] = info[i];
    1365:     }
    1366:   }

    1368:   PetscOptionsEnd();
    1369:   return(0);
    1370: }

    1372: PetscErrorCode PetscInitializeMUMPS(Mat A,Mat_MUMPS *mumps)
    1373: {
    1375:   PetscInt       nthreads=0;

    1378:   mumps->petsc_comm = PetscObjectComm((PetscObject)A);
    1379:   MPI_Comm_size(mumps->petsc_comm,&mumps->petsc_size);
    1380:   MPI_Comm_rank(mumps->petsc_comm,&mumps->myid); /* so that code like "if (!myid)" still works even if mumps_comm is different */

    1382:   PetscOptionsHasName(NULL,NULL,"-mat_mumps_use_omp_threads",&mumps->use_petsc_omp_support);
    1383:   if (mumps->use_petsc_omp_support) nthreads = -1; /* -1 will let PetscOmpCtrlCreate() guess a proper value when user did not supply one */
    1384:   PetscOptionsGetInt(NULL,NULL,"-mat_mumps_use_omp_threads",&nthreads,NULL);
    1385:   if (mumps->use_petsc_omp_support) {
    1386: #if defined(PETSC_HAVE_OPENMP_SUPPORT)
    1387:     PetscOmpCtrlCreate(mumps->petsc_comm,nthreads,&mumps->omp_ctrl);
    1388:     PetscOmpCtrlGetOmpComms(mumps->omp_ctrl,&mumps->omp_comm,&mumps->mumps_comm,&mumps->is_omp_master);
    1389: #else
    1390:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"the system does not have PETSc OpenMP support but you added the -mat_mumps_use_omp_threads option. Configure PETSc with --with-openmp --download-hwloc (or --with-hwloc) to enable it, see more in MATSOLVERMUMPS manual\n");
    1391: #endif
    1392:   } else {
    1393:     mumps->omp_comm      = PETSC_COMM_SELF;
    1394:     mumps->mumps_comm    = mumps->petsc_comm;
    1395:     mumps->is_omp_master = PETSC_TRUE;
    1396:   }
    1397:   MPI_Comm_size(mumps->omp_comm,&mumps->omp_comm_size);

    1399:   mumps->id.comm_fortran = MPI_Comm_c2f(mumps->mumps_comm);
    1400:   mumps->id.job = JOB_INIT;
    1401:   mumps->id.par = 1;  /* host participates factorizaton and solve */
    1402:   mumps->id.sym = mumps->sym;

    1404:   PetscMUMPS_c(mumps);

    1406:   /* copy MUMPS default control values from master to slaves. Although slaves do not call MUMPS, they may access these values in code.
    1407:      For example, ICNTL(9) is initialized to 1 by MUMPS and slaves check ICNTL(9) in MatSolve_MUMPS.
    1408:    */
    1409:   MPI_Bcast(mumps->id.icntl,40,MPIU_INT, 0,mumps->omp_comm); /* see MUMPS-5.1.2 Manual Section 9 */
    1410:   MPI_Bcast(mumps->id.cntl, 15,MPIU_REAL,0,mumps->omp_comm);

    1412:   mumps->scat_rhs     = NULL;
    1413:   mumps->scat_sol     = NULL;

    1415:   /* set PETSc-MUMPS default options - override MUMPS default */
    1416:   mumps->id.ICNTL(3) = 0;
    1417:   mumps->id.ICNTL(4) = 0;
    1418:   if (mumps->petsc_size == 1) {
    1419:     mumps->id.ICNTL(18) = 0;   /* centralized assembled matrix input */
    1420:   } else {
    1421:     mumps->id.ICNTL(18) = 3;   /* distributed assembled matrix input */
    1422:     mumps->id.ICNTL(20) = 0;   /* rhs is in dense format */
    1423:     mumps->id.ICNTL(21) = 1;   /* distributed solution */
    1424:   }

    1426:   /* schur */
    1427:   mumps->id.size_schur      = 0;
    1428:   mumps->id.listvar_schur   = NULL;
    1429:   mumps->id.schur           = NULL;
    1430:   mumps->sizeredrhs         = 0;
    1431:   mumps->schur_sol          = NULL;
    1432:   mumps->schur_sizesol      = 0;
    1433:   return(0);
    1434: }

    1436: PetscErrorCode MatFactorSymbolic_MUMPS_ReportIfError(Mat F,Mat A,const MatFactorInfo *info,Mat_MUMPS *mumps)
    1437: {

    1441:   MPI_Bcast(mumps->id.infog, 40,MPIU_INT, 0,mumps->omp_comm); /* see MUMPS-5.1.2 manual p82 */
    1442:   MPI_Bcast(mumps->id.rinfog,20,MPIU_REAL,0,mumps->omp_comm);
    1443:   if (mumps->id.INFOG(1) < 0) {
    1444:     if (A->erroriffailure) {
    1445:       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in analysis phase: INFOG(1)=%d\n",mumps->id.INFOG(1));
    1446:     } else {
    1447:       if (mumps->id.INFOG(1) == -6) {
    1448:         PetscInfo2(F,"matrix is singular in structure, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1449:         F->factorerrortype = MAT_FACTOR_STRUCT_ZEROPIVOT;
    1450:       } else if (mumps->id.INFOG(1) == -5 || mumps->id.INFOG(1) == -7) {
    1451:         PetscInfo2(F,"problem of workspace, INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1452:         F->factorerrortype = MAT_FACTOR_OUTMEMORY;
    1453:       } else {
    1454:         PetscInfo2(F,"Error reported by MUMPS in analysis phase: INFOG(1)=%d, INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));
    1455:         F->factorerrortype = MAT_FACTOR_OTHER;
    1456:       }
    1457:     }
    1458:   }
    1459:   return(0);
    1460: }

    1462: /* Note Petsc r(=c) permutation is used when mumps->id.ICNTL(7)==1 with centralized assembled matrix input; otherwise r and c are ignored */
    1463: PetscErrorCode MatLUFactorSymbolic_AIJMUMPS(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info)
    1464: {
    1465:   Mat_MUMPS      *mumps = (Mat_MUMPS*)F->data;
    1467:   Vec            b;
    1468:   IS             is_iden;
    1469:   const PetscInt M = A->rmap->N;

    1472:   mumps->matstruc = DIFFERENT_NONZERO_PATTERN;

    1474:   /* Set MUMPS options from the options database */
    1475:   PetscSetMUMPSFromOptions(F,A);

    1477:   (*mumps->ConvertToTriples)(A, 1, MAT_INITIAL_MATRIX, &mumps->nz, &mumps->irn, &mumps->jcn, &mumps->val);
    1478:   MatMumpsGatherNonzerosOnMaster(MAT_INITIAL_MATRIX,mumps);

    1480:   /* analysis phase */
    1481:   /*----------------*/
    1482:   mumps->id.job = JOB_FACTSYMBOLIC;
    1483:   mumps->id.n   = M;
    1484:   switch (mumps->id.ICNTL(18)) {
    1485:   case 0:  /* centralized assembled matrix input */
    1486:     if (!mumps->myid) {
    1487:       mumps->id.nz =mumps->nz; mumps->id.irn=mumps->irn; mumps->id.jcn=mumps->jcn;
    1488:       if (mumps->id.ICNTL(6)>1) {
    1489:         mumps->id.a = (MumpsScalar*)mumps->val;
    1490:       }
    1491:       if (mumps->id.ICNTL(7) == 1) { /* use user-provide matrix ordering - assuming r = c ordering */
    1492:         /*
    1493:         PetscBool      flag;
    1494:         ISEqual(r,c,&flag);
    1495:         if (!flag) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"row_perm != col_perm");
    1496:         ISView(r,PETSC_VIEWER_STDOUT_SELF);
    1497:          */
    1498:         if (!mumps->myid) {
    1499:           const PetscInt *idx;
    1500:           PetscInt       i,*perm_in;

    1502:           PetscMalloc1(M,&perm_in);
    1503:           ISGetIndices(r,&idx);

    1505:           mumps->id.perm_in = perm_in;
    1506:           for (i=0; i<M; i++) perm_in[i] = idx[i]+1; /* perm_in[]: start from 1, not 0! */
    1507:           ISRestoreIndices(r,&idx);
    1508:         }
    1509:       }
    1510:     }
    1511:     break;
    1512:   case 3:  /* distributed assembled matrix input (size>1) */
    1513:     mumps->id.nz_loc = mumps->nz;
    1514:     mumps->id.irn_loc=mumps->irn; mumps->id.jcn_loc=mumps->jcn;
    1515:     if (mumps->id.ICNTL(6)>1) {
    1516:       mumps->id.a_loc = (MumpsScalar*)mumps->val;
    1517:     }
    1518:     /* MUMPS only supports centralized rhs. Create scatter scat_rhs for repeated use in MatSolve() */
    1519:     if (!mumps->myid) {
    1520:       VecCreateSeq(PETSC_COMM_SELF,A->rmap->N,&mumps->b_seq);
    1521:       ISCreateStride(PETSC_COMM_SELF,A->rmap->N,0,1,&is_iden);
    1522:     } else {
    1523:       VecCreateSeq(PETSC_COMM_SELF,0,&mumps->b_seq);
    1524:       ISCreateStride(PETSC_COMM_SELF,0,0,1,&is_iden);
    1525:     }
    1526:     MatCreateVecs(A,NULL,&b);
    1527:     VecScatterCreate(b,is_iden,mumps->b_seq,is_iden,&mumps->scat_rhs);
    1528:     ISDestroy(&is_iden);
    1529:     VecDestroy(&b);
    1530:     break;
    1531:   }
    1532:   PetscMUMPS_c(mumps);
    1533:   MatFactorSymbolic_MUMPS_ReportIfError(F,A,info,mumps);

    1535:   F->ops->lufactornumeric = MatFactorNumeric_MUMPS;
    1536:   F->ops->solve           = MatSolve_MUMPS;
    1537:   F->ops->solvetranspose  = MatSolveTranspose_MUMPS;
    1538:   F->ops->matsolve        = MatMatSolve_MUMPS;
    1539:   F->ops->mattransposesolve = MatMatTransposeSolve_MUMPS;
    1540:   return(0);
    1541: }

    1543: /* Note the Petsc r and c permutations are ignored */
    1544: PetscErrorCode MatLUFactorSymbolic_BAIJMUMPS(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info)
    1545: {
    1546:   Mat_MUMPS      *mumps = (Mat_MUMPS*)F->data;
    1548:   Vec            b;
    1549:   IS             is_iden;
    1550:   const PetscInt M = A->rmap->N;

    1553:   mumps->matstruc = DIFFERENT_NONZERO_PATTERN;

    1555:   /* Set MUMPS options from the options database */
    1556:   PetscSetMUMPSFromOptions(F,A);

    1558:   (*mumps->ConvertToTriples)(A, 1, MAT_INITIAL_MATRIX, &mumps->nz, &mumps->irn, &mumps->jcn, &mumps->val);
    1559:   MatMumpsGatherNonzerosOnMaster(MAT_INITIAL_MATRIX,mumps);

    1561:   /* analysis phase */
    1562:   /*----------------*/
    1563:   mumps->id.job = JOB_FACTSYMBOLIC;
    1564:   mumps->id.n   = M;
    1565:   switch (mumps->id.ICNTL(18)) {
    1566:   case 0:  /* centralized assembled matrix input */
    1567:     if (!mumps->myid) {
    1568:       mumps->id.nz =mumps->nz; mumps->id.irn=mumps->irn; mumps->id.jcn=mumps->jcn;
    1569:       if (mumps->id.ICNTL(6)>1) {
    1570:         mumps->id.a = (MumpsScalar*)mumps->val;
    1571:       }
    1572:     }
    1573:     break;
    1574:   case 3:  /* distributed assembled matrix input (size>1) */
    1575:     mumps->id.nz_loc = mumps->nz;
    1576:     mumps->id.irn_loc=mumps->irn; mumps->id.jcn_loc=mumps->jcn;
    1577:     if (mumps->id.ICNTL(6)>1) {
    1578:       mumps->id.a_loc = (MumpsScalar*)mumps->val;
    1579:     }
    1580:     /* MUMPS only supports centralized rhs. Create scatter scat_rhs for repeated use in MatSolve() */
    1581:     if (!mumps->myid) {
    1582:       VecCreateSeq(PETSC_COMM_SELF,A->cmap->N,&mumps->b_seq);
    1583:       ISCreateStride(PETSC_COMM_SELF,A->cmap->N,0,1,&is_iden);
    1584:     } else {
    1585:       VecCreateSeq(PETSC_COMM_SELF,0,&mumps->b_seq);
    1586:       ISCreateStride(PETSC_COMM_SELF,0,0,1,&is_iden);
    1587:     }
    1588:     MatCreateVecs(A,NULL,&b);
    1589:     VecScatterCreate(b,is_iden,mumps->b_seq,is_iden,&mumps->scat_rhs);
    1590:     ISDestroy(&is_iden);
    1591:     VecDestroy(&b);
    1592:     break;
    1593:   }
    1594:   PetscMUMPS_c(mumps);
    1595:   MatFactorSymbolic_MUMPS_ReportIfError(F,A,info,mumps);

    1597:   F->ops->lufactornumeric = MatFactorNumeric_MUMPS;
    1598:   F->ops->solve           = MatSolve_MUMPS;
    1599:   F->ops->solvetranspose  = MatSolveTranspose_MUMPS;
    1600:   return(0);
    1601: }

    1603: /* Note the Petsc r permutation and factor info are ignored */
    1604: PetscErrorCode MatCholeskyFactorSymbolic_MUMPS(Mat F,Mat A,IS r,const MatFactorInfo *info)
    1605: {
    1606:   Mat_MUMPS      *mumps = (Mat_MUMPS*)F->data;
    1608:   Vec            b;
    1609:   IS             is_iden;
    1610:   const PetscInt M = A->rmap->N;

    1613:   mumps->matstruc = DIFFERENT_NONZERO_PATTERN;

    1615:   /* Set MUMPS options from the options database */
    1616:   PetscSetMUMPSFromOptions(F,A);

    1618:   (*mumps->ConvertToTriples)(A, 1, MAT_INITIAL_MATRIX, &mumps->nz, &mumps->irn, &mumps->jcn, &mumps->val);
    1619:   MatMumpsGatherNonzerosOnMaster(MAT_INITIAL_MATRIX,mumps);

    1621:   /* analysis phase */
    1622:   /*----------------*/
    1623:   mumps->id.job = JOB_FACTSYMBOLIC;
    1624:   mumps->id.n   = M;
    1625:   switch (mumps->id.ICNTL(18)) {
    1626:   case 0:  /* centralized assembled matrix input */
    1627:     if (!mumps->myid) {
    1628:       mumps->id.nz =mumps->nz; mumps->id.irn=mumps->irn; mumps->id.jcn=mumps->jcn;
    1629:       if (mumps->id.ICNTL(6)>1) {
    1630:         mumps->id.a = (MumpsScalar*)mumps->val;
    1631:       }
    1632:     }
    1633:     break;
    1634:   case 3:  /* distributed assembled matrix input (size>1) */
    1635:     mumps->id.nz_loc = mumps->nz;
    1636:     mumps->id.irn_loc=mumps->irn; mumps->id.jcn_loc=mumps->jcn;
    1637:     if (mumps->id.ICNTL(6)>1) {
    1638:       mumps->id.a_loc = (MumpsScalar*)mumps->val;
    1639:     }
    1640:     /* MUMPS only supports centralized rhs. Create scatter scat_rhs for repeated use in MatSolve() */
    1641:     if (!mumps->myid) {
    1642:       VecCreateSeq(PETSC_COMM_SELF,A->cmap->N,&mumps->b_seq);
    1643:       ISCreateStride(PETSC_COMM_SELF,A->cmap->N,0,1,&is_iden);
    1644:     } else {
    1645:       VecCreateSeq(PETSC_COMM_SELF,0,&mumps->b_seq);
    1646:       ISCreateStride(PETSC_COMM_SELF,0,0,1,&is_iden);
    1647:     }
    1648:     MatCreateVecs(A,NULL,&b);
    1649:     VecScatterCreate(b,is_iden,mumps->b_seq,is_iden,&mumps->scat_rhs);
    1650:     ISDestroy(&is_iden);
    1651:     VecDestroy(&b);
    1652:     break;
    1653:   }
    1654:   PetscMUMPS_c(mumps);
    1655:   MatFactorSymbolic_MUMPS_ReportIfError(F,A,info,mumps);

    1657:   F->ops->choleskyfactornumeric = MatFactorNumeric_MUMPS;
    1658:   F->ops->solve                 = MatSolve_MUMPS;
    1659:   F->ops->solvetranspose        = MatSolve_MUMPS;
    1660:   F->ops->matsolve              = MatMatSolve_MUMPS;
    1661: #if defined(PETSC_USE_COMPLEX)
    1662:   F->ops->getinertia = NULL;
    1663: #else
    1664:   F->ops->getinertia = MatGetInertia_SBAIJMUMPS;
    1665: #endif
    1666:   return(0);
    1667: }

    1669: PetscErrorCode MatView_MUMPS(Mat A,PetscViewer viewer)
    1670: {
    1671:   PetscErrorCode    ierr;
    1672:   PetscBool         iascii;
    1673:   PetscViewerFormat format;
    1674:   Mat_MUMPS         *mumps=(Mat_MUMPS*)A->data;

    1677:   /* check if matrix is mumps type */
    1678:   if (A->ops->solve != MatSolve_MUMPS) return(0);

    1680:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    1681:   if (iascii) {
    1682:     PetscViewerGetFormat(viewer,&format);
    1683:     if (format == PETSC_VIEWER_ASCII_INFO) {
    1684:       PetscViewerASCIIPrintf(viewer,"MUMPS run parameters:\n");
    1685:       PetscViewerASCIIPrintf(viewer,"  SYM (matrix type):                   %d \n",mumps->id.sym);
    1686:       PetscViewerASCIIPrintf(viewer,"  PAR (host participation):            %d \n",mumps->id.par);
    1687:       PetscViewerASCIIPrintf(viewer,"  ICNTL(1) (output for error):         %d \n",mumps->id.ICNTL(1));
    1688:       PetscViewerASCIIPrintf(viewer,"  ICNTL(2) (output of diagnostic msg): %d \n",mumps->id.ICNTL(2));
    1689:       PetscViewerASCIIPrintf(viewer,"  ICNTL(3) (output for global info):   %d \n",mumps->id.ICNTL(3));
    1690:       PetscViewerASCIIPrintf(viewer,"  ICNTL(4) (level of printing):        %d \n",mumps->id.ICNTL(4));
    1691:       PetscViewerASCIIPrintf(viewer,"  ICNTL(5) (input mat struct):         %d \n",mumps->id.ICNTL(5));
    1692:       PetscViewerASCIIPrintf(viewer,"  ICNTL(6) (matrix prescaling):        %d \n",mumps->id.ICNTL(6));
    1693:       PetscViewerASCIIPrintf(viewer,"  ICNTL(7) (sequential matrix ordering):%d \n",mumps->id.ICNTL(7));
    1694:       PetscViewerASCIIPrintf(viewer,"  ICNTL(8) (scaling strategy):        %d \n",mumps->id.ICNTL(8));
    1695:       PetscViewerASCIIPrintf(viewer,"  ICNTL(10) (max num of refinements):  %d \n",mumps->id.ICNTL(10));
    1696:       PetscViewerASCIIPrintf(viewer,"  ICNTL(11) (error analysis):          %d \n",mumps->id.ICNTL(11));
    1697:       if (mumps->id.ICNTL(11)>0) {
    1698:         PetscViewerASCIIPrintf(viewer,"    RINFOG(4) (inf norm of input mat):        %g\n",mumps->id.RINFOG(4));
    1699:         PetscViewerASCIIPrintf(viewer,"    RINFOG(5) (inf norm of solution):         %g\n",mumps->id.RINFOG(5));
    1700:         PetscViewerASCIIPrintf(viewer,"    RINFOG(6) (inf norm of residual):         %g\n",mumps->id.RINFOG(6));
    1701:         PetscViewerASCIIPrintf(viewer,"    RINFOG(7),RINFOG(8) (backward error est): %g, %g\n",mumps->id.RINFOG(7),mumps->id.RINFOG(8));
    1702:         PetscViewerASCIIPrintf(viewer,"    RINFOG(9) (error estimate):               %g \n",mumps->id.RINFOG(9));
    1703:         PetscViewerASCIIPrintf(viewer,"    RINFOG(10),RINFOG(11)(condition numbers): %g, %g\n",mumps->id.RINFOG(10),mumps->id.RINFOG(11));
    1704:       }
    1705:       PetscViewerASCIIPrintf(viewer,"  ICNTL(12) (efficiency control):                         %d \n",mumps->id.ICNTL(12));
    1706:       PetscViewerASCIIPrintf(viewer,"  ICNTL(13) (efficiency control):                         %d \n",mumps->id.ICNTL(13));
    1707:       PetscViewerASCIIPrintf(viewer,"  ICNTL(14) (percentage of estimated workspace increase): %d \n",mumps->id.ICNTL(14));
    1708:       /* ICNTL(15-17) not used */
    1709:       PetscViewerASCIIPrintf(viewer,"  ICNTL(18) (input mat struct):                           %d \n",mumps->id.ICNTL(18));
    1710:       PetscViewerASCIIPrintf(viewer,"  ICNTL(19) (Schur complement info):                      %d \n",mumps->id.ICNTL(19));
    1711:       PetscViewerASCIIPrintf(viewer,"  ICNTL(20) (rhs sparse pattern):                         %d \n",mumps->id.ICNTL(20));
    1712:       PetscViewerASCIIPrintf(viewer,"  ICNTL(21) (solution struct):                            %d \n",mumps->id.ICNTL(21));
    1713:       PetscViewerASCIIPrintf(viewer,"  ICNTL(22) (in-core/out-of-core facility):               %d \n",mumps->id.ICNTL(22));
    1714:       PetscViewerASCIIPrintf(viewer,"  ICNTL(23) (max size of memory can be allocated locally):%d \n",mumps->id.ICNTL(23));

    1716:       PetscViewerASCIIPrintf(viewer,"  ICNTL(24) (detection of null pivot rows):               %d \n",mumps->id.ICNTL(24));
    1717:       PetscViewerASCIIPrintf(viewer,"  ICNTL(25) (computation of a null space basis):          %d \n",mumps->id.ICNTL(25));
    1718:       PetscViewerASCIIPrintf(viewer,"  ICNTL(26) (Schur options for rhs or solution):          %d \n",mumps->id.ICNTL(26));
    1719:       PetscViewerASCIIPrintf(viewer,"  ICNTL(27) (experimental parameter):                     %d \n",mumps->id.ICNTL(27));
    1720:       PetscViewerASCIIPrintf(viewer,"  ICNTL(28) (use parallel or sequential ordering):        %d \n",mumps->id.ICNTL(28));
    1721:       PetscViewerASCIIPrintf(viewer,"  ICNTL(29) (parallel ordering):                          %d \n",mumps->id.ICNTL(29));

    1723:       PetscViewerASCIIPrintf(viewer,"  ICNTL(30) (user-specified set of entries in inv(A)):    %d \n",mumps->id.ICNTL(30));
    1724:       PetscViewerASCIIPrintf(viewer,"  ICNTL(31) (factors is discarded in the solve phase):    %d \n",mumps->id.ICNTL(31));
    1725:       PetscViewerASCIIPrintf(viewer,"  ICNTL(33) (compute determinant):                        %d \n",mumps->id.ICNTL(33));
    1726:       PetscViewerASCIIPrintf(viewer,"  ICNTL(35) (activate BLR based factorization):           %d \n",mumps->id.ICNTL(35));

    1728:       PetscViewerASCIIPrintf(viewer,"  CNTL(1) (relative pivoting threshold):      %g \n",mumps->id.CNTL(1));
    1729:       PetscViewerASCIIPrintf(viewer,"  CNTL(2) (stopping criterion of refinement): %g \n",mumps->id.CNTL(2));
    1730:       PetscViewerASCIIPrintf(viewer,"  CNTL(3) (absolute pivoting threshold):      %g \n",mumps->id.CNTL(3));
    1731:       PetscViewerASCIIPrintf(viewer,"  CNTL(4) (value of static pivoting):         %g \n",mumps->id.CNTL(4));
    1732:       PetscViewerASCIIPrintf(viewer,"  CNTL(5) (fixation for null pivots):         %g \n",mumps->id.CNTL(5));
    1733:       PetscViewerASCIIPrintf(viewer,"  CNTL(7) (dropping parameter for BLR):       %g \n",mumps->id.CNTL(7));

    1735:       /* infomation local to each processor */
    1736:       PetscViewerASCIIPrintf(viewer, "  RINFO(1) (local estimated flops for the elimination after analysis): \n");
    1737:       PetscViewerASCIIPushSynchronized(viewer);
    1738:       PetscViewerASCIISynchronizedPrintf(viewer,"    [%d] %g \n",mumps->myid,mumps->id.RINFO(1));
    1739:       PetscViewerFlush(viewer);
    1740:       PetscViewerASCIIPrintf(viewer, "  RINFO(2) (local estimated flops for the assembly after factorization): \n");
    1741:       PetscViewerASCIISynchronizedPrintf(viewer,"    [%d]  %g \n",mumps->myid,mumps->id.RINFO(2));
    1742:       PetscViewerFlush(viewer);
    1743:       PetscViewerASCIIPrintf(viewer, "  RINFO(3) (local estimated flops for the elimination after factorization): \n");
    1744:       PetscViewerASCIISynchronizedPrintf(viewer,"    [%d]  %g \n",mumps->myid,mumps->id.RINFO(3));
    1745:       PetscViewerFlush(viewer);

    1747:       PetscViewerASCIIPrintf(viewer, "  INFO(15) (estimated size of (in MB) MUMPS internal data for running numerical factorization): \n");
    1748:       PetscViewerASCIISynchronizedPrintf(viewer,"  [%d] %d \n",mumps->myid,mumps->id.INFO(15));
    1749:       PetscViewerFlush(viewer);

    1751:       PetscViewerASCIIPrintf(viewer, "  INFO(16) (size of (in MB) MUMPS internal data used during numerical factorization): \n");
    1752:       PetscViewerASCIISynchronizedPrintf(viewer,"    [%d] %d \n",mumps->myid,mumps->id.INFO(16));
    1753:       PetscViewerFlush(viewer);

    1755:       PetscViewerASCIIPrintf(viewer, "  INFO(23) (num of pivots eliminated on this processor after factorization): \n");
    1756:       PetscViewerASCIISynchronizedPrintf(viewer,"    [%d] %d \n",mumps->myid,mumps->id.INFO(23));
    1757:       PetscViewerFlush(viewer);

    1759:       if (mumps->ninfo && mumps->ninfo <= 40){
    1760:         PetscInt i;
    1761:         for (i=0; i<mumps->ninfo; i++){
    1762:           PetscViewerASCIIPrintf(viewer, "  INFO(%d): \n",mumps->info[i]);
    1763:           PetscViewerASCIISynchronizedPrintf(viewer,"    [%d] %d \n",mumps->myid,mumps->id.INFO(mumps->info[i]));
    1764:           PetscViewerFlush(viewer);
    1765:         }
    1766:       }
    1767:       PetscViewerASCIIPopSynchronized(viewer);

    1769:       if (!mumps->myid) { /* information from the host */
    1770:         PetscViewerASCIIPrintf(viewer,"  RINFOG(1) (global estimated flops for the elimination after analysis): %g \n",mumps->id.RINFOG(1));
    1771:         PetscViewerASCIIPrintf(viewer,"  RINFOG(2) (global estimated flops for the assembly after factorization): %g \n",mumps->id.RINFOG(2));
    1772:         PetscViewerASCIIPrintf(viewer,"  RINFOG(3) (global estimated flops for the elimination after factorization): %g \n",mumps->id.RINFOG(3));
    1773:         PetscViewerASCIIPrintf(viewer,"  (RINFOG(12) RINFOG(13))*2^INFOG(34) (determinant): (%g,%g)*(2^%d)\n",mumps->id.RINFOG(12),mumps->id.RINFOG(13),mumps->id.INFOG(34));

    1775:         PetscViewerASCIIPrintf(viewer,"  INFOG(3) (estimated real workspace for factors on all processors after analysis): %d \n",mumps->id.INFOG(3));
    1776:         PetscViewerASCIIPrintf(viewer,"  INFOG(4) (estimated integer workspace for factors on all processors after analysis): %d \n",mumps->id.INFOG(4));
    1777:         PetscViewerASCIIPrintf(viewer,"  INFOG(5) (estimated maximum front size in the complete tree): %d \n",mumps->id.INFOG(5));
    1778:         PetscViewerASCIIPrintf(viewer,"  INFOG(6) (number of nodes in the complete tree): %d \n",mumps->id.INFOG(6));
    1779:         PetscViewerASCIIPrintf(viewer,"  INFOG(7) (ordering option effectively use after analysis): %d \n",mumps->id.INFOG(7));
    1780:         PetscViewerASCIIPrintf(viewer,"  INFOG(8) (structural symmetry in percent of the permuted matrix after analysis): %d \n",mumps->id.INFOG(8));
    1781:         PetscViewerASCIIPrintf(viewer,"  INFOG(9) (total real/complex workspace to store the matrix factors after factorization): %d \n",mumps->id.INFOG(9));
    1782:         PetscViewerASCIIPrintf(viewer,"  INFOG(10) (total integer space store the matrix factors after factorization): %d \n",mumps->id.INFOG(10));
    1783:         PetscViewerASCIIPrintf(viewer,"  INFOG(11) (order of largest frontal matrix after factorization): %d \n",mumps->id.INFOG(11));
    1784:         PetscViewerASCIIPrintf(viewer,"  INFOG(12) (number of off-diagonal pivots): %d \n",mumps->id.INFOG(12));
    1785:         PetscViewerASCIIPrintf(viewer,"  INFOG(13) (number of delayed pivots after factorization): %d \n",mumps->id.INFOG(13));
    1786:         PetscViewerASCIIPrintf(viewer,"  INFOG(14) (number of memory compress after factorization): %d \n",mumps->id.INFOG(14));
    1787:         PetscViewerASCIIPrintf(viewer,"  INFOG(15) (number of steps of iterative refinement after solution): %d \n",mumps->id.INFOG(15));
    1788:         PetscViewerASCIIPrintf(viewer,"  INFOG(16) (estimated size (in MB) of all MUMPS internal data for factorization after analysis: value on the most memory consuming processor): %d \n",mumps->id.INFOG(16));
    1789:         PetscViewerASCIIPrintf(viewer,"  INFOG(17) (estimated size of all MUMPS internal data for factorization after analysis: sum over all processors): %d \n",mumps->id.INFOG(17));
    1790:         PetscViewerASCIIPrintf(viewer,"  INFOG(18) (size of all MUMPS internal data allocated during factorization: value on the most memory consuming processor): %d \n",mumps->id.INFOG(18));
    1791:         PetscViewerASCIIPrintf(viewer,"  INFOG(19) (size of all MUMPS internal data allocated during factorization: sum over all processors): %d \n",mumps->id.INFOG(19));
    1792:         PetscViewerASCIIPrintf(viewer,"  INFOG(20) (estimated number of entries in the factors): %d \n",mumps->id.INFOG(20));
    1793:         PetscViewerASCIIPrintf(viewer,"  INFOG(21) (size in MB of memory effectively used during factorization - value on the most memory consuming processor): %d \n",mumps->id.INFOG(21));
    1794:         PetscViewerASCIIPrintf(viewer,"  INFOG(22) (size in MB of memory effectively used during factorization - sum over all processors): %d \n",mumps->id.INFOG(22));
    1795:         PetscViewerASCIIPrintf(viewer,"  INFOG(23) (after analysis: value of ICNTL(6) effectively used): %d \n",mumps->id.INFOG(23));
    1796:         PetscViewerASCIIPrintf(viewer,"  INFOG(24) (after analysis: value of ICNTL(12) effectively used): %d \n",mumps->id.INFOG(24));
    1797:         PetscViewerASCIIPrintf(viewer,"  INFOG(25) (after factorization: number of pivots modified by static pivoting): %d \n",mumps->id.INFOG(25));
    1798:         PetscViewerASCIIPrintf(viewer,"  INFOG(28) (after factorization: number of null pivots encountered): %d\n",mumps->id.INFOG(28));
    1799:         PetscViewerASCIIPrintf(viewer,"  INFOG(29) (after factorization: effective number of entries in the factors (sum over all processors)): %d\n",mumps->id.INFOG(29));
    1800:         PetscViewerASCIIPrintf(viewer,"  INFOG(30, 31) (after solution: size in Mbytes of memory used during solution phase): %d, %d\n",mumps->id.INFOG(30),mumps->id.INFOG(31));
    1801:         PetscViewerASCIIPrintf(viewer,"  INFOG(32) (after analysis: type of analysis done): %d\n",mumps->id.INFOG(32));
    1802:         PetscViewerASCIIPrintf(viewer,"  INFOG(33) (value used for ICNTL(8)): %d\n",mumps->id.INFOG(33));
    1803:         PetscViewerASCIIPrintf(viewer,"  INFOG(34) (exponent of the determinant if determinant is requested): %d\n",mumps->id.INFOG(34));
    1804:       }
    1805:     }
    1806:   }
    1807:   return(0);
    1808: }

    1810: PetscErrorCode MatGetInfo_MUMPS(Mat A,MatInfoType flag,MatInfo *info)
    1811: {
    1812:   Mat_MUMPS *mumps =(Mat_MUMPS*)A->data;

    1815:   info->block_size        = 1.0;
    1816:   info->nz_allocated      = mumps->id.INFOG(20);
    1817:   info->nz_used           = mumps->id.INFOG(20);
    1818:   info->nz_unneeded       = 0.0;
    1819:   info->assemblies        = 0.0;
    1820:   info->mallocs           = 0.0;
    1821:   info->memory            = 0.0;
    1822:   info->fill_ratio_given  = 0;
    1823:   info->fill_ratio_needed = 0;
    1824:   info->factor_mallocs    = 0;
    1825:   return(0);
    1826: }

    1828: /* -------------------------------------------------------------------------------------------*/
    1829: PetscErrorCode MatFactorSetSchurIS_MUMPS(Mat F, IS is)
    1830: {
    1831:   Mat_MUMPS      *mumps =(Mat_MUMPS*)F->data;
    1832:   const PetscInt *idxs;
    1833:   PetscInt       size,i;

    1837:   ISGetLocalSize(is,&size);
    1838:   if (mumps->petsc_size > 1) {
    1839:     PetscBool ls,gs; /* gs is false if any rank other than root has non-empty IS */

    1841:     ls   = mumps->myid ? (size ? PETSC_FALSE : PETSC_TRUE) : PETSC_TRUE; /* always true on root; false on others if their size != 0 */
    1842:     MPI_Allreduce(&ls,&gs,1,MPIU_BOOL,MPI_LAND,mumps->petsc_comm);
    1843:     if (!gs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MUMPS distributed parallel Schur complements not yet supported from PETSc\n");
    1844:   }
    1845:   if (mumps->id.size_schur != size) {
    1846:     PetscFree2(mumps->id.listvar_schur,mumps->id.schur);
    1847:     mumps->id.size_schur = size;
    1848:     mumps->id.schur_lld  = size;
    1849:     PetscMalloc2(size,&mumps->id.listvar_schur,size*size,&mumps->id.schur);
    1850:   }

    1852:   /* Schur complement matrix */
    1853:   MatCreateSeqDense(PETSC_COMM_SELF,mumps->id.size_schur,mumps->id.size_schur,(PetscScalar*)mumps->id.schur,&F->schur);
    1854:   if (mumps->sym == 1) {
    1855:     MatSetOption(F->schur,MAT_SPD,PETSC_TRUE);
    1856:   }

    1858:   /* MUMPS expects Fortran style indices */
    1859:   ISGetIndices(is,&idxs);
    1860:   PetscMemcpy(mumps->id.listvar_schur,idxs,size*sizeof(PetscInt));
    1861:   for (i=0;i<size;i++) mumps->id.listvar_schur[i]++;
    1862:   ISRestoreIndices(is,&idxs);
    1863:   if (mumps->petsc_size > 1) {
    1864:     mumps->id.ICNTL(19) = 1; /* MUMPS returns Schur centralized on the host */
    1865:   } else {
    1866:     if (F->factortype == MAT_FACTOR_LU) {
    1867:       mumps->id.ICNTL(19) = 3; /* MUMPS returns full matrix */
    1868:     } else {
    1869:       mumps->id.ICNTL(19) = 2; /* MUMPS returns lower triangular part */
    1870:     }
    1871:   }
    1872:   /* set a special value of ICNTL (not handled my MUMPS) to be used in the solve phase by PETSc */
    1873:   mumps->id.ICNTL(26) = -1;
    1874:   return(0);
    1875: }

    1877: /* -------------------------------------------------------------------------------------------*/
    1878: PetscErrorCode MatFactorCreateSchurComplement_MUMPS(Mat F,Mat* S)
    1879: {
    1880:   Mat            St;
    1881:   Mat_MUMPS      *mumps =(Mat_MUMPS*)F->data;
    1882:   PetscScalar    *array;
    1883: #if defined(PETSC_USE_COMPLEX)
    1884:   PetscScalar    im = PetscSqrtScalar((PetscScalar)-1.0);
    1885: #endif

    1889:   if (!mumps->id.ICNTL(19)) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ORDER,"Schur complement mode not selected! You should call MatFactorSetSchurIS to enable it");
    1890:   MatCreate(PETSC_COMM_SELF,&St);
    1891:   MatSetSizes(St,PETSC_DECIDE,PETSC_DECIDE,mumps->id.size_schur,mumps->id.size_schur);
    1892:   MatSetType(St,MATDENSE);
    1893:   MatSetUp(St);
    1894:   MatDenseGetArray(St,&array);
    1895:   if (!mumps->sym) { /* MUMPS always return a full matrix */
    1896:     if (mumps->id.ICNTL(19) == 1) { /* stored by rows */
    1897:       PetscInt i,j,N=mumps->id.size_schur;
    1898:       for (i=0;i<N;i++) {
    1899:         for (j=0;j<N;j++) {
    1900: #if !defined(PETSC_USE_COMPLEX)
    1901:           PetscScalar val = mumps->id.schur[i*N+j];
    1902: #else
    1903:           PetscScalar val = mumps->id.schur[i*N+j].r + im*mumps->id.schur[i*N+j].i;
    1904: #endif
    1905:           array[j*N+i] = val;
    1906:         }
    1907:       }
    1908:     } else { /* stored by columns */
    1909:       PetscMemcpy(array,mumps->id.schur,mumps->id.size_schur*mumps->id.size_schur*sizeof(PetscScalar));
    1910:     }
    1911:   } else { /* either full or lower-triangular (not packed) */
    1912:     if (mumps->id.ICNTL(19) == 2) { /* lower triangular stored by columns */
    1913:       PetscInt i,j,N=mumps->id.size_schur;
    1914:       for (i=0;i<N;i++) {
    1915:         for (j=i;j<N;j++) {
    1916: #if !defined(PETSC_USE_COMPLEX)
    1917:           PetscScalar val = mumps->id.schur[i*N+j];
    1918: #else
    1919:           PetscScalar val = mumps->id.schur[i*N+j].r + im*mumps->id.schur[i*N+j].i;
    1920: #endif
    1921:           array[i*N+j] = val;
    1922:           array[j*N+i] = val;
    1923:         }
    1924:       }
    1925:     } else if (mumps->id.ICNTL(19) == 3) { /* full matrix */
    1926:       PetscMemcpy(array,mumps->id.schur,mumps->id.size_schur*mumps->id.size_schur*sizeof(PetscScalar));
    1927:     } else { /* ICNTL(19) == 1 lower triangular stored by rows */
    1928:       PetscInt i,j,N=mumps->id.size_schur;
    1929:       for (i=0;i<N;i++) {
    1930:         for (j=0;j<i+1;j++) {
    1931: #if !defined(PETSC_USE_COMPLEX)
    1932:           PetscScalar val = mumps->id.schur[i*N+j];
    1933: #else
    1934:           PetscScalar val = mumps->id.schur[i*N+j].r + im*mumps->id.schur[i*N+j].i;
    1935: #endif
    1936:           array[i*N+j] = val;
    1937:           array[j*N+i] = val;
    1938:         }
    1939:       }
    1940:     }
    1941:   }
    1942:   MatDenseRestoreArray(St,&array);
    1943:   *S   = St;
    1944:   return(0);
    1945: }

    1947: /* -------------------------------------------------------------------------------------------*/
    1948: PetscErrorCode MatMumpsSetIcntl_MUMPS(Mat F,PetscInt icntl,PetscInt ival)
    1949: {
    1950:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    1953:   mumps->id.ICNTL(icntl) = ival;
    1954:   return(0);
    1955: }

    1957: PetscErrorCode MatMumpsGetIcntl_MUMPS(Mat F,PetscInt icntl,PetscInt *ival)
    1958: {
    1959:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    1962:   *ival = mumps->id.ICNTL(icntl);
    1963:   return(0);
    1964: }

    1966: /*@
    1967:   MatMumpsSetIcntl - Set MUMPS parameter ICNTL()

    1969:    Logically Collective on Mat

    1971:    Input Parameters:
    1972: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    1973: .  icntl - index of MUMPS parameter array ICNTL()
    1974: -  ival - value of MUMPS ICNTL(icntl)

    1976:   Options Database:
    1977: .   -mat_mumps_icntl_<icntl> <ival>

    1979:    Level: beginner

    1981:    References:
    1982: .     MUMPS Users' Guide

    1984: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    1985:  @*/
    1986: PetscErrorCode MatMumpsSetIcntl(Mat F,PetscInt icntl,PetscInt ival)
    1987: {

    1992:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    1995:   PetscTryMethod(F,"MatMumpsSetIcntl_C",(Mat,PetscInt,PetscInt),(F,icntl,ival));
    1996:   return(0);
    1997: }

    1999: /*@
    2000:   MatMumpsGetIcntl - Get MUMPS parameter ICNTL()

    2002:    Logically Collective on Mat

    2004:    Input Parameters:
    2005: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2006: -  icntl - index of MUMPS parameter array ICNTL()

    2008:   Output Parameter:
    2009: .  ival - value of MUMPS ICNTL(icntl)

    2011:    Level: beginner

    2013:    References:
    2014: .     MUMPS Users' Guide

    2016: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2017: @*/
    2018: PetscErrorCode MatMumpsGetIcntl(Mat F,PetscInt icntl,PetscInt *ival)
    2019: {

    2024:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2027:   PetscUseMethod(F,"MatMumpsGetIcntl_C",(Mat,PetscInt,PetscInt*),(F,icntl,ival));
    2028:   return(0);
    2029: }

    2031: /* -------------------------------------------------------------------------------------------*/
    2032: PetscErrorCode MatMumpsSetCntl_MUMPS(Mat F,PetscInt icntl,PetscReal val)
    2033: {
    2034:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2037:   mumps->id.CNTL(icntl) = val;
    2038:   return(0);
    2039: }

    2041: PetscErrorCode MatMumpsGetCntl_MUMPS(Mat F,PetscInt icntl,PetscReal *val)
    2042: {
    2043:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2046:   *val = mumps->id.CNTL(icntl);
    2047:   return(0);
    2048: }

    2050: /*@
    2051:   MatMumpsSetCntl - Set MUMPS parameter CNTL()

    2053:    Logically Collective on Mat

    2055:    Input Parameters:
    2056: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2057: .  icntl - index of MUMPS parameter array CNTL()
    2058: -  val - value of MUMPS CNTL(icntl)

    2060:   Options Database:
    2061: .   -mat_mumps_cntl_<icntl> <val>

    2063:    Level: beginner

    2065:    References:
    2066: .     MUMPS Users' Guide

    2068: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2069: @*/
    2070: PetscErrorCode MatMumpsSetCntl(Mat F,PetscInt icntl,PetscReal val)
    2071: {

    2076:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2079:   PetscTryMethod(F,"MatMumpsSetCntl_C",(Mat,PetscInt,PetscReal),(F,icntl,val));
    2080:   return(0);
    2081: }

    2083: /*@
    2084:   MatMumpsGetCntl - Get MUMPS parameter CNTL()

    2086:    Logically Collective on Mat

    2088:    Input Parameters:
    2089: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2090: -  icntl - index of MUMPS parameter array CNTL()

    2092:   Output Parameter:
    2093: .  val - value of MUMPS CNTL(icntl)

    2095:    Level: beginner

    2097:    References:
    2098: .      MUMPS Users' Guide

    2100: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2101: @*/
    2102: PetscErrorCode MatMumpsGetCntl(Mat F,PetscInt icntl,PetscReal *val)
    2103: {

    2108:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2111:   PetscUseMethod(F,"MatMumpsGetCntl_C",(Mat,PetscInt,PetscReal*),(F,icntl,val));
    2112:   return(0);
    2113: }

    2115: PetscErrorCode MatMumpsGetInfo_MUMPS(Mat F,PetscInt icntl,PetscInt *info)
    2116: {
    2117:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2120:   *info = mumps->id.INFO(icntl);
    2121:   return(0);
    2122: }

    2124: PetscErrorCode MatMumpsGetInfog_MUMPS(Mat F,PetscInt icntl,PetscInt *infog)
    2125: {
    2126:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2129:   *infog = mumps->id.INFOG(icntl);
    2130:   return(0);
    2131: }

    2133: PetscErrorCode MatMumpsGetRinfo_MUMPS(Mat F,PetscInt icntl,PetscReal *rinfo)
    2134: {
    2135:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2138:   *rinfo = mumps->id.RINFO(icntl);
    2139:   return(0);
    2140: }

    2142: PetscErrorCode MatMumpsGetRinfog_MUMPS(Mat F,PetscInt icntl,PetscReal *rinfog)
    2143: {
    2144:   Mat_MUMPS *mumps =(Mat_MUMPS*)F->data;

    2147:   *rinfog = mumps->id.RINFOG(icntl);
    2148:   return(0);
    2149: }

    2151: PetscErrorCode MatMumpsGetInverse_MUMPS(Mat F,Mat spRHS)
    2152: {
    2154:   Mat            Bt = NULL,Btseq = NULL;
    2155:   PetscBool      flg;
    2156:   Mat_MUMPS      *mumps =(Mat_MUMPS*)F->data;
    2157:   PetscScalar    *aa;
    2158:   PetscInt       spnr,*ia,*ja;

    2162:   PetscObjectTypeCompare((PetscObject)spRHS,MATTRANSPOSEMAT,&flg);
    2163:   if (flg) {
    2164:     MatTransposeGetMat(spRHS,&Bt);
    2165:   } else SETERRQ(PetscObjectComm((PetscObject)spRHS),PETSC_ERR_ARG_WRONG,"Matrix spRHS must be type MATTRANSPOSEMAT matrix");

    2167:   MatMumpsSetIcntl(F,30,1);

    2169:   if (mumps->petsc_size > 1) {
    2170:     Mat_MPIAIJ *b = (Mat_MPIAIJ*)Bt->data;
    2171:     Btseq = b->A;
    2172:   } else {
    2173:     Btseq = Bt;
    2174:   }

    2176:   if (!mumps->myid) {
    2177:     MatSeqAIJGetArray(Btseq,&aa);
    2178:     MatGetRowIJ(Btseq,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    2179:     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot get IJ structure");

    2181:     mumps->id.irhs_ptr    = ia;
    2182:     mumps->id.irhs_sparse = ja;
    2183:     mumps->id.nz_rhs      = ia[spnr] - 1;
    2184:     mumps->id.rhs_sparse  = (MumpsScalar*)aa;
    2185:   } else {
    2186:     mumps->id.irhs_ptr    = NULL;
    2187:     mumps->id.irhs_sparse = NULL;
    2188:     mumps->id.nz_rhs      = 0;
    2189:     mumps->id.rhs_sparse  = NULL;
    2190:   }
    2191:   mumps->id.ICNTL(20)   = 1; /* rhs is sparse */
    2192:   mumps->id.ICNTL(21)   = 0; /* solution is in assembled centralized format */

    2194:   /* solve phase */
    2195:   /*-------------*/
    2196:   mumps->id.job = JOB_SOLVE;
    2197:   PetscMUMPS_c(mumps);
    2198:   if (mumps->id.INFOG(1) < 0)
    2199:     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d INFO(2)=%d\n",mumps->id.INFOG(1),mumps->id.INFO(2));

    2201:   if (!mumps->myid) {
    2202:     MatSeqAIJRestoreArray(Btseq,&aa);
    2203:     MatRestoreRowIJ(Btseq,1,PETSC_FALSE,PETSC_FALSE,&spnr,(const PetscInt**)&ia,(const PetscInt**)&ja,&flg);
    2204:     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot get IJ structure");
    2205:   }
    2206:   return(0);
    2207: }

    2209: /*@
    2210:   MatMumpsGetInverse - Get user-specified set of entries in inverse of A

    2212:    Logically Collective on Mat

    2214:    Input Parameters:
    2215: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2216: -  spRHS - sequential sparse matrix in MATTRANSPOSEMAT format holding specified indices in processor[0]

    2218:   Output Parameter:
    2219: . spRHS - requested entries of inverse of A

    2221:    Level: beginner

    2223:    References:
    2224: .      MUMPS Users' Guide

    2226: .seealso: MatGetFactor(), MatCreateTranspose()
    2227: @*/
    2228: PetscErrorCode MatMumpsGetInverse(Mat F,Mat spRHS)
    2229: {

    2234:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2235:   PetscUseMethod(F,"MatMumpsGetInverse_C",(Mat,Mat),(F,spRHS));
    2236:   return(0);
    2237: }

    2239: PetscErrorCode MatMumpsGetInverseTranspose_MUMPS(Mat F,Mat spRHST)
    2240: {
    2242:   Mat            spRHS;

    2245:   MatCreateTranspose(spRHST,&spRHS);
    2246:   MatMumpsGetInverse_MUMPS(F,spRHS);
    2247:   MatDestroy(&spRHS);
    2248:   return(0);
    2249: }

    2251: /*@
    2252:   MatMumpsGetInverseTranspose - Get user-specified set of entries in inverse of matrix A^T

    2254:    Logically Collective on Mat

    2256:    Input Parameters:
    2257: +  F - the factored matrix of A obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2258: -  spRHST - sequential sparse matrix in MATAIJ format holding specified indices of A^T in processor[0]

    2260:   Output Parameter:
    2261: . spRHST - requested entries of inverse of A^T

    2263:    Level: beginner

    2265:    References:
    2266: .      MUMPS Users' Guide

    2268: .seealso: MatGetFactor(), MatCreateTranspose(), MatMumpsGetInverse()
    2269: @*/
    2270: PetscErrorCode MatMumpsGetInverseTranspose(Mat F,Mat spRHST)
    2271: {
    2273:   PetscBool      flg;

    2277:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2278:   PetscObjectTypeCompareAny((PetscObject)spRHST,&flg,MATSEQAIJ,MATMPIAIJ,NULL);
    2279:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)spRHST),PETSC_ERR_ARG_WRONG,"Matrix spRHST must be MATAIJ matrix");

    2281:   PetscUseMethod(F,"MatMumpsGetInverseTranspose_C",(Mat,Mat),(F,spRHST));
    2282:   return(0);
    2283: }

    2285: /*@
    2286:   MatMumpsGetInfo - Get MUMPS parameter INFO()

    2288:    Logically Collective on Mat

    2290:    Input Parameters:
    2291: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2292: -  icntl - index of MUMPS parameter array INFO()

    2294:   Output Parameter:
    2295: .  ival - value of MUMPS INFO(icntl)

    2297:    Level: beginner

    2299:    References:
    2300: .      MUMPS Users' Guide

    2302: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2303: @*/
    2304: PetscErrorCode MatMumpsGetInfo(Mat F,PetscInt icntl,PetscInt *ival)
    2305: {

    2310:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2312:   PetscUseMethod(F,"MatMumpsGetInfo_C",(Mat,PetscInt,PetscInt*),(F,icntl,ival));
    2313:   return(0);
    2314: }

    2316: /*@
    2317:   MatMumpsGetInfog - Get MUMPS parameter INFOG()

    2319:    Logically Collective on Mat

    2321:    Input Parameters:
    2322: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2323: -  icntl - index of MUMPS parameter array INFOG()

    2325:   Output Parameter:
    2326: .  ival - value of MUMPS INFOG(icntl)

    2328:    Level: beginner

    2330:    References:
    2331: .      MUMPS Users' Guide

    2333: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2334: @*/
    2335: PetscErrorCode MatMumpsGetInfog(Mat F,PetscInt icntl,PetscInt *ival)
    2336: {

    2341:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2343:   PetscUseMethod(F,"MatMumpsGetInfog_C",(Mat,PetscInt,PetscInt*),(F,icntl,ival));
    2344:   return(0);
    2345: }

    2347: /*@
    2348:   MatMumpsGetRinfo - Get MUMPS parameter RINFO()

    2350:    Logically Collective on Mat

    2352:    Input Parameters:
    2353: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2354: -  icntl - index of MUMPS parameter array RINFO()

    2356:   Output Parameter:
    2357: .  val - value of MUMPS RINFO(icntl)

    2359:    Level: beginner

    2361:    References:
    2362: .       MUMPS Users' Guide

    2364: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2365: @*/
    2366: PetscErrorCode MatMumpsGetRinfo(Mat F,PetscInt icntl,PetscReal *val)
    2367: {

    2372:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2374:   PetscUseMethod(F,"MatMumpsGetRinfo_C",(Mat,PetscInt,PetscReal*),(F,icntl,val));
    2375:   return(0);
    2376: }

    2378: /*@
    2379:   MatMumpsGetRinfog - Get MUMPS parameter RINFOG()

    2381:    Logically Collective on Mat

    2383:    Input Parameters:
    2384: +  F - the factored matrix obtained by calling MatGetFactor() from PETSc-MUMPS interface
    2385: -  icntl - index of MUMPS parameter array RINFOG()

    2387:   Output Parameter:
    2388: .  val - value of MUMPS RINFOG(icntl)

    2390:    Level: beginner

    2392:    References:
    2393: .      MUMPS Users' Guide

    2395: .seealso: MatGetFactor(), MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog()
    2396: @*/
    2397: PetscErrorCode MatMumpsGetRinfog(Mat F,PetscInt icntl,PetscReal *val)
    2398: {

    2403:   if (!F->factortype) SETERRQ(PetscObjectComm((PetscObject)F),PETSC_ERR_ARG_WRONGSTATE,"Only for factored matrix");
    2405:   PetscUseMethod(F,"MatMumpsGetRinfog_C",(Mat,PetscInt,PetscReal*),(F,icntl,val));
    2406:   return(0);
    2407: }

    2409: /*MC
    2410:   MATSOLVERMUMPS -  A matrix type providing direct solvers (LU and Cholesky) for
    2411:   distributed and sequential matrices via the external package MUMPS.

    2413:   Works with MATAIJ and MATSBAIJ matrices

    2415:   Use ./configure --download-mumps --download-scalapack --download-parmetis --download-metis --download-ptscotch  to have PETSc installed with MUMPS

    2417:   Use ./configure --with-openmp --download-hwloc (or --with-hwloc) to enable running MUMPS in MPI+OpenMP hybrid mode and non-MUMPS in flat-MPI mode. See details below.

    2419:   Use -pc_type cholesky or lu -pc_factor_mat_solver_type mumps to use this direct solver

    2421:   Options Database Keys:
    2422: +  -mat_mumps_icntl_1 - ICNTL(1): output stream for error messages
    2423: .  -mat_mumps_icntl_2 - ICNTL(2): output stream for diagnostic printing, statistics, and warning
    2424: .  -mat_mumps_icntl_3 -  ICNTL(3): output stream for global information, collected on the host
    2425: .  -mat_mumps_icntl_4 -  ICNTL(4): level of printing (0 to 4)
    2426: .  -mat_mumps_icntl_6 - ICNTL(6): permutes to a zero-free diagonal and/or scale the matrix (0 to 7)
    2427: .  -mat_mumps_icntl_7 - ICNTL(7): computes a symmetric permutation in sequential analysis (0 to 7). 3=Scotch, 4=PORD, 5=Metis
    2428: .  -mat_mumps_icntl_8  - ICNTL(8): scaling strategy (-2 to 8 or 77)
    2429: .  -mat_mumps_icntl_10  - ICNTL(10): max num of refinements
    2430: .  -mat_mumps_icntl_11  - ICNTL(11): statistics related to an error analysis (via -ksp_view)
    2431: .  -mat_mumps_icntl_12  - ICNTL(12): an ordering strategy for symmetric matrices (0 to 3)
    2432: .  -mat_mumps_icntl_13  - ICNTL(13): parallelism of the root node (enable ScaLAPACK) and its splitting
    2433: .  -mat_mumps_icntl_14  - ICNTL(14): percentage increase in the estimated working space
    2434: .  -mat_mumps_icntl_19  - ICNTL(19): computes the Schur complement
    2435: .  -mat_mumps_icntl_22  - ICNTL(22): in-core/out-of-core factorization and solve (0 or 1)
    2436: .  -mat_mumps_icntl_23  - ICNTL(23): max size of the working memory (MB) that can allocate per processor
    2437: .  -mat_mumps_icntl_24  - ICNTL(24): detection of null pivot rows (0 or 1)
    2438: .  -mat_mumps_icntl_25  - ICNTL(25): compute a solution of a deficient matrix and a null space basis
    2439: .  -mat_mumps_icntl_26  - ICNTL(26): drives the solution phase if a Schur complement matrix
    2440: .  -mat_mumps_icntl_28  - ICNTL(28): use 1 for sequential analysis and ictnl(7) ordering, or 2 for parallel analysis and ictnl(29) ordering
    2441: .  -mat_mumps_icntl_29 - ICNTL(29): parallel ordering 1 = ptscotch, 2 = parmetis
    2442: .  -mat_mumps_icntl_30 - ICNTL(30): compute user-specified set of entries in inv(A)
    2443: .  -mat_mumps_icntl_31 - ICNTL(31): indicates which factors may be discarded during factorization
    2444: .  -mat_mumps_icntl_33 - ICNTL(33): compute determinant
    2445: .  -mat_mumps_cntl_1  - CNTL(1): relative pivoting threshold
    2446: .  -mat_mumps_cntl_2  -  CNTL(2): stopping criterion of refinement
    2447: .  -mat_mumps_cntl_3 - CNTL(3): absolute pivoting threshold
    2448: .  -mat_mumps_cntl_4 - CNTL(4): value for static pivoting
    2449: .  -mat_mumps_cntl_5 - CNTL(5): fixation for null pivots
    2450: -  -mat_mumps_use_omp_threads [m] - run MUMPS in MPI+OpenMP hybrid mode as if omp_set_num_threads(m) is called before calling MUMPS.
    2451:                                    Default might be the number of cores per CPU package (socket) as reported by hwloc and suggested by the MUMPS manual.

    2453:   Level: beginner

    2455:     Notes:
    2456:     When a MUMPS factorization fails inside a KSP solve, for example with a KSP_DIVERGED_PCSETUP_FAILED, one can find the MUMPS information about the failure by calling
    2457: $          KSPGetPC(ksp,&pc);
    2458: $          PCFactorGetMatrix(pc,&mat);
    2459: $          MatMumpsGetInfo(mat,....);
    2460: $          MatMumpsGetInfog(mat,....); etc.
    2461:            Or you can run with -ksp_error_if_not_converged and the program will be stopped and the information printed in the error message.

    2463:    If you want to run MUMPS in MPI+OpenMP hybrid mode (i.e., enable multithreading in MUMPS), but still want to run the non-MUMPS part
    2464:    (i.e., PETSc part) of your code in the so-called flat-MPI (aka pure-MPI) mode, you need to configure PETSc with --with-openmp --download-hwloc
    2465:    (or --with-hwloc), and have an MPI that supports MPI-3.0's process shared memory (which is usually available). Since MUMPS calls BLAS
    2466:    libraries, to really get performance, you should have multithreaded BLAS libraries such as Intel MKL, AMD ACML, Cray libSci or open sourced
    2467:    OpenBLAS (PETSc has configure options to install/specify them). With these conditions met, you can run your program as before but with
    2468:    an extra option -mat_mumps_use_omp_threads [m]. It works as if we set OMP_NUM_THREADS=m to MUMPS, with m defaults to the number of cores
    2469:    per CPU socket (or package, in hwloc term), or number of PETSc MPI processes on a node, whichever is smaller.

    2471:    By flat-MPI or pure-MPI mode, it means you run your code with as many MPI ranks as the number of cores. For example,
    2472:    if a compute node has 32 cores and you run on two nodes, you may use "mpirun -n 64 ./test". To run MPI+OpenMP hybrid MUMPS,
    2473:    the tranditional way is to set OMP_NUM_THREADS and run with fewer MPI ranks than cores. For example, if you want to have 16 OpenMP
    2474:    threads per rank, then you may use "export OMP_NUM_THREADS=16 && mpirun -n 4 ./test". The problem of this approach is that the non-MUMPS
    2475:    part of your code is run with fewer cores and CPUs are wasted. "-mat_mumps_use_omp_threads [m]" provides an alternative such that
    2476:    you can stil run your code with as many MPI ranks as the number of cores, but have MUMPS run in MPI+OpenMP hybrid mode. In our example,
    2477:    you can use "mpirun -n 64 ./test -mat_mumps_use_omp_threads 16".

    2479:    If you run your code through a job submission system, there are caveats in MPI rank mapping. We use MPI_Comm_split_type to get MPI
    2480:    processes on each compute node. Listing the processes in rank ascending order, we split processes on a node into consecutive groups of
    2481:    size m and create a communicator called omp_comm for each group. Rank 0 in an omp_comm is called the master rank, and others in the omp_comm
    2482:    are called slave ranks (or slaves). Only master ranks are seen to MUMPS and slaves are not. We will free CPUs assigned to slaves (might be set
    2483:    by CPU binding policies in job scripts) and make the CPUs available to the master so that OMP threads spawned by MUMPS can run on the CPUs.
    2484:    In a multi-socket compute node, MPI rank mapping is an issue. Still use the above example and suppose your compute node has two sockets,
    2485:    if you interleave MPI ranks on the two sockets, in other words, even ranks are placed on socket 0, and odd ranks are on socket 1, and bind
    2486:    MPI ranks to cores, then with -mat_mumps_use_omp_threads 16, a master rank (and threads it spawns) will use half cores in socket 0, and half
    2487:    cores in socket 1, that definitely hurts locality. On the other hand, if you map MPI ranks consecutively on the two sockets, then the
    2488:    problem will not happen. Therefore, when you use -mat_mumps_use_omp_threads, you need to keep an eye on your MPI rank mapping and CPU binding.
    2489:    For example, with the Slurm job scheduler, one can use srun --cpu-bind=verbsoe -m block:block to map consecutive MPI ranks to sockets and
    2490:    examine the mapping result.

    2492:    PETSc does not control thread binding in MUMPS. So to get best performance, one still has to set OMP_PROC_BIND and OMP_PLACES in job scripts,
    2493:    for example, export OMP_PLACES=threads and export OMP_PROC_BIND=spread. One does not need to export OMP_NUM_THREADS=m in job scripts as PETSc
    2494:    calls omp_set_num_threads(m) internally before calling MUMPS.

    2496:    References:
    2497: +   1. - Heroux, Michael A., R. Brightwell, and Michael M. Wolf. "Bi-modal MPI and MPI+ threads computing on scalable multicore systems." IJHPCA (Submitted) (2011).
    2498: -   2. - Gutierrez, Samuel K., et al. "Accommodating Thread-Level Heterogeneity in Coupled Parallel Applications." Parallel and Distributed Processing Symposium (IPDPS), 2017 IEEE International. IEEE, 2017.

    2500: .seealso: PCFactorSetMatSolverType(), MatSolverType, MatMumpsSetICntl(), MatMumpsGetIcntl(), MatMumpsSetCntl(), MatMumpsGetCntl(), MatMumpsGetInfo(), MatMumpsGetInfog(), MatMumpsGetRinfo(), MatMumpsGetRinfog(), KSPGetPC(), PCGetFactor(), PCFactorGetMatrix()

    2502: M*/

    2504: static PetscErrorCode MatFactorGetSolverType_mumps(Mat A,MatSolverType *type)
    2505: {
    2507:   *type = MATSOLVERMUMPS;
    2508:   return(0);
    2509: }

    2511: /* MatGetFactor for Seq and MPI AIJ matrices */
    2512: static PetscErrorCode MatGetFactor_aij_mumps(Mat A,MatFactorType ftype,Mat *F)
    2513: {
    2514:   Mat            B;
    2516:   Mat_MUMPS      *mumps;
    2517:   PetscBool      isSeqAIJ;

    2520:   /* Create the factorization matrix */
    2521:   PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isSeqAIJ);
    2522:   MatCreate(PetscObjectComm((PetscObject)A),&B);
    2523:   MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
    2524:   PetscStrallocpy("mumps",&((PetscObject)B)->type_name);
    2525:   MatSetUp(B);

    2527:   PetscNewLog(B,&mumps);

    2529:   B->ops->view        = MatView_MUMPS;
    2530:   B->ops->getinfo     = MatGetInfo_MUMPS;

    2532:   PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_mumps);
    2533:   PetscObjectComposeFunction((PetscObject)B,"MatFactorSetSchurIS_C",MatFactorSetSchurIS_MUMPS);
    2534:   PetscObjectComposeFunction((PetscObject)B,"MatFactorCreateSchurComplement_C",MatFactorCreateSchurComplement_MUMPS);
    2535:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetIcntl_C",MatMumpsSetIcntl_MUMPS);
    2536:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetIcntl_C",MatMumpsGetIcntl_MUMPS);
    2537:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetCntl_C",MatMumpsSetCntl_MUMPS);
    2538:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetCntl_C",MatMumpsGetCntl_MUMPS);
    2539:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfo_C",MatMumpsGetInfo_MUMPS);
    2540:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfog_C",MatMumpsGetInfog_MUMPS);
    2541:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfo_C",MatMumpsGetRinfo_MUMPS);
    2542:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfog_C",MatMumpsGetRinfog_MUMPS);
    2543:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverse_C",MatMumpsGetInverse_MUMPS);
    2544:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverseTranspose_C",MatMumpsGetInverseTranspose_MUMPS);

    2546:   if (ftype == MAT_FACTOR_LU) {
    2547:     B->ops->lufactorsymbolic = MatLUFactorSymbolic_AIJMUMPS;
    2548:     B->factortype            = MAT_FACTOR_LU;
    2549:     if (isSeqAIJ) mumps->ConvertToTriples = MatConvertToTriples_seqaij_seqaij;
    2550:     else mumps->ConvertToTriples = MatConvertToTriples_mpiaij_mpiaij;
    2551:     mumps->sym = 0;
    2552:   } else {
    2553:     B->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_MUMPS;
    2554:     B->factortype                  = MAT_FACTOR_CHOLESKY;
    2555:     if (isSeqAIJ) mumps->ConvertToTriples = MatConvertToTriples_seqaij_seqsbaij;
    2556:     else mumps->ConvertToTriples = MatConvertToTriples_mpiaij_mpisbaij;
    2557: #if defined(PETSC_USE_COMPLEX)
    2558:     mumps->sym = 2;
    2559: #else
    2560:     if (A->spd_set && A->spd) mumps->sym = 1;
    2561:     else                      mumps->sym = 2;
    2562: #endif
    2563:   }

    2565:   /* set solvertype */
    2566:   PetscFree(B->solvertype);
    2567:   PetscStrallocpy(MATSOLVERMUMPS,&B->solvertype);

    2569:   B->ops->destroy = MatDestroy_MUMPS;
    2570:   B->data         = (void*)mumps;

    2572:   PetscInitializeMUMPS(A,mumps);

    2574:   *F = B;
    2575:   return(0);
    2576: }

    2578: /* MatGetFactor for Seq and MPI SBAIJ matrices */
    2579: static PetscErrorCode MatGetFactor_sbaij_mumps(Mat A,MatFactorType ftype,Mat *F)
    2580: {
    2581:   Mat            B;
    2583:   Mat_MUMPS      *mumps;
    2584:   PetscBool      isSeqSBAIJ;

    2587:   if (ftype != MAT_FACTOR_CHOLESKY) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot use PETSc SBAIJ matrices with MUMPS LU, use AIJ matrix");
    2588:   if (A->rmap->bs > 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Cannot use PETSc SBAIJ matrices with block size > 1 with MUMPS Cholesky, use AIJ matrix instead");
    2589:   PetscObjectTypeCompare((PetscObject)A,MATSEQSBAIJ,&isSeqSBAIJ);
    2590:   /* Create the factorization matrix */
    2591:   MatCreate(PetscObjectComm((PetscObject)A),&B);
    2592:   MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
    2593:   PetscStrallocpy("mumps",&((PetscObject)B)->type_name);
    2594:   MatSetUp(B);

    2596:   PetscNewLog(B,&mumps);
    2597:   if (isSeqSBAIJ) {
    2598:     mumps->ConvertToTriples = MatConvertToTriples_seqsbaij_seqsbaij;
    2599:   } else {
    2600:     mumps->ConvertToTriples = MatConvertToTriples_mpisbaij_mpisbaij;
    2601:   }

    2603:   B->ops->getinfo                = MatGetInfo_External;
    2604:   B->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_MUMPS;
    2605:   B->ops->view                   = MatView_MUMPS;

    2607:   PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_mumps);
    2608:   PetscObjectComposeFunction((PetscObject)B,"MatFactorSetSchurIS_C",MatFactorSetSchurIS_MUMPS);
    2609:   PetscObjectComposeFunction((PetscObject)B,"MatFactorCreateSchurComplement_C",MatFactorCreateSchurComplement_MUMPS);
    2610:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetIcntl_C",MatMumpsSetIcntl_MUMPS);
    2611:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetIcntl_C",MatMumpsGetIcntl_MUMPS);
    2612:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetCntl_C",MatMumpsSetCntl_MUMPS);
    2613:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetCntl_C",MatMumpsGetCntl_MUMPS);
    2614:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfo_C",MatMumpsGetInfo_MUMPS);
    2615:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfog_C",MatMumpsGetInfog_MUMPS);
    2616:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfo_C",MatMumpsGetRinfo_MUMPS);
    2617:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfog_C",MatMumpsGetRinfog_MUMPS);
    2618:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverse_C",MatMumpsGetInverse_MUMPS);
    2619:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverseTranspose_C",MatMumpsGetInverseTranspose_MUMPS);

    2621:   B->factortype = MAT_FACTOR_CHOLESKY;
    2622: #if defined(PETSC_USE_COMPLEX)
    2623:   mumps->sym = 2;
    2624: #else
    2625:   if (A->spd_set && A->spd) mumps->sym = 1;
    2626:   else                      mumps->sym = 2;
    2627: #endif

    2629:   /* set solvertype */
    2630:   PetscFree(B->solvertype);
    2631:   PetscStrallocpy(MATSOLVERMUMPS,&B->solvertype);

    2633:   B->ops->destroy = MatDestroy_MUMPS;
    2634:   B->data         = (void*)mumps;

    2636:   PetscInitializeMUMPS(A,mumps);

    2638:   *F = B;
    2639:   return(0);
    2640: }

    2642: static PetscErrorCode MatGetFactor_baij_mumps(Mat A,MatFactorType ftype,Mat *F)
    2643: {
    2644:   Mat            B;
    2646:   Mat_MUMPS      *mumps;
    2647:   PetscBool      isSeqBAIJ;

    2650:   /* Create the factorization matrix */
    2651:   PetscObjectTypeCompare((PetscObject)A,MATSEQBAIJ,&isSeqBAIJ);
    2652:   MatCreate(PetscObjectComm((PetscObject)A),&B);
    2653:   MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
    2654:   PetscStrallocpy("mumps",&((PetscObject)B)->type_name);
    2655:   MatSetUp(B);

    2657:   PetscNewLog(B,&mumps);
    2658:   if (ftype == MAT_FACTOR_LU) {
    2659:     B->ops->lufactorsymbolic = MatLUFactorSymbolic_BAIJMUMPS;
    2660:     B->factortype            = MAT_FACTOR_LU;
    2661:     if (isSeqBAIJ) mumps->ConvertToTriples = MatConvertToTriples_seqbaij_seqaij;
    2662:     else mumps->ConvertToTriples = MatConvertToTriples_mpibaij_mpiaij;
    2663:     mumps->sym = 0;
    2664:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot use PETSc BAIJ matrices with MUMPS Cholesky, use SBAIJ or AIJ matrix instead\n");

    2666:   B->ops->getinfo     = MatGetInfo_External;
    2667:   B->ops->view        = MatView_MUMPS;

    2669:   PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_mumps);
    2670:   PetscObjectComposeFunction((PetscObject)B,"MatFactorSetSchurIS_C",MatFactorSetSchurIS_MUMPS);
    2671:   PetscObjectComposeFunction((PetscObject)B,"MatFactorCreateSchurComplement_C",MatFactorCreateSchurComplement_MUMPS);
    2672:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetIcntl_C",MatMumpsSetIcntl_MUMPS);
    2673:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetIcntl_C",MatMumpsGetIcntl_MUMPS);
    2674:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetCntl_C",MatMumpsSetCntl_MUMPS);
    2675:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetCntl_C",MatMumpsGetCntl_MUMPS);
    2676:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfo_C",MatMumpsGetInfo_MUMPS);
    2677:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfog_C",MatMumpsGetInfog_MUMPS);
    2678:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfo_C",MatMumpsGetRinfo_MUMPS);
    2679:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfog_C",MatMumpsGetRinfog_MUMPS);
    2680:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverse_C",MatMumpsGetInverse_MUMPS);
    2681:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInverseTranspose_C",MatMumpsGetInverseTranspose_MUMPS);

    2683:   /* set solvertype */
    2684:   PetscFree(B->solvertype);
    2685:   PetscStrallocpy(MATSOLVERMUMPS,&B->solvertype);

    2687:   B->ops->destroy = MatDestroy_MUMPS;
    2688:   B->data         = (void*)mumps;

    2690:   PetscInitializeMUMPS(A,mumps);

    2692:   *F = B;
    2693:   return(0);
    2694: }

    2696: /* MatGetFactor for Seq and MPI SELL matrices */
    2697: static PetscErrorCode MatGetFactor_sell_mumps(Mat A,MatFactorType ftype,Mat *F)
    2698: {
    2699:   Mat            B;
    2701:   Mat_MUMPS      *mumps;
    2702:   PetscBool      isSeqSELL;

    2705:   /* Create the factorization matrix */
    2706:   PetscObjectTypeCompare((PetscObject)A,MATSEQSELL,&isSeqSELL);
    2707:   MatCreate(PetscObjectComm((PetscObject)A),&B);
    2708:   MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
    2709:   PetscStrallocpy("mumps",&((PetscObject)B)->type_name);
    2710:   MatSetUp(B);

    2712:   PetscNewLog(B,&mumps);

    2714:   B->ops->view        = MatView_MUMPS;
    2715:   B->ops->getinfo     = MatGetInfo_MUMPS;

    2717:   PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_mumps);
    2718:   PetscObjectComposeFunction((PetscObject)B,"MatFactorSetSchurIS_C",MatFactorSetSchurIS_MUMPS);
    2719:   PetscObjectComposeFunction((PetscObject)B,"MatFactorCreateSchurComplement_C",MatFactorCreateSchurComplement_MUMPS);
    2720:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetIcntl_C",MatMumpsSetIcntl_MUMPS);
    2721:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetIcntl_C",MatMumpsGetIcntl_MUMPS);
    2722:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsSetCntl_C",MatMumpsSetCntl_MUMPS);
    2723:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetCntl_C",MatMumpsGetCntl_MUMPS);
    2724:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfo_C",MatMumpsGetInfo_MUMPS);
    2725:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetInfog_C",MatMumpsGetInfog_MUMPS);
    2726:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfo_C",MatMumpsGetRinfo_MUMPS);
    2727:   PetscObjectComposeFunction((PetscObject)B,"MatMumpsGetRinfog_C",MatMumpsGetRinfog_MUMPS);

    2729:   if (ftype == MAT_FACTOR_LU) {
    2730:     B->ops->lufactorsymbolic = MatLUFactorSymbolic_AIJMUMPS;
    2731:     B->factortype            = MAT_FACTOR_LU;
    2732:     if (isSeqSELL) mumps->ConvertToTriples = MatConvertToTriples_seqsell_seqaij;
    2733:     else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"To be implemented");
    2734:     mumps->sym = 0;
    2735:   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"To be implemented");

    2737:   /* set solvertype */
    2738:   PetscFree(B->solvertype);
    2739:   PetscStrallocpy(MATSOLVERMUMPS,&B->solvertype);

    2741:   B->ops->destroy = MatDestroy_MUMPS;
    2742:   B->data         = (void*)mumps;

    2744:   PetscInitializeMUMPS(A,mumps);

    2746:   *F = B;
    2747:   return(0);
    2748: }

    2750: PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_MUMPS(void)
    2751: {

    2755:   MatSolverTypeRegister(MATSOLVERMUMPS,MATMPIAIJ,MAT_FACTOR_LU,MatGetFactor_aij_mumps);
    2756:   MatSolverTypeRegister(MATSOLVERMUMPS,MATMPIAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_aij_mumps);
    2757:   MatSolverTypeRegister(MATSOLVERMUMPS,MATMPIBAIJ,MAT_FACTOR_LU,MatGetFactor_baij_mumps);
    2758:   MatSolverTypeRegister(MATSOLVERMUMPS,MATMPIBAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_baij_mumps);
    2759:   MatSolverTypeRegister(MATSOLVERMUMPS,MATMPISBAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_sbaij_mumps);
    2760:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQAIJ,MAT_FACTOR_LU,MatGetFactor_aij_mumps);
    2761:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_aij_mumps);
    2762:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQBAIJ,MAT_FACTOR_LU,MatGetFactor_baij_mumps);
    2763:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQBAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_baij_mumps);
    2764:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQSBAIJ,MAT_FACTOR_CHOLESKY,MatGetFactor_sbaij_mumps);
    2765:   MatSolverTypeRegister(MATSOLVERMUMPS,MATSEQSELL,MAT_FACTOR_LU,MatGetFactor_sell_mumps);
    2766:   return(0);
    2767: }