xref: /petsc/src/mat/impls/aij/mpi/mumps/mumps.c (revision 8ada1bb42b3e5bf111bf39db3f93186d0c8a4722)
1 #define PETSCMAT_DLL
2 
3 /*
4     Provides an interface to the MUMPS_4.3.1 sparse solver
5 */
6 #include "src/mat/impls/aij/seq/aij.h"
7 #include "src/mat/impls/aij/mpi/mpiaij.h"
8 #include "src/mat/impls/sbaij/seq/sbaij.h"
9 #include "src/mat/impls/sbaij/mpi/mpisbaij.h"
10 
11 EXTERN_C_BEGIN
12 #if defined(PETSC_USE_COMPLEX)
13 #include "zmumps_c.h"
14 #else
15 #include "dmumps_c.h"
16 #endif
17 EXTERN_C_END
18 #define JOB_INIT -1
19 #define JOB_END -2
20 /* macros s.t. indices match MUMPS documentation */
21 #define ICNTL(I) icntl[(I)-1]
22 #define CNTL(I) cntl[(I)-1]
23 #define INFOG(I) infog[(I)-1]
24 #define INFO(I) info[(I)-1]
25 #define RINFOG(I) rinfog[(I)-1]
26 #define RINFO(I) rinfo[(I)-1]
27 
28 typedef struct {
29 #if defined(PETSC_USE_COMPLEX)
30   ZMUMPS_STRUC_C id;
31 #else
32   DMUMPS_STRUC_C id;
33 #endif
34   MatStructure   matstruc;
35   int            myid,size,*irn,*jcn,sym;
36   PetscScalar    *val;
37   MPI_Comm       comm_mumps;
38 
39   PetscTruth     isAIJ,CleanUpMUMPS;
40   PetscErrorCode (*MatDuplicate)(Mat,MatDuplicateOption,Mat*);
41   PetscErrorCode (*MatView)(Mat,PetscViewer);
42   PetscErrorCode (*MatAssemblyEnd)(Mat,MatAssemblyType);
43   PetscErrorCode (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*);
44   PetscErrorCode (*MatCholeskyFactorSymbolic)(Mat,IS,MatFactorInfo*,Mat*);
45   PetscErrorCode (*MatDestroy)(Mat);
46   PetscErrorCode (*specialdestroy)(Mat);
47   PetscErrorCode (*MatPreallocate)(Mat,int,int,int*,int,int*);
48 } Mat_MUMPS;
49 
50 EXTERN PetscErrorCode MatDuplicate_MUMPS(Mat,MatDuplicateOption,Mat*);
51 EXTERN_C_BEGIN
52 PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_SBAIJ_SBAIJMUMPS(Mat,MatType,MatReuse,Mat*);
53 EXTERN_C_END
54 /* convert Petsc mpiaij matrix to triples: row[nz], col[nz], val[nz] */
55 /*
56   input:
57     A       - matrix in mpiaij or mpisbaij (bs=1) format
58     shift   - 0: C style output triple; 1: Fortran style output triple.
59     valOnly - FALSE: spaces are allocated and values are set for the triple
60               TRUE:  only the values in v array are updated
61   output:
62     nnz     - dim of r, c, and v (number of local nonzero entries of A)
63     r, c, v - row and col index, matrix values (matrix triples)
64  */
65 PetscErrorCode MatConvertToTriples(Mat A,int shift,PetscTruth valOnly,int *nnz,int **r, int **c, PetscScalar **v) {
66   int         *ai, *aj, *bi, *bj, rstart,nz, *garray;
67   PetscErrorCode ierr;
68   int         i,j,jj,jB,irow,m=A->m,*ajj,*bjj,countA,countB,colA_start,jcol;
69   int         *row,*col;
70   PetscScalar *av, *bv,*val;
71   Mat_MUMPS   *mumps=(Mat_MUMPS*)A->spptr;
72 
73   PetscFunctionBegin;
74   if (mumps->isAIJ){
75     Mat_MPIAIJ    *mat =  (Mat_MPIAIJ*)A->data;
76     Mat_SeqAIJ    *aa=(Mat_SeqAIJ*)(mat->A)->data;
77     Mat_SeqAIJ    *bb=(Mat_SeqAIJ*)(mat->B)->data;
78     nz = aa->nz + bb->nz;
79     ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= mat->rstart;
80     garray = mat->garray;
81     av=aa->a; bv=bb->a;
82 
83   } else {
84     Mat_MPISBAIJ  *mat =  (Mat_MPISBAIJ*)A->data;
85     Mat_SeqSBAIJ  *aa=(Mat_SeqSBAIJ*)(mat->A)->data;
86     Mat_SeqBAIJ    *bb=(Mat_SeqBAIJ*)(mat->B)->data;
87     if (A->bs > 1) SETERRQ1(PETSC_ERR_SUP," bs=%d is not supported yet\n", A->bs);
88     nz = aa->nz + bb->nz;
89     ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= mat->rstart;
90     garray = mat->garray;
91     av=aa->a; bv=bb->a;
92   }
93 
94   if (!valOnly){
95     ierr = PetscMalloc(nz*sizeof(PetscInt) ,&row);CHKERRQ(ierr);
96     ierr = PetscMalloc(nz*sizeof(PetscInt),&col);CHKERRQ(ierr);
97     ierr = PetscMalloc(nz*sizeof(PetscScalar),&val);CHKERRQ(ierr);
98     *r = row; *c = col; *v = val;
99   } else {
100     row = *r; col = *c; val = *v;
101   }
102   *nnz = nz;
103 
104   jj = 0; irow = rstart;
105   for ( i=0; i<m; i++ ) {
106     ajj = aj + ai[i];                 /* ptr to the beginning of this row */
107     countA = ai[i+1] - ai[i];
108     countB = bi[i+1] - bi[i];
109     bjj = bj + bi[i];
110 
111     /* get jB, the starting local col index for the 2nd B-part */
112     colA_start = rstart + ajj[0]; /* the smallest col index for A */
113     j=-1;
114     do {
115       j++;
116       if (j == countB) break;
117       jcol = garray[bjj[j]];
118     } while (jcol < colA_start);
119     jB = j;
120 
121     /* B-part, smaller col index */
122     colA_start = rstart + ajj[0]; /* the smallest col index for A */
123     for (j=0; j<jB; j++){
124       jcol = garray[bjj[j]];
125       if (!valOnly){
126         row[jj] = irow + shift; col[jj] = jcol + shift;
127 
128       }
129       val[jj++] = *bv++;
130     }
131     /* A-part */
132     for (j=0; j<countA; j++){
133       if (!valOnly){
134         row[jj] = irow + shift; col[jj] = rstart + ajj[j] + shift;
135       }
136       val[jj++] = *av++;
137     }
138     /* B-part, larger col index */
139     for (j=jB; j<countB; j++){
140       if (!valOnly){
141         row[jj] = irow + shift; col[jj] = garray[bjj[j]] + shift;
142       }
143       val[jj++] = *bv++;
144     }
145     irow++;
146   }
147 
148   PetscFunctionReturn(0);
149 }
150 
151 EXTERN_C_BEGIN
152 #undef __FUNCT__
153 #define __FUNCT__ "MatConvert_MUMPS_Base"
154 PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_MUMPS_Base(Mat A,MatType type,MatReuse reuse,Mat *newmat) \
155 {
156   PetscErrorCode ierr;
157   Mat            B=*newmat;
158   Mat_MUMPS      *mumps=(Mat_MUMPS*)A->spptr;
159   void           (*f)(void);
160 
161   PetscFunctionBegin;
162   if (reuse == MAT_INITIAL_MATRIX) {
163     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
164   }
165   B->ops->duplicate              = mumps->MatDuplicate;
166   B->ops->view                   = mumps->MatView;
167   B->ops->assemblyend            = mumps->MatAssemblyEnd;
168   B->ops->lufactorsymbolic       = mumps->MatLUFactorSymbolic;
169   B->ops->choleskyfactorsymbolic = mumps->MatCholeskyFactorSymbolic;
170   B->ops->destroy                = mumps->MatDestroy;
171 
172   ierr = PetscObjectQueryFunction((PetscObject)B,"MatMPISBAIJSetPreallocation_C",&f);CHKERRQ(ierr);
173   if (f) {
174     ierr = PetscObjectComposeFunction((PetscObject)B,"MatMPISBAIJSetPreallocation_C","",(FCNVOID)mumps->MatPreallocate);CHKERRQ(ierr);
175   }
176   ierr = PetscFree(mumps);CHKERRQ(ierr);
177 
178   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqaij_aijmumps_C","",PETSC_NULL);CHKERRQ(ierr);
179   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_aijmumps_seqaij_C","",PETSC_NULL);CHKERRQ(ierr);
180   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_mpiaij_aijmumps_C","",PETSC_NULL);CHKERRQ(ierr);
181   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_aijmumps_mpiaij_C","",PETSC_NULL);CHKERRQ(ierr);
182   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqsbaij_sbaijmumps_C","",PETSC_NULL);CHKERRQ(ierr);
183   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_sbaijmumps_seqsbaij_C","",PETSC_NULL);CHKERRQ(ierr);
184   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_mpisbaij_sbaijmumps_C","",PETSC_NULL);CHKERRQ(ierr);
185   ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_sbaijmumps_mpisbaij_C","",PETSC_NULL);CHKERRQ(ierr);
186 
187   ierr = PetscObjectChangeTypeName((PetscObject)B,type);CHKERRQ(ierr);
188   *newmat = B;
189   PetscFunctionReturn(0);
190 }
191 EXTERN_C_END
192 
193 #undef __FUNCT__
194 #define __FUNCT__ "MatDestroy_MUMPS"
195 PetscErrorCode MatDestroy_MUMPS(Mat A)
196 {
197   Mat_MUMPS *lu=(Mat_MUMPS*)A->spptr;
198   PetscErrorCode ierr;
199   int       size=lu->size;
200   PetscErrorCode (*specialdestroy)(Mat);
201   PetscFunctionBegin;
202   if (lu->CleanUpMUMPS) {
203     /* Terminate instance, deallocate memories */
204     lu->id.job=JOB_END;
205 #if defined(PETSC_USE_COMPLEX)
206     zmumps_c(&lu->id);
207 #else
208     dmumps_c(&lu->id);
209 #endif
210     if (lu->irn) {
211       ierr = PetscFree(lu->irn);CHKERRQ(ierr);
212     }
213     if (lu->jcn) {
214       ierr = PetscFree(lu->jcn);CHKERRQ(ierr);
215     }
216     if (size>1 && lu->val) {
217       ierr = PetscFree(lu->val);CHKERRQ(ierr);
218     }
219     ierr = MPI_Comm_free(&(lu->comm_mumps));CHKERRQ(ierr);
220   }
221   specialdestroy = lu->specialdestroy;
222   ierr = (*specialdestroy)(A);CHKERRQ(ierr);
223   ierr = (*A->ops->destroy)(A);CHKERRQ(ierr);
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "MatDestroy_AIJMUMPS"
229 PetscErrorCode MatDestroy_AIJMUMPS(Mat A)
230 {
231   PetscErrorCode ierr;
232   int  size;
233 
234   PetscFunctionBegin;
235   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);
236   if (size==1) {
237     ierr = MatConvert_MUMPS_Base(A,MATSEQAIJ,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
238   } else {
239     ierr = MatConvert_MUMPS_Base(A,MATMPIAIJ,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
240   }
241   PetscFunctionReturn(0);
242 }
243 
244 #undef __FUNCT__
245 #define __FUNCT__ "MatDestroy_SBAIJMUMPS"
246 PetscErrorCode MatDestroy_SBAIJMUMPS(Mat A)
247 {
248   PetscErrorCode ierr;
249   int  size;
250 
251   PetscFunctionBegin;
252   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);
253   if (size==1) {
254     ierr = MatConvert_MUMPS_Base(A,MATSEQSBAIJ,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
255   } else {
256     ierr = MatConvert_MUMPS_Base(A,MATMPISBAIJ,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
257   }
258   PetscFunctionReturn(0);
259 }
260 
261 #undef __FUNCT__
262 #define __FUNCT__ "MatFactorInfo_MUMPS"
263 PetscErrorCode MatFactorInfo_MUMPS(Mat A,PetscViewer viewer) {
264   Mat_MUMPS *lu=(Mat_MUMPS*)A->spptr;
265   PetscErrorCode ierr;
266 
267   PetscFunctionBegin;
268   ierr = PetscViewerASCIIPrintf(viewer,"MUMPS run parameters:\n");CHKERRQ(ierr);
269   ierr = PetscViewerASCIIPrintf(viewer,"  SYM (matrix type):                  %d \n",lu->id.sym);CHKERRQ(ierr);
270   ierr = PetscViewerASCIIPrintf(viewer,"  PAR (host participation):           %d \n",lu->id.par);CHKERRQ(ierr);
271   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(4) (level of printing):       %d \n",lu->id.ICNTL(4));CHKERRQ(ierr);
272   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(5) (input mat struct):        %d \n",lu->id.ICNTL(5));CHKERRQ(ierr);
273   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(6) (matrix prescaling):       %d \n",lu->id.ICNTL(6));CHKERRQ(ierr);
274   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(7) (matrix ordering):         %d \n",lu->id.ICNTL(7));CHKERRQ(ierr);
275   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(9) (A/A^T x=b is solved):     %d \n",lu->id.ICNTL(9));CHKERRQ(ierr);
276   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(10) (max num of refinements): %d \n",lu->id.ICNTL(10));CHKERRQ(ierr);
277   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(11) (error analysis):         %d \n",lu->id.ICNTL(11));CHKERRQ(ierr);
278   if (!lu->myid && lu->id.ICNTL(11)>0) {
279     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(4) (inf norm of input mat):        %g\n",lu->id.RINFOG(4));CHKERRQ(ierr);
280     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(5) (inf norm of solution):         %g\n",lu->id.RINFOG(5));CHKERRQ(ierr);
281     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(6) (inf norm of residual):         %g\n",lu->id.RINFOG(6));CHKERRQ(ierr);
282     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(7),RINFOG(8) (backward error est): %g, %g\n",lu->id.RINFOG(7),lu->id.RINFOG(8));CHKERRQ(ierr);
283     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(9) (error estimate):               %g \n",lu->id.RINFOG(9));CHKERRQ(ierr);
284     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(10),RINFOG(11)(condition numbers): %g, %g\n",lu->id.RINFOG(10),lu->id.RINFOG(11));CHKERRQ(ierr);
285 
286   }
287   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(12) (efficiency control):                         %d \n",lu->id.ICNTL(12));CHKERRQ(ierr);
288   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(13) (efficiency control):                         %d \n",lu->id.ICNTL(13));CHKERRQ(ierr);
289   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(14) (percentage of estimated workspace increase): %d \n",lu->id.ICNTL(14));CHKERRQ(ierr);
290   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(15) (efficiency control):                         %d \n",lu->id.ICNTL(15));CHKERRQ(ierr);
291   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(18) (input mat struct):                           %d \n",lu->id.ICNTL(18));CHKERRQ(ierr);
292 
293   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(1) (relative pivoting threshold):      %g \n",lu->id.CNTL(1));CHKERRQ(ierr);
294   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(2) (stopping criterion of refinement): %g \n",lu->id.CNTL(2));CHKERRQ(ierr);
295   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(3) (absolute pivoting threshold):      %g \n",lu->id.CNTL(3));CHKERRQ(ierr);
296 
297   /* infomation local to each processor */
298   if (!lu->myid) ierr = PetscPrintf(PETSC_COMM_SELF, "      RINFO(1) (local estimated flops for the elimination after analysis): \n");CHKERRQ(ierr);
299   ierr = PetscSynchronizedPrintf(A->comm,"             [%d] %g \n",lu->myid,lu->id.RINFO(1));CHKERRQ(ierr);
300   ierr = PetscSynchronizedFlush(A->comm);
301   if (!lu->myid) ierr = PetscPrintf(PETSC_COMM_SELF, "      RINFO(2) (local estimated flops for the assembly after factorization): \n");CHKERRQ(ierr);
302   ierr = PetscSynchronizedPrintf(A->comm,"             [%d]  %g \n",lu->myid,lu->id.RINFO(2));CHKERRQ(ierr);
303   ierr = PetscSynchronizedFlush(A->comm);
304   if (!lu->myid) ierr = PetscPrintf(PETSC_COMM_SELF, "      RINFO(3) (local estimated flops for the elimination after factorization): \n");CHKERRQ(ierr);
305   ierr = PetscSynchronizedPrintf(A->comm,"             [%d]  %g \n",lu->myid,lu->id.RINFO(3));CHKERRQ(ierr);
306   ierr = PetscSynchronizedFlush(A->comm);
307 
308   if (!lu->myid){ /* information from the host */
309     ierr = PetscViewerASCIIPrintf(viewer,"  RINFOG(1) (global estimated flops for the elimination after analysis): %g \n",lu->id.RINFOG(1));CHKERRQ(ierr);
310     ierr = PetscViewerASCIIPrintf(viewer,"  RINFOG(2) (global estimated flops for the assembly after factorization): %g \n",lu->id.RINFOG(2));CHKERRQ(ierr);
311     ierr = PetscViewerASCIIPrintf(viewer,"  RINFOG(3) (global estimated flops for the elimination after factorization): %g \n",lu->id.RINFOG(3));CHKERRQ(ierr);
312 
313     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(3) (estimated real workspace for factors on all processors after analysis): %d \n",lu->id.INFOG(3));CHKERRQ(ierr);
314     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(4) (estimated integer workspace for factors on all processors after analysis): %d \n",lu->id.INFOG(4));CHKERRQ(ierr);
315     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(5) (estimated maximum front size in the complete tree): %d \n",lu->id.INFOG(5));CHKERRQ(ierr);
316     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(6) (number of nodes in the complete tree): %d \n",lu->id.INFOG(6));CHKERRQ(ierr);
317     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(7) (ordering option effectively uese after analysis): %d \n",lu->id.INFOG(7));CHKERRQ(ierr);
318     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(8) (structural symmetry in percent of the permuted matrix after analysis): %d \n",lu->id.INFOG(8));CHKERRQ(ierr);
319     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(9) (total real space store the matrix factors after analysis): %d \n",lu->id.INFOG(9));CHKERRQ(ierr);
320     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(10) (total integer space store the matrix factors after analysis): %d \n",lu->id.INFOG(10));CHKERRQ(ierr);
321     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(11) (order of largest frontal matrix): %d \n",lu->id.INFOG(11));CHKERRQ(ierr);
322     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(12) (number of off-diagonal pivots): %d \n",lu->id.INFOG(12));CHKERRQ(ierr);
323     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(13) (number of delayed pivots after factorization): %d \n",lu->id.INFOG(13));CHKERRQ(ierr);
324     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(14) (number of memory compress after factorization): %d \n",lu->id.INFOG(14));CHKERRQ(ierr);
325     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(15) (number of steps of iterative refinement after solution): %d \n",lu->id.INFOG(15));CHKERRQ(ierr);
326     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(16) (estimated size (in million of bytes) of all MUMPS internal data for factorization after analysis: value on the most memory consuming processor): %d \n",lu->id.INFOG(16));CHKERRQ(ierr);
327     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(17) (estimated size of all MUMPS internal data for factorization after analysis: sum over all processors): %d \n",lu->id.INFOG(17));CHKERRQ(ierr);
328     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(18) (size of all MUMPS internal data allocated during factorization: value on the most memory consuming processor): %d \n",lu->id.INFOG(18));CHKERRQ(ierr);
329     ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(19) (size of all MUMPS internal data allocated during factorization: sum over all processors): %d \n",lu->id.INFOG(19));CHKERRQ(ierr);
330      ierr = PetscViewerASCIIPrintf(viewer,"  INFOG(20) (estimated number of entries in the factors): %d \n",lu->id.INFOG(20));CHKERRQ(ierr);
331   }
332 
333   PetscFunctionReturn(0);
334 }
335 
336 #undef __FUNCT__
337 #define __FUNCT__ "MatView_AIJMUMPS"
338 PetscErrorCode MatView_AIJMUMPS(Mat A,PetscViewer viewer) {
339   PetscErrorCode ierr;
340   PetscTruth        iascii;
341   PetscViewerFormat format;
342   Mat_MUMPS         *mumps=(Mat_MUMPS*)(A->spptr);
343 
344   PetscFunctionBegin;
345   ierr = (*mumps->MatView)(A,viewer);CHKERRQ(ierr);
346 
347   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
348   if (iascii) {
349     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
350     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
351       ierr = MatFactorInfo_MUMPS(A,viewer);CHKERRQ(ierr);
352     }
353   }
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "MatSolve_AIJMUMPS"
359 PetscErrorCode MatSolve_AIJMUMPS(Mat A,Vec b,Vec x) {
360   Mat_MUMPS   *lu=(Mat_MUMPS*)A->spptr;
361   PetscScalar *array;
362   Vec         x_seq;
363   IS          iden;
364   VecScatter  scat;
365   PetscErrorCode ierr;
366 
367   PetscFunctionBegin;
368   if (lu->size > 1){
369     if (!lu->myid){
370       ierr = VecCreateSeq(PETSC_COMM_SELF,A->N,&x_seq);CHKERRQ(ierr);
371       ierr = ISCreateStride(PETSC_COMM_SELF,A->N,0,1,&iden);CHKERRQ(ierr);
372     } else {
373       ierr = VecCreateSeq(PETSC_COMM_SELF,0,&x_seq);CHKERRQ(ierr);
374       ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&iden);CHKERRQ(ierr);
375     }
376     ierr = VecScatterCreate(b,iden,x_seq,iden,&scat);CHKERRQ(ierr);
377     ierr = ISDestroy(iden);CHKERRQ(ierr);
378 
379     ierr = VecScatterBegin(b,x_seq,INSERT_VALUES,SCATTER_FORWARD,scat);CHKERRQ(ierr);
380     ierr = VecScatterEnd(b,x_seq,INSERT_VALUES,SCATTER_FORWARD,scat);CHKERRQ(ierr);
381     if (!lu->myid) {ierr = VecGetArray(x_seq,&array);CHKERRQ(ierr);}
382   } else {  /* size == 1 */
383     ierr = VecCopy(b,x);CHKERRQ(ierr);
384     ierr = VecGetArray(x,&array);CHKERRQ(ierr);
385   }
386   if (!lu->myid) { /* define rhs on the host */
387 #if defined(PETSC_USE_COMPLEX)
388     lu->id.rhs = (mumps_double_complex*)array;
389 #else
390     lu->id.rhs = array;
391 #endif
392   }
393 
394   /* solve phase */
395   lu->id.job=3;
396 #if defined(PETSC_USE_COMPLEX)
397   zmumps_c(&lu->id);
398 #else
399   dmumps_c(&lu->id);
400 #endif
401   if (lu->id.INFOG(1) < 0) {
402     SETERRQ1(PETSC_ERR_LIB,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",lu->id.INFOG(1));
403   }
404 
405   /* convert mumps solution x_seq to petsc mpi x */
406   if (lu->size > 1) {
407     if (!lu->myid){
408       ierr = VecRestoreArray(x_seq,&array);CHKERRQ(ierr);
409     }
410     ierr = VecScatterBegin(x_seq,x,INSERT_VALUES,SCATTER_REVERSE,scat);CHKERRQ(ierr);
411     ierr = VecScatterEnd(x_seq,x,INSERT_VALUES,SCATTER_REVERSE,scat);CHKERRQ(ierr);
412     ierr = VecScatterDestroy(scat);CHKERRQ(ierr);
413     ierr = VecDestroy(x_seq);CHKERRQ(ierr);
414   } else {
415     ierr = VecRestoreArray(x,&array);CHKERRQ(ierr);
416   }
417 
418   PetscFunctionReturn(0);
419 }
420 
421 /*
422   input:
423    F:        numeric factor
424   output:
425    nneg:     total number of negative pivots
426    nzero:    0
427    npos:     (global dimension of F) - nneg
428 */
429 
430 #undef __FUNCT__
431 #define __FUNCT__ "MatGetInertia_SBAIJMUMPS"
432 PetscErrorCode MatGetInertia_SBAIJMUMPS(Mat F,int *nneg,int *nzero,int *npos)
433 {
434   Mat_MUMPS  *lu =(Mat_MUMPS*)F->spptr;
435   PetscErrorCode ierr;
436   int        size;
437 
438   PetscFunctionBegin;
439   ierr = MPI_Comm_size(F->comm,&size);CHKERRQ(ierr);
440   /* 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 */
441   if (size > 1 && lu->id.ICNTL(13) != 1){
442     SETERRQ1(PETSC_ERR_ARG_WRONG,"ICNTL(13)=%d. -mat_mumps_icntl_13 must be set as 1 for correct global matrix inertia\n",lu->id.INFOG(13));
443   }
444   if (nneg){
445     if (!lu->myid){
446       *nneg = lu->id.INFOG(12);
447     }
448     ierr = MPI_Bcast(nneg,1,MPI_INT,0,lu->comm_mumps);CHKERRQ(ierr);
449   }
450   if (nzero) *nzero = 0;
451   if (npos)  *npos  = F->M - (*nneg);
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "MatFactorNumeric_AIJMUMPS"
457 PetscErrorCode MatFactorNumeric_AIJMUMPS(Mat A,MatFactorInfo *info,Mat *F)
458 {
459   Mat_MUMPS      *lu =(Mat_MUMPS*)(*F)->spptr;
460   Mat_MUMPS      *lua=(Mat_MUMPS*)(A)->spptr;
461   PetscErrorCode ierr;
462   PetscInt       rnz,nnz,nz,i,M=A->M,*ai,*aj,icntl;
463   PetscTruth     valOnly,flg;
464   Mat            F_diag;
465 
466   PetscFunctionBegin;
467   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
468     (*F)->ops->solve    = MatSolve_AIJMUMPS;
469 
470     /* Initialize a MUMPS instance */
471     ierr = MPI_Comm_rank(A->comm, &lu->myid);
472     ierr = MPI_Comm_size(A->comm,&lu->size);CHKERRQ(ierr);
473     lua->myid = lu->myid; lua->size = lu->size;
474     lu->id.job = JOB_INIT;
475     ierr = MPI_Comm_dup(A->comm,&(lu->comm_mumps));CHKERRQ(ierr);
476     lu->id.comm_fortran = lu->comm_mumps;
477 
478     /* Set mumps options */
479     ierr = PetscOptionsBegin(A->comm,A->prefix,"MUMPS Options","Mat");CHKERRQ(ierr);
480     lu->id.par=1;  /* host participates factorizaton and solve */
481     lu->id.sym=lu->sym;
482     if (lu->sym == 2){
483       ierr = PetscOptionsInt("-mat_mumps_sym","SYM: (1,2)","None",lu->id.sym,&icntl,&flg);CHKERRQ(ierr);
484       if (flg && icntl == 1) lu->id.sym=icntl;  /* matrix is spd */
485     }
486 #if defined(PETSC_USE_COMPLEX)
487     zmumps_c(&lu->id);
488 #else
489     dmumps_c(&lu->id);
490 #endif
491 
492     if (lu->size == 1){
493       lu->id.ICNTL(18) = 0;   /* centralized assembled matrix input */
494     } else {
495       lu->id.ICNTL(18) = 3;   /* distributed assembled matrix input */
496     }
497 
498     icntl=-1;
499     ierr = PetscOptionsInt("-mat_mumps_icntl_4","ICNTL(4): level of printing (0 to 4)","None",lu->id.ICNTL(4),&icntl,&flg);CHKERRQ(ierr);
500     if ((flg && icntl > 0) || PetscLogPrintInfo) {
501       lu->id.ICNTL(4)=icntl; /* and use mumps default icntl(i), i=1,2,3 */
502     } else { /* no output */
503       lu->id.ICNTL(1) = 0;  /* error message, default= 6 */
504       lu->id.ICNTL(2) = -1; /* output stream for diagnostic printing, statistics, and warning. default=0 */
505       lu->id.ICNTL(3) = -1; /* output stream for global information, default=6 */
506       lu->id.ICNTL(4) = 0;  /* level of printing, 0,1,2,3,4, default=2 */
507     }
508     ierr = PetscOptionsInt("-mat_mumps_icntl_6","ICNTL(6): matrix prescaling (0 to 7)","None",lu->id.ICNTL(6),&lu->id.ICNTL(6),PETSC_NULL);CHKERRQ(ierr);
509     icntl=-1;
510     ierr = PetscOptionsInt("-mat_mumps_icntl_7","ICNTL(7): matrix ordering (0 to 7)","None",lu->id.ICNTL(7),&icntl,&flg);CHKERRQ(ierr);
511     if (flg) {
512       if (icntl== 1){
513         SETERRQ(PETSC_ERR_SUP,"pivot order be set by the user in PERM_IN -- not supported by the PETSc/MUMPS interface\n");
514       } else {
515         lu->id.ICNTL(7) = icntl;
516       }
517     }
518     ierr = PetscOptionsInt("-mat_mumps_icntl_9","ICNTL(9): A or A^T x=b to be solved. 1: A; otherwise: A^T","None",lu->id.ICNTL(9),&lu->id.ICNTL(9),PETSC_NULL);CHKERRQ(ierr);
519     ierr = PetscOptionsInt("-mat_mumps_icntl_10","ICNTL(10): max num of refinements","None",lu->id.ICNTL(10),&lu->id.ICNTL(10),PETSC_NULL);CHKERRQ(ierr);
520     ierr = PetscOptionsInt("-mat_mumps_icntl_11","ICNTL(11): error analysis, a positive value returns statistics (by -ksp_view)","None",lu->id.ICNTL(11),&lu->id.ICNTL(11),PETSC_NULL);CHKERRQ(ierr);
521     ierr = PetscOptionsInt("-mat_mumps_icntl_12","ICNTL(12): efficiency control","None",lu->id.ICNTL(12),&lu->id.ICNTL(12),PETSC_NULL);CHKERRQ(ierr);
522     ierr = PetscOptionsInt("-mat_mumps_icntl_13","ICNTL(13): efficiency control","None",lu->id.ICNTL(13),&lu->id.ICNTL(13),PETSC_NULL);CHKERRQ(ierr);
523     ierr = PetscOptionsInt("-mat_mumps_icntl_14","ICNTL(14): percentage of estimated workspace increase","None",lu->id.ICNTL(14),&lu->id.ICNTL(14),PETSC_NULL);CHKERRQ(ierr);
524     ierr = PetscOptionsInt("-mat_mumps_icntl_15","ICNTL(15): efficiency control","None",lu->id.ICNTL(15),&lu->id.ICNTL(15),PETSC_NULL);CHKERRQ(ierr);
525 
526     /*
527     ierr = PetscOptionsInt("-mat_mumps_icntl_16","ICNTL(16): 1: rank detection; 2: rank detection and nullspace","None",lu->id.ICNTL(16),&icntl,&flg);CHKERRQ(ierr);
528     if (flg){
529       if (icntl >-1 && icntl <3 ){
530         if (lu->myid==0) lu->id.ICNTL(16) = icntl;
531       } else {
532         SETERRQ1(PETSC_ERR_SUP,"ICNTL(16)=%d -- not supported\n",icntl);
533       }
534     }
535     */
536 
537     ierr = PetscOptionsReal("-mat_mumps_cntl_1","CNTL(1): relative pivoting threshold","None",lu->id.CNTL(1),&lu->id.CNTL(1),PETSC_NULL);CHKERRQ(ierr);
538     ierr = PetscOptionsReal("-mat_mumps_cntl_2","CNTL(2): stopping criterion of refinement","None",lu->id.CNTL(2),&lu->id.CNTL(2),PETSC_NULL);CHKERRQ(ierr);
539     ierr = PetscOptionsReal("-mat_mumps_cntl_3","CNTL(3): absolute pivoting threshold","None",lu->id.CNTL(3),&lu->id.CNTL(3),PETSC_NULL);CHKERRQ(ierr);
540     PetscOptionsEnd();
541   }
542 
543   /* define matrix A */
544   switch (lu->id.ICNTL(18)){
545   case 0:  /* centralized assembled matrix input (size=1) */
546     if (!lu->myid) {
547       if (lua->isAIJ){
548         Mat_SeqAIJ   *aa = (Mat_SeqAIJ*)A->data;
549         nz               = aa->nz;
550         ai = aa->i; aj = aa->j; lu->val = aa->a;
551       } else {
552         Mat_SeqSBAIJ *aa = (Mat_SeqSBAIJ*)A->data;
553         nz                  =  aa->nz;
554         ai = aa->i; aj = aa->j; lu->val = aa->a;
555       }
556       if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){ /* first numeric factorization, get irn and jcn */
557         ierr = PetscMalloc(nz*sizeof(PetscInt),&lu->irn);CHKERRQ(ierr);
558         ierr = PetscMalloc(nz*sizeof(PetscInt),&lu->jcn);CHKERRQ(ierr);
559         nz = 0;
560         for (i=0; i<M; i++){
561           rnz = ai[i+1] - ai[i];
562           while (rnz--) {  /* Fortran row/col index! */
563             lu->irn[nz] = i+1; lu->jcn[nz] = (*aj)+1; aj++; nz++;
564           }
565         }
566       }
567     }
568     break;
569   case 3:  /* distributed assembled matrix input (size>1) */
570     if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
571       valOnly = PETSC_FALSE;
572     } else {
573       valOnly = PETSC_TRUE; /* only update mat values, not row and col index */
574     }
575     ierr = MatConvertToTriples(A,1,valOnly, &nnz, &lu->irn, &lu->jcn, &lu->val);CHKERRQ(ierr);
576     break;
577   default: SETERRQ(PETSC_ERR_SUP,"Matrix input format is not supported by MUMPS.");
578   }
579 
580   /* analysis phase */
581   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
582      lu->id.n = M;
583     switch (lu->id.ICNTL(18)){
584     case 0:  /* centralized assembled matrix input */
585       if (!lu->myid) {
586         lu->id.nz =nz; lu->id.irn=lu->irn; lu->id.jcn=lu->jcn;
587         if (lu->id.ICNTL(6)>1){
588 #if defined(PETSC_USE_COMPLEX)
589           lu->id.a = (mumps_double_complex*)lu->val;
590 #else
591           lu->id.a = lu->val;
592 #endif
593         }
594       }
595       break;
596     case 3:  /* distributed assembled matrix input (size>1) */
597       lu->id.nz_loc = nnz;
598       lu->id.irn_loc=lu->irn; lu->id.jcn_loc=lu->jcn;
599       if (lu->id.ICNTL(6)>1) {
600 #if defined(PETSC_USE_COMPLEX)
601         lu->id.a_loc = (mumps_double_complex*)lu->val;
602 #else
603         lu->id.a_loc = lu->val;
604 #endif
605       }
606       break;
607     }
608     lu->id.job=1;
609 #if defined(PETSC_USE_COMPLEX)
610     zmumps_c(&lu->id);
611 #else
612     dmumps_c(&lu->id);
613 #endif
614     if (lu->id.INFOG(1) < 0) {
615       SETERRQ1(PETSC_ERR_LIB,"Error reported by MUMPS in analysis phase: INFOG(1)=%d\n",lu->id.INFOG(1));
616     }
617   }
618 
619   /* numerical factorization phase */
620   if(!lu->id.ICNTL(18)) {
621     if (!lu->myid) {
622 #if defined(PETSC_USE_COMPLEX)
623       lu->id.a = (mumps_double_complex*)lu->val;
624 #else
625       lu->id.a = lu->val;
626 #endif
627     }
628   } else {
629 #if defined(PETSC_USE_COMPLEX)
630     lu->id.a_loc = (mumps_double_complex*)lu->val;
631 #else
632     lu->id.a_loc = lu->val;
633 #endif
634   }
635   lu->id.job=2;
636 #if defined(PETSC_USE_COMPLEX)
637   zmumps_c(&lu->id);
638 #else
639   dmumps_c(&lu->id);
640 #endif
641   if (lu->id.INFOG(1) < 0) {
642     if (lu->id.INFO(1) == -13) {
643       SETERRQ1(PETSC_ERR_LIB,"Error reported by MUMPS in numerical factorization phase: Cannot allocate required memory %d megabytes\n",lu->id.INFO(2));
644     } else {
645       SETERRQ2(PETSC_ERR_LIB,"Error reported by MUMPS in numerical factorization phase: INFO(1)=%d, INFO(2)=%d\n",lu->id.INFO(1),lu->id.INFO(2));
646     }
647   }
648 
649   if (!lu->myid && lu->id.ICNTL(16) > 0){
650     SETERRQ1(PETSC_ERR_LIB,"  lu->id.ICNTL(16):=%d\n",lu->id.INFOG(16));
651   }
652 
653   if (lu->size > 1){
654     if ((*F)->factor == FACTOR_LU){
655       F_diag = ((Mat_MPIAIJ *)(*F)->data)->A;
656     } else {
657       F_diag = ((Mat_MPISBAIJ *)(*F)->data)->A;
658     }
659     F_diag->assembled = PETSC_TRUE;
660   }
661   (*F)->assembled   = PETSC_TRUE;
662   lu->matstruc      = SAME_NONZERO_PATTERN;
663   lu->CleanUpMUMPS  = PETSC_TRUE;
664   PetscFunctionReturn(0);
665 }
666 
667 /* Note the Petsc r and c permutations are ignored */
668 #undef __FUNCT__
669 #define __FUNCT__ "MatLUFactorSymbolic_AIJMUMPS"
670 PetscErrorCode MatLUFactorSymbolic_AIJMUMPS(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F) {
671   Mat            B;
672   Mat_MUMPS      *lu;
673   PetscErrorCode ierr;
674 
675   PetscFunctionBegin;
676 
677   /* Create the factorization matrix */
678   ierr = MatCreate(A->comm,&B);CHKERRQ(ierr);
679   ierr = MatSetSizes(B,A->m,A->n,A->M,A->N);CHKERRQ(ierr);
680   ierr = MatSetType(B,A->type_name);CHKERRQ(ierr);
681   ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr);
682   ierr = MatMPIAIJSetPreallocation(B,0,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
683 
684   B->ops->lufactornumeric = MatFactorNumeric_AIJMUMPS;
685   B->factor               = FACTOR_LU;
686   lu                      = (Mat_MUMPS*)B->spptr;
687   lu->sym                 = 0;
688   lu->matstruc            = DIFFERENT_NONZERO_PATTERN;
689 
690   *F = B;
691   PetscFunctionReturn(0);
692 }
693 
694 /* Note the Petsc r permutation is ignored */
695 #undef __FUNCT__
696 #define __FUNCT__ "MatCholeskyFactorSymbolic_SBAIJMUMPS"
697 PetscErrorCode MatCholeskyFactorSymbolic_SBAIJMUMPS(Mat A,IS r,MatFactorInfo *info,Mat *F) {
698   Mat            B;
699   Mat_MUMPS      *lu;
700   PetscErrorCode ierr;
701 
702   PetscFunctionBegin;
703   /* Create the factorization matrix */
704   ierr = MatCreate(A->comm,&B);CHKERRQ(ierr);
705   ierr = MatSetSizes(B,A->m,A->n,A->M,A->N);CHKERRQ(ierr);
706   ierr = MatSetType(B,A->type_name);CHKERRQ(ierr);
707   ierr = MatSeqSBAIJSetPreallocation(B,1,0,PETSC_NULL);CHKERRQ(ierr);
708   ierr = MatMPISBAIJSetPreallocation(B,1,0,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
709 
710   B->ops->choleskyfactornumeric = MatFactorNumeric_AIJMUMPS;
711   B->ops->getinertia            = MatGetInertia_SBAIJMUMPS;
712   B->factor                     = FACTOR_CHOLESKY;
713   lu                            = (Mat_MUMPS*)B->spptr;
714   lu->sym                       = 2;
715   lu->matstruc                  = DIFFERENT_NONZERO_PATTERN;
716 
717   *F = B;
718   PetscFunctionReturn(0);
719 }
720 
721 #undef __FUNCT__
722 #define __FUNCT__ "MatAssemblyEnd_AIJMUMPS"
723 PetscErrorCode MatAssemblyEnd_AIJMUMPS(Mat A,MatAssemblyType mode) {
724   PetscErrorCode ierr;
725   Mat_MUMPS *mumps=(Mat_MUMPS*)A->spptr;
726 
727   PetscFunctionBegin;
728   ierr = (*mumps->MatAssemblyEnd)(A,mode);CHKERRQ(ierr);
729 
730   mumps->MatLUFactorSymbolic       = A->ops->lufactorsymbolic;
731   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
732   A->ops->lufactorsymbolic         = MatLUFactorSymbolic_AIJMUMPS;
733   PetscFunctionReturn(0);
734 }
735 
736 EXTERN_C_BEGIN
737 #undef __FUNCT__
738 #define __FUNCT__ "MatConvert_AIJ_AIJMUMPS"
739 PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_AIJ_AIJMUMPS(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
740 {
741   PetscErrorCode ierr;
742   PetscMPIInt    size;
743   MPI_Comm       comm;
744   Mat            B=*newmat;
745   Mat_MUMPS      *mumps;
746 
747   PetscFunctionBegin;
748   if (reuse == MAT_INITIAL_MATRIX) {
749     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
750   }
751 
752   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
753   ierr = PetscNew(Mat_MUMPS,&mumps);CHKERRQ(ierr);
754 
755   mumps->MatDuplicate              = A->ops->duplicate;
756   mumps->MatView                   = A->ops->view;
757   mumps->MatAssemblyEnd            = A->ops->assemblyend;
758   mumps->MatLUFactorSymbolic       = A->ops->lufactorsymbolic;
759   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
760   mumps->MatDestroy                = A->ops->destroy;
761   mumps->specialdestroy            = MatDestroy_AIJMUMPS;
762   mumps->CleanUpMUMPS              = PETSC_FALSE;
763   mumps->isAIJ                     = PETSC_TRUE;
764 
765   B->spptr                         = (void*)mumps;
766   B->ops->duplicate                = MatDuplicate_MUMPS;
767   B->ops->view                     = MatView_AIJMUMPS;
768   B->ops->assemblyend              = MatAssemblyEnd_AIJMUMPS;
769   B->ops->lufactorsymbolic         = MatLUFactorSymbolic_AIJMUMPS;
770   B->ops->destroy                  = MatDestroy_MUMPS;
771 
772   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
773   if (size == 1) {
774     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_aijmumps_C",
775                                              "MatConvert_AIJ_AIJMUMPS",MatConvert_AIJ_AIJMUMPS);CHKERRQ(ierr);
776     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_aijmumps_seqaij_C",
777                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
778   } else {
779     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mpiaij_aijmumps_C",
780                                              "MatConvert_AIJ_AIJMUMPS",MatConvert_AIJ_AIJMUMPS);CHKERRQ(ierr);
781     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_aijmumps_mpiaij_C",
782                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
783   }
784 
785   ierr = PetscLogInfo((0,"MatConvert_AIJ_AIJMUMPS:Using MUMPS for LU factorization and solves.\n"));CHKERRQ(ierr);
786   ierr = PetscObjectChangeTypeName((PetscObject)B,newtype);CHKERRQ(ierr);
787   *newmat = B;
788   PetscFunctionReturn(0);
789 }
790 EXTERN_C_END
791 
792 /*MC
793   MATAIJMUMPS - MATAIJMUMPS = "aijmumps" - A matrix type providing direct solvers (LU) for distributed
794   and sequential matrices via the external package MUMPS.
795 
796   If MUMPS is installed (see the manual for instructions
797   on how to declare the existence of external packages),
798   a matrix type can be constructed which invokes MUMPS solvers.
799   After calling MatCreate(...,A), simply call MatSetType(A,MATAIJMUMPS).
800 
801   If created with a single process communicator, this matrix type inherits from MATSEQAIJ.
802   Otherwise, this matrix type inherits from MATMPIAIJ.  Hence for single process communicators,
803   MatSeqAIJSetPreallocation is supported, and similarly MatMPIAIJSetPreallocation is supported
804   for communicators controlling multiple processes.  It is recommended that you call both of
805   the above preallocation routines for simplicity.  One can also call MatConvert for an inplace
806   conversion to or from the MATSEQAIJ or MATMPIAIJ type (depending on the communicator size)
807   without data copy.
808 
809   Options Database Keys:
810 + -mat_type aijmumps - sets the matrix type to "aijmumps" during a call to MatSetFromOptions()
811 . -mat_mumps_sym <0,1,2> - 0 the matrix is unsymmetric, 1 symmetric positive definite, 2 symmetric
812 . -mat_mumps_icntl_4 <0,1,2,3,4> - print level
813 . -mat_mumps_icntl_6 <0,...,7> - matrix prescaling options (see MUMPS User's Guide)
814 . -mat_mumps_icntl_7 <0,...,7> - matrix orderings (see MUMPS User's Guide)
815 . -mat_mumps_icntl_9 <1,2> - A or A^T x=b to be solved: 1 denotes A, 2 denotes A^T
816 . -mat_mumps_icntl_10 <n> - maximum number of iterative refinements
817 . -mat_mumps_icntl_11 <n> - error analysis, a positive value returns statistics during -ksp_view
818 . -mat_mumps_icntl_12 <n> - efficiency control (see MUMPS User's Guide)
819 . -mat_mumps_icntl_13 <n> - efficiency control (see MUMPS User's Guide)
820 . -mat_mumps_icntl_14 <n> - efficiency control (see MUMPS User's Guide)
821 . -mat_mumps_icntl_15 <n> - efficiency control (see MUMPS User's Guide)
822 . -mat_mumps_cntl_1 <delta> - relative pivoting threshold
823 . -mat_mumps_cntl_2 <tol> - stopping criterion for refinement
824 - -mat_mumps_cntl_3 <adelta> - absolute pivoting threshold
825 
826   Level: beginner
827 
828 .seealso: MATSBAIJMUMPS
829 M*/
830 
831 EXTERN_C_BEGIN
832 #undef __FUNCT__
833 #define __FUNCT__ "MatCreate_AIJMUMPS"
834 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_AIJMUMPS(Mat A)
835 {
836   PetscErrorCode ierr;
837   int      size;
838   Mat      A_diag;
839   MPI_Comm comm;
840 
841   PetscFunctionBegin;
842   /* Change type name before calling MatSetType to force proper construction of SeqAIJ or MPIAIJ */
843   /*   and AIJMUMPS types */
844   ierr = PetscObjectChangeTypeName((PetscObject)A,MATAIJMUMPS);CHKERRQ(ierr);
845   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
846   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
847   if (size == 1) {
848     ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr);
849   } else {
850     ierr   = MatSetType(A,MATMPIAIJ);CHKERRQ(ierr);
851     A_diag = ((Mat_MPIAIJ *)A->data)->A;
852     ierr   = MatConvert_AIJ_AIJMUMPS(A_diag,MATAIJMUMPS,MAT_REUSE_MATRIX,&A_diag);CHKERRQ(ierr);
853   }
854   ierr = MatConvert_AIJ_AIJMUMPS(A,MATAIJMUMPS,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
855   PetscFunctionReturn(0);
856 }
857 EXTERN_C_END
858 
859 #undef __FUNCT__
860 #define __FUNCT__ "MatAssemblyEnd_SBAIJMUMPS"
861 PetscErrorCode MatAssemblyEnd_SBAIJMUMPS(Mat A,MatAssemblyType mode)
862 {
863   PetscErrorCode ierr;
864   Mat_MUMPS *mumps=(Mat_MUMPS*)A->spptr;
865 
866   PetscFunctionBegin;
867   ierr = (*mumps->MatAssemblyEnd)(A,mode);CHKERRQ(ierr);
868   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
869   A->ops->choleskyfactorsymbolic   = MatCholeskyFactorSymbolic_SBAIJMUMPS;
870   PetscFunctionReturn(0);
871 }
872 
873 EXTERN_C_BEGIN
874 #undef __FUNCT__
875 #define __FUNCT__ "MatMPISBAIJSetPreallocation_MPISBAIJMUMPS"
876 PetscErrorCode PETSCMAT_DLLEXPORT MatMPISBAIJSetPreallocation_MPISBAIJMUMPS(Mat  B,int bs,int d_nz,int *d_nnz,int o_nz,int *o_nnz)
877 {
878   Mat       A;
879   Mat_MUMPS *mumps=(Mat_MUMPS*)B->spptr;
880   PetscErrorCode ierr;
881 
882   PetscFunctionBegin;
883   /*
884     After performing the MPISBAIJ Preallocation, we need to convert the local diagonal block matrix
885     into MUMPS type so that the block jacobi preconditioner (for example) can use MUMPS.  I would
886     like this to be done in the MatCreate routine, but the creation of this inner matrix requires
887     block size info so that PETSc can determine the local size properly.  The block size info is set
888     in the preallocation routine.
889   */
890   ierr = (*mumps->MatPreallocate)(B,bs,d_nz,d_nnz,o_nz,o_nnz);
891   A    = ((Mat_MPISBAIJ *)B->data)->A;
892   ierr = MatConvert_SBAIJ_SBAIJMUMPS(A,MATSBAIJMUMPS,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
893   PetscFunctionReturn(0);
894 }
895 EXTERN_C_END
896 
897 EXTERN_C_BEGIN
898 #undef __FUNCT__
899 #define __FUNCT__ "MatConvert_SBAIJ_SBAIJMUMPS"
900 PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_SBAIJ_SBAIJMUMPS(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
901 {
902   PetscErrorCode ierr;
903   PetscMPIInt    size;
904   MPI_Comm       comm;
905   Mat            B=*newmat;
906   Mat_MUMPS      *mumps;
907   void           (*f)(void);
908 
909   PetscFunctionBegin;
910   if (reuse == MAT_INITIAL_MATRIX) {
911     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
912   }
913 
914   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
915   ierr = PetscNew(Mat_MUMPS,&mumps);CHKERRQ(ierr);
916 
917   mumps->MatDuplicate              = A->ops->duplicate;
918   mumps->MatView                   = A->ops->view;
919   mumps->MatAssemblyEnd            = A->ops->assemblyend;
920   mumps->MatLUFactorSymbolic       = A->ops->lufactorsymbolic;
921   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
922   mumps->MatDestroy                = A->ops->destroy;
923   mumps->specialdestroy            = MatDestroy_SBAIJMUMPS;
924   mumps->CleanUpMUMPS              = PETSC_FALSE;
925   mumps->isAIJ                     = PETSC_FALSE;
926 
927   B->spptr                         = (void*)mumps;
928   B->ops->duplicate                = MatDuplicate_MUMPS;
929   B->ops->view                     = MatView_AIJMUMPS;
930   B->ops->assemblyend              = MatAssemblyEnd_SBAIJMUMPS;
931   B->ops->choleskyfactorsymbolic   = MatCholeskyFactorSymbolic_SBAIJMUMPS;
932   B->ops->destroy                  = MatDestroy_MUMPS;
933 
934   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
935   if (size == 1) {
936     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqsbaij_sbaijmumps_C",
937                                              "MatConvert_SBAIJ_SBAIJMUMPS",MatConvert_SBAIJ_SBAIJMUMPS);CHKERRQ(ierr);
938     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_sbaijmumps_seqsbaij_C",
939                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
940   } else {
941   /* I really don't like needing to know the tag: MatMPISBAIJSetPreallocation_C */
942     ierr = PetscObjectQueryFunction((PetscObject)B,"MatMPISBAIJSetPreallocation_C",&f);CHKERRQ(ierr);
943     if (f) { /* This case should always be true when this routine is called */
944       mumps->MatPreallocate = (PetscErrorCode (*)(Mat,int,int,int*,int,int*))f;
945       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatMPISBAIJSetPreallocation_C",
946                                                "MatMPISBAIJSetPreallocation_MPISBAIJMUMPS",
947                                                MatMPISBAIJSetPreallocation_MPISBAIJMUMPS);CHKERRQ(ierr);
948     }
949     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mpisbaij_sbaijmumps_C",
950                                              "MatConvert_SBAIJ_SBAIJMUMPS",MatConvert_SBAIJ_SBAIJMUMPS);CHKERRQ(ierr);
951     ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_sbaijmumps_mpisbaij_C",
952                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
953   }
954 
955   ierr = PetscLogInfo((0,"MatConvert_AIJ_AIJMUMPS:Using MUMPS for Cholesky factorization and solves.\n"));CHKERRQ(ierr);
956   ierr = PetscObjectChangeTypeName((PetscObject)B,newtype);CHKERRQ(ierr);
957   *newmat = B;
958   PetscFunctionReturn(0);
959 }
960 EXTERN_C_END
961 
962 #undef __FUNCT__
963 #define __FUNCT__ "MatDuplicate_MUMPS"
964 PetscErrorCode MatDuplicate_MUMPS(Mat A, MatDuplicateOption op, Mat *M) {
965   PetscErrorCode ierr;
966   Mat_MUMPS   *lu=(Mat_MUMPS *)A->spptr;
967 
968   PetscFunctionBegin;
969   ierr = (*lu->MatDuplicate)(A,op,M);CHKERRQ(ierr);
970   ierr = PetscMemcpy((*M)->spptr,lu,sizeof(Mat_MUMPS));CHKERRQ(ierr);
971   PetscFunctionReturn(0);
972 }
973 
974 /*MC
975   MATSBAIJMUMPS - MATSBAIJMUMPS = "sbaijmumps" - A symmetric matrix type providing direct solvers (Cholesky) for
976   distributed and sequential matrices via the external package MUMPS.
977 
978   If MUMPS is installed (see the manual for instructions
979   on how to declare the existence of external packages),
980   a matrix type can be constructed which invokes MUMPS solvers.
981   After calling MatCreate(...,A), simply call MatSetType(A,MATSBAIJMUMPS).
982 
983   If created with a single process communicator, this matrix type inherits from MATSEQSBAIJ.
984   Otherwise, this matrix type inherits from MATMPISBAIJ.  Hence for single process communicators,
985   MatSeqSBAIJSetPreallocation is supported, and similarly MatMPISBAIJSetPreallocation is supported
986   for communicators controlling multiple processes.  It is recommended that you call both of
987   the above preallocation routines for simplicity.  One can also call MatConvert for an inplace
988   conversion to or from the MATSEQSBAIJ or MATMPISBAIJ type (depending on the communicator size)
989   without data copy.
990 
991   Options Database Keys:
992 + -mat_type sbaijmumps - sets the matrix type to "sbaijmumps" during a call to MatSetFromOptions()
993 . -mat_mumps_sym <0,1,2> - 0 the matrix is unsymmetric, 1 symmetric positive definite, 2 symmetric
994 . -mat_mumps_icntl_4 <0,...,4> - print level
995 . -mat_mumps_icntl_6 <0,...,7> - matrix prescaling options (see MUMPS User's Guide)
996 . -mat_mumps_icntl_7 <0,...,7> - matrix orderings (see MUMPS User's Guide)
997 . -mat_mumps_icntl_9 <1,2> - A or A^T x=b to be solved: 1 denotes A, 2 denotes A^T
998 . -mat_mumps_icntl_10 <n> - maximum number of iterative refinements
999 . -mat_mumps_icntl_11 <n> - error analysis, a positive value returns statistics during -ksp_view
1000 . -mat_mumps_icntl_12 <n> - efficiency control (see MUMPS User's Guide)
1001 . -mat_mumps_icntl_13 <n> - efficiency control (see MUMPS User's Guide)
1002 . -mat_mumps_icntl_14 <n> - efficiency control (see MUMPS User's Guide)
1003 . -mat_mumps_icntl_15 <n> - efficiency control (see MUMPS User's Guide)
1004 . -mat_mumps_cntl_1 <delta> - relative pivoting threshold
1005 . -mat_mumps_cntl_2 <tol> - stopping criterion for refinement
1006 - -mat_mumps_cntl_3 <adelta> - absolute pivoting threshold
1007 
1008   Level: beginner
1009 
1010 .seealso: MATAIJMUMPS
1011 M*/
1012 
1013 EXTERN_C_BEGIN
1014 #undef __FUNCT__
1015 #define __FUNCT__ "MatCreate_SBAIJMUMPS"
1016 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_SBAIJMUMPS(Mat A)
1017 {
1018   PetscErrorCode ierr;
1019   PetscMPIInt    size;
1020 
1021   PetscFunctionBegin;
1022   /* Change type name before calling MatSetType to force proper construction of SeqSBAIJ or MPISBAIJ */
1023   /*   and SBAIJMUMPS types */
1024   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSBAIJMUMPS);CHKERRQ(ierr);
1025   ierr = MPI_Comm_size(A->comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
1026   if (size == 1) {
1027     ierr = MatSetType(A,MATSEQSBAIJ);CHKERRQ(ierr);
1028   } else {
1029     ierr   = MatSetType(A,MATMPISBAIJ);CHKERRQ(ierr);
1030     /*  -- crash! don't know why?
1031     Mat            A_diag;
1032     MPI_Comm       comm;
1033     A_diag = ((Mat_MPISBAIJ *)A->data)->A;
1034     ierr = PetscObjectGetComm((PetscObject)A_diag,&comm);CHKERRQ(ierr);
1035     ierr = MatConvert_SBAIJ_SBAIJMUMPS(A_diag,MATSBAIJMUMPS,MAT_REUSE_MATRIX,&A_diag);CHKERRQ(ierr);
1036 
1037     */
1038   }
1039   ierr = MatConvert_SBAIJ_SBAIJMUMPS(A,MATSBAIJMUMPS,MAT_REUSE_MATRIX,&A);CHKERRQ(ierr);
1040   PetscFunctionReturn(0);
1041 }
1042 EXTERN_C_END
1043