xref: /petsc/src/mat/impls/aij/mpi/mumps/mumps.c (revision 24b6179b2e53a53f9744a57b694a3f39bd426704)
1 /*$Id: mumps.c,v 1.10 2001/08/15 15:56:50 bsmith Exp $*/
2 /*
3     Provides an interface to the MUMPS_4.2_beta sparse solver
4 */
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 RINFOG(I) rinfog[(I)-1]
25 
26 typedef struct {
27 #if defined(PETSC_USE_COMPLEX)
28   ZMUMPS_STRUC_C id;
29 #else
30   DMUMPS_STRUC_C id;
31 #endif
32   MatStructure   matstruc;
33   int            myid,size,*irn,*jcn,sym;
34   PetscScalar    *val;
35   MPI_Comm       comm_mumps;
36 
37   MatType        basetype;
38   PetscTruth     isAIJ,CleanUpMUMPS;
39   int (*MatView)(Mat,PetscViewer);
40   int (*MatAssemblyEnd)(Mat,MatAssemblyType);
41   int (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*);
42   int (*MatCholeskyFactorSymbolic)(Mat,IS,MatFactorInfo*,Mat*);
43   int (*MatDestroy)(Mat);
44 } Mat_AIJ_MUMPS;
45 
46 /* convert Petsc mpiaij matrix to triples: row[nz], col[nz], val[nz] */
47 /*
48   input:
49     A       - matrix in mpiaij format
50     shift   - 0: C style output triple; 1: Fortran style output triple.
51     valOnly - FALSE: spaces are allocated and values are set for the triple
52               TRUE:  only the values in v array are updated
53   output:
54     nnz     - dim of r, c, and v (number of local nonzero entries of A)
55     r, c, v - row and col index, matrix values (matrix triples)
56  */
57 int MatConvertToTriples(Mat A,int shift,PetscTruth valOnly,int *nnz,int **r, int **c, PetscScalar **v)
58 {
59   int              *ai, *aj, *bi, *bj, rstart,nz, *garray;
60   int              ierr,i,j,jj,jB,irow,m=A->m,*ajj,*bjj,countA,countB,colA_start,jcol;
61   int              *row,*col;
62   PetscScalar      *av, *bv,*val;
63   Mat_AIJ_MUMPS *mumps = (Mat_AIJ_MUMPS *)A->spptr;
64 
65   PetscFunctionBegin;
66 
67   if (mumps->isAIJ){
68     Mat_MPIAIJ    *mat =  (Mat_MPIAIJ*)A->data;
69     Mat_SeqAIJ    *aa=(Mat_SeqAIJ*)(mat->A)->data;
70     Mat_SeqAIJ    *bb=(Mat_SeqAIJ*)(mat->B)->data;
71     nz = aa->nz + bb->nz;
72     ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= mat->rstart;
73     garray = mat->garray;
74     av=aa->a; bv=bb->a;
75 
76   } else {
77     Mat_MPISBAIJ  *mat =  (Mat_MPISBAIJ*)A->data;
78     Mat_SeqSBAIJ  *aa=(Mat_SeqSBAIJ*)(mat->A)->data;
79     Mat_SeqBAIJ    *bb=(Mat_SeqBAIJ*)(mat->B)->data;
80     if (mat->bs > 1) SETERRQ1(PETSC_ERR_SUP," bs=%d is not supported yet\n", mat->bs);
81     nz = aa->s_nz + bb->nz;
82     ai=aa->i; aj=aa->j; bi=bb->i; bj=bb->j; rstart= mat->rstart;
83     garray = mat->garray;
84     av=aa->a; bv=bb->a;
85   }
86 
87   if (!valOnly){
88     ierr = PetscMalloc(nz*sizeof(int),&row);CHKERRQ(ierr);
89     ierr = PetscMalloc(nz*sizeof(int),&col);CHKERRQ(ierr);
90     ierr = PetscMalloc(nz*sizeof(PetscScalar),&val);CHKERRQ(ierr);
91     *r = row; *c = col; *v = val;
92   } else {
93     row = *r; col = *c; val = *v;
94   }
95   *nnz = nz;
96 
97   jj = 0; jB = 0; irow = rstart;
98   for ( i=0; i<m; i++ ) {
99     ajj = aj + ai[i];                 /* ptr to the beginning of this row */
100     countA = ai[i+1] - ai[i];
101     countB = bi[i+1] - bi[i];
102     bjj = bj + bi[i];
103 
104     /* get jB, the starting local col index for the 2nd B-part */
105     colA_start = rstart + ajj[0]; /* the smallest col index for A */
106     for (j=0; j<countB; j++){
107       jcol = garray[bjj[j]];
108       if (jcol > colA_start) { jB = j; break; }
109       if (j==countB-1) jB = countB;
110     }
111 
112     /* B-part, smaller col index */
113     colA_start = rstart + ajj[0]; /* the smallest col index for A */
114     for (j=0; j<jB; j++){
115       jcol = garray[bjj[j]];
116       if (!valOnly){
117         row[jj] = irow + shift; col[jj] = jcol + shift;
118       }
119       val[jj++] = *bv++;
120     }
121     /* A-part */
122     for (j=0; j<countA; j++){
123       if (!valOnly){
124         row[jj] = irow + shift; col[jj] = rstart + ajj[j] + shift;
125       }
126       val[jj++] = *av++;
127     }
128     /* B-part, larger col index */
129     for (j=jB; j<countB; j++){
130       if (!valOnly){
131         row[jj] = irow + shift; col[jj] = garray[bjj[j]] + shift;
132       }
133       val[jj++] = *bv++;
134     }
135     irow++;
136   }
137 
138   PetscFunctionReturn(0);
139 }
140 
141 EXTERN_C_BEGIN
142 #undef __FUNCT__
143 #define __FUNCT__ "MatConvert_MUMPS_Base"
144 int MatConvert_MUMPS_Base(Mat A,MatType type,Mat *newmat) {
145   /* This routine is only called to convert an unfactored PETSc-MUMPS matrix */
146   /* to its base PETSc type, so we will ignore 'MatType type'. */
147   int           ierr;
148   Mat           B=*newmat;
149   Mat_AIJ_MUMPS *lu=(Mat_AIJ_MUMPS*)A->spptr;
150 
151   PetscFunctionBegin;
152   if (B != A) {
153     /* This routine was inherited from SeqAIJ. */
154     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
155   } else {
156 
157   B->ops->view                   = lu->MatView;
158   B->ops->assemblyend            = lu->MatAssemblyEnd;
159   B->ops->lufactorsymbolic       = lu->MatLUFactorSymbolic;
160   B->ops->choleskyfactorsymbolic = lu->MatCholeskyFactorSymbolic;
161   B->ops->destroy                = lu->MatDestroy;
162   ierr = PetscObjectChangeTypeName((PetscObject)B,lu->basetype);CHKERRQ(ierr);
163   ierr = PetscFree(lu);CHKERRQ(ierr);
164   }
165   *newmat = B;
166   PetscFunctionReturn(0);
167 }
168 EXTERN_C_END
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "MatDestroy_AIJ_MUMPS"
172 int MatDestroy_AIJ_MUMPS(Mat A)
173 {
174   Mat_AIJ_MUMPS *lu = (Mat_AIJ_MUMPS*)A->spptr;
175   int           ierr,size=lu->size;
176 
177   PetscFunctionBegin;
178   if (lu->CleanUpMUMPS) {
179     /* Terminate instance, deallocate memories */
180     lu->id.job=JOB_END;
181 #if defined(PETSC_USE_COMPLEX)
182     zmumps_c(&lu->id);
183 #else
184     dmumps_c(&lu->id);
185 #endif
186     if (lu->irn) {
187       ierr = PetscFree(lu->irn);CHKERRQ(ierr);
188     }
189     if (lu->jcn) {
190       ierr = PetscFree(lu->jcn);CHKERRQ(ierr);
191     }
192     if (size>1 && lu->val) {
193       ierr = PetscFree(lu->val);CHKERRQ(ierr);
194     }
195     ierr = MPI_Comm_free(&(lu->comm_mumps));CHKERRQ(ierr);
196   }
197   ierr = MatConvert_MUMPS_Base(A,lu->basetype,&A);CHKERRQ(ierr);
198   ierr = (*A->ops->destroy)(A);CHKERRQ(ierr);
199   PetscFunctionReturn(0);
200 }
201 
202 #undef __FUNCT__
203 #define __FUNCT__ "MatFactorInfo_MUMPS"
204 int MatFactorInfo_MUMPS(Mat A,PetscViewer viewer)
205 {
206   Mat_AIJ_MUMPS *lu= (Mat_AIJ_MUMPS*)A->spptr;
207   int              ierr;
208 
209   PetscFunctionBegin;
210   ierr = PetscViewerASCIIPrintf(viewer,"MUMPS run parameters:\n");CHKERRQ(ierr);
211   ierr = PetscViewerASCIIPrintf(viewer,"  SYM (matrix type):                  %d \n",lu->id.sym);CHKERRQ(ierr);
212   ierr = PetscViewerASCIIPrintf(viewer,"  PAR (host participation):           %d \n",lu->id.par);CHKERRQ(ierr);
213   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(4) (level of printing):       %d \n",lu->id.ICNTL(4));CHKERRQ(ierr);
214   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(5) (input mat struct):        %d \n",lu->id.ICNTL(5));CHKERRQ(ierr);
215   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(6) (matrix prescaling):       %d \n",lu->id.ICNTL(6));CHKERRQ(ierr);
216   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(7) (matrix ordering):         %d \n",lu->id.ICNTL(7));CHKERRQ(ierr);
217   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(9) (A/A^T x=b is solved):     %d \n",lu->id.ICNTL(9));CHKERRQ(ierr);
218   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(10) (max num of refinements): %d \n",lu->id.ICNTL(10));CHKERRQ(ierr);
219   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(11) (error analysis):         %d \n",lu->id.ICNTL(11));CHKERRQ(ierr);
220   if (lu->myid == 0 && lu->id.ICNTL(11)>0) {
221     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(4) (inf norm of input mat):        %g\n",lu->id.RINFOG(4));CHKERRQ(ierr);
222     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(5) (inf norm of solution):         %g\n",lu->id.RINFOG(5));CHKERRQ(ierr);
223     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(6) (inf norm of residual):         %g\n",lu->id.RINFOG(6));CHKERRQ(ierr);
224     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);
225     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(9) (error estimate):               %g \n",lu->id.RINFOG(9));CHKERRQ(ierr);
226     ierr = PetscPrintf(PETSC_COMM_SELF,"        RINFOG(10),RINFOG(11)(condition numbers): %g, %g\n",lu->id.RINFOG(10),lu->id.RINFOG(11));CHKERRQ(ierr);
227 
228   }
229   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(12) (efficiency control):     %d \n",lu->id.ICNTL(12));CHKERRQ(ierr);
230   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(13) (efficiency control):     %d \n",lu->id.ICNTL(13));CHKERRQ(ierr);
231   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(14) (efficiency control):     %d \n",lu->id.ICNTL(14));CHKERRQ(ierr);
232   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(15) (efficiency control):     %d \n",lu->id.ICNTL(15));CHKERRQ(ierr);
233   ierr = PetscViewerASCIIPrintf(viewer,"  ICNTL(18) (input mat struct):       %d \n",lu->id.ICNTL(18));CHKERRQ(ierr);
234 
235   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(1) (relative pivoting threshold):      %g \n",lu->id.CNTL(1));CHKERRQ(ierr);
236   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(2) (stopping criterion of refinement): %g \n",lu->id.CNTL(2));CHKERRQ(ierr);
237   ierr = PetscViewerASCIIPrintf(viewer,"  CNTL(3) (absolute pivoting threshold):      %g \n",lu->id.CNTL(3));CHKERRQ(ierr);
238   PetscFunctionReturn(0);
239 }
240 
241 #undef __FUNCT__
242 #define __FUNCT__ "MatView_AIJ_MUMPS"
243 int MatView_AIJ_MUMPS(Mat A,PetscViewer viewer) {
244   int               ierr;
245   PetscTruth        isascii;
246   PetscViewerFormat format;
247   Mat_AIJ_MUMPS     *mumps=(Mat_AIJ_MUMPS*)(A->spptr);
248 
249   PetscFunctionBegin;
250   ierr = (*mumps->MatView)(A,viewer);CHKERRQ(ierr);
251 
252   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
253   if (isascii) {
254     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
255     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
256       ierr = MatFactorInfo_MUMPS(A,viewer);CHKERRQ(ierr);
257     }
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 #undef __FUNCT__
263 #define __FUNCT__ "MatSolve_AIJ_MUMPS"
264 int MatSolve_AIJ_MUMPS(Mat A,Vec b,Vec x)
265 {
266   Mat_AIJ_MUMPS *lu = (Mat_AIJ_MUMPS*)A->spptr;
267   PetscScalar      *array;
268   Vec              x_seq;
269   IS               iden;
270   VecScatter       scat;
271   int              ierr;
272 
273   PetscFunctionBegin;
274   if (lu->size > 1){
275     if (!lu->myid){
276       ierr = VecCreateSeq(PETSC_COMM_SELF,A->N,&x_seq);CHKERRQ(ierr);
277       ierr = ISCreateStride(PETSC_COMM_SELF,A->N,0,1,&iden);CHKERRQ(ierr);
278     } else {
279       ierr = VecCreateSeq(PETSC_COMM_SELF,0,&x_seq);CHKERRQ(ierr);
280       ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&iden);CHKERRQ(ierr);
281     }
282     ierr = VecScatterCreate(b,iden,x_seq,iden,&scat);CHKERRQ(ierr);
283     ierr = ISDestroy(iden);CHKERRQ(ierr);
284 
285     ierr = VecScatterBegin(b,x_seq,INSERT_VALUES,SCATTER_FORWARD,scat);CHKERRQ(ierr);
286     ierr = VecScatterEnd(b,x_seq,INSERT_VALUES,SCATTER_FORWARD,scat);CHKERRQ(ierr);
287     if (!lu->myid) {ierr = VecGetArray(x_seq,&array);CHKERRQ(ierr);}
288   } else {  /* size == 1 */
289     ierr = VecCopy(b,x);CHKERRQ(ierr);
290     ierr = VecGetArray(x,&array);CHKERRQ(ierr);
291   }
292   if (!lu->myid) { /* define rhs on the host */
293 #if defined(PETSC_USE_COMPLEX)
294     lu->id.rhs = (mumps_double_complex*)array;
295 #else
296     lu->id.rhs = array;
297 #endif
298   }
299 
300   /* solve phase */
301   lu->id.job=3;
302 #if defined(PETSC_USE_COMPLEX)
303   zmumps_c(&lu->id);
304 #else
305   dmumps_c(&lu->id);
306 #endif
307   if (lu->id.INFOG(1) < 0) {
308     SETERRQ1(1,"Error reported by MUMPS in solve phase: INFOG(1)=%d\n",lu->id.INFOG(1));
309   }
310 
311   /* convert mumps solution x_seq to petsc mpi x */
312   if (lu->size > 1) {
313     if (!lu->myid){
314       ierr = VecRestoreArray(x_seq,&array);CHKERRQ(ierr);
315     }
316     ierr = VecScatterBegin(x_seq,x,INSERT_VALUES,SCATTER_REVERSE,scat);CHKERRQ(ierr);
317     ierr = VecScatterEnd(x_seq,x,INSERT_VALUES,SCATTER_REVERSE,scat);CHKERRQ(ierr);
318     ierr = VecScatterDestroy(scat);CHKERRQ(ierr);
319     ierr = VecDestroy(x_seq);CHKERRQ(ierr);
320   } else {
321     ierr = VecRestoreArray(x,&array);CHKERRQ(ierr);
322   }
323 
324   PetscFunctionReturn(0);
325 }
326 
327 #undef __FUNCT__
328 #define __FUNCT__ "MatFactorNumeric_MPIAIJ_MUMPS"
329 int MatFactorNumeric_AIJ_MUMPS(Mat A,Mat *F)
330 {
331   Mat_AIJ_MUMPS *lu  = (Mat_AIJ_MUMPS*)(*F)->spptr;
332   Mat_AIJ_MUMPS *lua = (Mat_AIJ_MUMPS*)(A)->spptr;
333   int              rnz,nnz,ierr,nz,i,M=A->M,*ai,*aj,icntl;
334   PetscTruth       valOnly,flg;
335 
336   PetscFunctionBegin;
337   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
338     (*F)->ops->solve    = MatSolve_AIJ_MUMPS;
339 
340     /* Initialize a MUMPS instance */
341     ierr = MPI_Comm_rank(A->comm, &lu->myid);
342     ierr = MPI_Comm_size(A->comm,&lu->size);CHKERRQ(ierr);
343     lu->id.job = JOB_INIT;
344     ierr = MPI_Comm_dup(A->comm,&(lu->comm_mumps));CHKERRQ(ierr);
345     lu->id.comm_fortran = lu->comm_mumps;
346 
347     /* Set mumps options */
348     ierr = PetscOptionsBegin(A->comm,A->prefix,"MUMPS Options","Mat");CHKERRQ(ierr);
349     lu->id.par=1;  /* host participates factorizaton and solve */
350     lu->id.sym=lu->sym;
351     if (lu->sym == 2){
352       ierr = PetscOptionsInt("-mat_mumps_sym","SYM: (1,2)","None",lu->id.sym,&icntl,&flg);CHKERRQ(ierr);
353       if (flg && icntl == 1) lu->id.sym=icntl;  /* matrix is spd */
354     }
355 #if defined(PETSC_USE_COMPLEX)
356   zmumps_c(&lu->id);
357 #else
358   dmumps_c(&lu->id);
359 #endif
360 
361     if (lu->size == 1){
362       lu->id.ICNTL(18) = 0;   /* centralized assembled matrix input */
363     } else {
364       lu->id.ICNTL(18) = 3;   /* distributed assembled matrix input */
365     }
366 
367     icntl=-1;
368     ierr = PetscOptionsInt("-mat_mumps_icntl_4","ICNTL(4): level of printing (0 to 4)","None",lu->id.ICNTL(4),&icntl,&flg);CHKERRQ(ierr);
369     if (flg && icntl > 0) {
370       lu->id.ICNTL(4)=icntl; /* and use mumps default icntl(i), i=1,2,3 */
371     } else { /* no output */
372       lu->id.ICNTL(1) = 0;  /* error message, default= 6 */
373       lu->id.ICNTL(2) = -1; /* output stream for diagnostic printing, statistics, and warning. default=0 */
374       lu->id.ICNTL(3) = -1; /* output stream for global information, default=6 */
375       lu->id.ICNTL(4) = 0;  /* level of printing, 0,1,2,3,4, default=2 */
376     }
377     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);
378     icntl=-1;
379     ierr = PetscOptionsInt("-mat_mumps_icntl_7","ICNTL(7): matrix ordering (0 to 7)","None",lu->id.ICNTL(7),&icntl,&flg);CHKERRQ(ierr);
380     if (flg) {
381       if (icntl== 1){
382         SETERRQ(PETSC_ERR_SUP,"pivot order be set by the user in PERM_IN -- not supported by the PETSc/MUMPS interface\n");
383       } else {
384         lu->id.ICNTL(7) = icntl;
385       }
386     }
387     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);
388     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);
389     ierr = PetscOptionsInt("-mat_mumps_icntl_11","ICNTL(11): error analysis, a positive value returns statistics (by -sles_view)","None",lu->id.ICNTL(11),&lu->id.ICNTL(11),PETSC_NULL);CHKERRQ(ierr);
390     ierr = PetscOptionsInt("-mat_mumps_icntl_12","ICNTL(12): efficiency control","None",lu->id.ICNTL(12),&lu->id.ICNTL(12),PETSC_NULL);CHKERRQ(ierr);
391     ierr = PetscOptionsInt("-mat_mumps_icntl_13","ICNTL(13): efficiency control","None",lu->id.ICNTL(13),&lu->id.ICNTL(13),PETSC_NULL);CHKERRQ(ierr);
392     ierr = PetscOptionsInt("-mat_mumps_icntl_14","ICNTL(14): efficiency control","None",lu->id.ICNTL(14),&lu->id.ICNTL(14),PETSC_NULL);CHKERRQ(ierr);
393     ierr = PetscOptionsInt("-mat_mumps_icntl_15","ICNTL(15): efficiency control","None",lu->id.ICNTL(15),&lu->id.ICNTL(15),PETSC_NULL);CHKERRQ(ierr);
394 
395     /*
396     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);
397     if (flg){
398       if (icntl >-1 && icntl <3 ){
399         if (lu->myid==0) lu->id.ICNTL(16) = icntl;
400       } else {
401         SETERRQ1(PETSC_ERR_SUP,"ICNTL(16)=%d -- not supported\n",icntl);
402       }
403     }
404     */
405 
406     ierr = PetscOptionsReal("-mat_mumps_cntl_1","CNTL(1): relative pivoting threshold","None",lu->id.CNTL(1),&lu->id.CNTL(1),PETSC_NULL);CHKERRQ(ierr);
407     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);
408     ierr = PetscOptionsReal("-mat_mumps_cntl_3","CNTL(3): absolute pivoting threshold","None",lu->id.CNTL(3),&lu->id.CNTL(3),PETSC_NULL);CHKERRQ(ierr);
409     PetscOptionsEnd();
410   }
411 
412   /* define matrix A */
413   switch (lu->id.ICNTL(18)){
414   case 0:  /* centralized assembled matrix input (size=1) */
415     if (!lu->myid) {
416       if (lua->isAIJ){
417         Mat_SeqAIJ   *aa = (Mat_SeqAIJ*)A->data;
418         nz               = aa->nz;
419         ai = aa->i; aj = aa->j; lu->val = aa->a;
420       } else {
421         Mat_SeqSBAIJ *aa = (Mat_SeqSBAIJ*)A->data;
422         nz                  =  aa->s_nz;
423         ai = aa->i; aj = aa->j; lu->val = aa->a;
424       }
425       if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){ /* first numeric factorization, get irn and jcn */
426         ierr = PetscMalloc(nz*sizeof(int),&lu->irn);CHKERRQ(ierr);
427         ierr = PetscMalloc(nz*sizeof(int),&lu->jcn);CHKERRQ(ierr);
428         nz = 0;
429         for (i=0; i<M; i++){
430           rnz = ai[i+1] - ai[i];
431           while (rnz--) {  /* Fortran row/col index! */
432             lu->irn[nz] = i+1; lu->jcn[nz] = (*aj)+1; aj++; nz++;
433           }
434         }
435       }
436     }
437     break;
438   case 3:  /* distributed assembled matrix input (size>1) */
439     if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
440       valOnly = PETSC_FALSE;
441     } else {
442       valOnly = PETSC_TRUE; /* only update mat values, not row and col index */
443     }
444     ierr = MatConvertToTriples(A,1,valOnly, &nnz, &lu->irn, &lu->jcn, &lu->val);CHKERRQ(ierr);
445     break;
446   default: SETERRQ(PETSC_ERR_SUP,"Matrix input format is not supported by MUMPS.");
447   }
448 
449   /* analysis phase */
450   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN){
451      lu->id.n = M;
452     switch (lu->id.ICNTL(18)){
453     case 0:  /* centralized assembled matrix input */
454       if (!lu->myid) {
455         lu->id.nz =nz; lu->id.irn=lu->irn; lu->id.jcn=lu->jcn;
456         if (lu->id.ICNTL(6)>1){
457 #if defined(PETSC_USE_COMPLEX)
458           lu->id.a = (mumps_double_complex*)lu->val;
459 #else
460           lu->id.a = lu->val;
461 #endif
462         }
463       }
464       break;
465     case 3:  /* distributed assembled matrix input (size>1) */
466       lu->id.nz_loc = nnz;
467       lu->id.irn_loc=lu->irn; lu->id.jcn_loc=lu->jcn;
468       if (lu->id.ICNTL(6)>1) {
469 #if defined(PETSC_USE_COMPLEX)
470         lu->id.a_loc = (mumps_double_complex*)lu->val;
471 #else
472         lu->id.a_loc = lu->val;
473 #endif
474       }
475       break;
476     }
477     lu->id.job=1;
478 #if defined(PETSC_USE_COMPLEX)
479   zmumps_c(&lu->id);
480 #else
481   dmumps_c(&lu->id);
482 #endif
483     if (lu->id.INFOG(1) < 0) {
484       SETERRQ1(1,"Error reported by MUMPS in analysis phase: INFOG(1)=%d\n",lu->id.INFOG(1));
485     }
486   }
487 
488   /* numerical factorization phase */
489   if(lu->id.ICNTL(18) == 0) {
490     if (lu->myid == 0) {
491 #if defined(PETSC_USE_COMPLEX)
492       lu->id.a = (mumps_double_complex*)lu->val;
493 #else
494       lu->id.a = lu->val;
495 #endif
496     }
497   } else {
498 #if defined(PETSC_USE_COMPLEX)
499     lu->id.a_loc = (mumps_double_complex*)lu->val;
500 #else
501     lu->id.a_loc = lu->val;
502 #endif
503   }
504   lu->id.job=2;
505 #if defined(PETSC_USE_COMPLEX)
506   zmumps_c(&lu->id);
507 #else
508   dmumps_c(&lu->id);
509 #endif
510   if (lu->id.INFOG(1) < 0) {
511     SETERRQ1(1,"1, Error reported by MUMPS in numerical factorization phase: INFOG(1)=%d\n",lu->id.INFOG(1));
512   }
513 
514   if (lu->myid==0 && lu->id.ICNTL(16) > 0){
515     SETERRQ1(1,"  lu->id.ICNTL(16):=%d\n",lu->id.INFOG(16));
516   }
517 
518   (*F)->assembled = PETSC_TRUE;
519   lu->matstruc    = SAME_NONZERO_PATTERN;
520   PetscFunctionReturn(0);
521 }
522 
523 /* Note the Petsc r and c permutations are ignored */
524 #undef __FUNCT__
525 #define __FUNCT__ "MatLUFactorSymbolic_AIJ_MUMPS"
526 int MatLUFactorSymbolic_AIJ_MUMPS(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F)
527 {
528   Mat              B;
529   Mat_AIJ_MUMPS *lu;
530   int              ierr;
531 
532   PetscFunctionBegin;
533 
534   /* Create the factorization matrix */
535   ierr = MatCreate(A->comm,A->m,A->n,A->M,A->N,&B);CHKERRQ(ierr);
536   ierr = MatSetType(B,MATAIJMUMPS);CHKERRQ(ierr);
537   ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr);
538   ierr = MatMPIAIJSetPreallocation(B,0,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
539 
540   B->ops->lufactornumeric = MatFactorNumeric_AIJ_MUMPS;
541   B->factor               = FACTOR_LU;
542   lu                      = (Mat_AIJ_MUMPS*)B->spptr;
543   lu->sym                 = 0;
544   lu->matstruc            = DIFFERENT_NONZERO_PATTERN;
545 
546   *F = B;
547   PetscFunctionReturn(0);
548 }
549 
550 /* Note the Petsc r permutation is ignored */
551 #undef __FUNCT__
552 #define __FUNCT__ "MatCholeskyFactorSymbolic_AIJ_MUMPS"
553 int MatCholeskyFactorSymbolic_AIJ_MUMPS(Mat A,IS r,MatFactorInfo *info,Mat *F)
554 {
555   Mat              B;
556   Mat_AIJ_MUMPS *lu;
557   int              ierr;
558 
559   PetscFunctionBegin;
560 
561   /* Create the factorization matrix */
562   ierr = MatCreate(A->comm,A->m,A->n,A->M,A->N,&B);CHKERRQ(ierr);
563   ierr = MatSetType(B,MATAIJMUMPS);CHKERRQ(ierr);
564   ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr);
565   ierr = MatMPIAIJSetPreallocation(B,0,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
566 
567   B->ops->choleskyfactornumeric = MatFactorNumeric_AIJ_MUMPS;
568   B->factor                     = FACTOR_CHOLESKY;
569   lu                            = (Mat_AIJ_MUMPS *)B->spptr;
570   lu->sym                       = 2;
571   lu->matstruc                  = DIFFERENT_NONZERO_PATTERN;
572 
573   *F = B;
574   PetscFunctionReturn(0);
575 }
576 
577 #undef __FUNCT__
578 #define __FUNCT__ "MatAssemblyEnd_AIJ_MUMPS"
579 int MatAssemblyEnd_AIJ_MUMPS(Mat A,MatAssemblyType mode) {
580   int           ierr;
581   Mat_AIJ_MUMPS *mumps=(Mat_AIJ_MUMPS*)A->spptr;
582 
583   PetscFunctionBegin;
584   ierr = (*mumps->MatAssemblyEnd)(A,mode);CHKERRQ(ierr);
585   mumps->MatLUFactorSymbolic       = A->ops->lufactorsymbolic;
586   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
587   A->ops->lufactorsymbolic         = MatLUFactorSymbolic_AIJ_MUMPS;
588   A->ops->choleskyfactorsymbolic   = MatCholeskyFactorSymbolic_AIJ_MUMPS;
589   PetscFunctionReturn(0);
590 }
591 
592 EXTERN_C_BEGIN
593 #undef __FUNCT__
594 #define __FUNCT__ "MatConvert_Base_MUMPS"
595 int MatConvert_Base_MUMPS(Mat A,MatType newtype,Mat *newmat) {
596   int           ierr,size;
597   MPI_Comm      comm;
598   Mat           B=*newmat;
599   Mat_AIJ_MUMPS *mumps;
600 
601   PetscFunctionBegin;
602   if (B != A) {
603     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
604   }
605 
606   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
607   ierr = PetscNew(Mat_AIJ_MUMPS,&mumps);CHKERRQ(ierr);
608 
609   mumps->MatView                   = A->ops->view;
610   mumps->MatAssemblyEnd            = A->ops->assemblyend;
611   mumps->MatLUFactorSymbolic       = A->ops->lufactorsymbolic;
612   mumps->MatCholeskyFactorSymbolic = A->ops->choleskyfactorsymbolic;
613   mumps->MatDestroy                = A->ops->destroy;
614   mumps->CleanUpMUMPS              = PETSC_FALSE;
615 
616   B->spptr                         = (void *)mumps;
617   B->ops->view                     = MatView_AIJ_MUMPS;
618   B->ops->assemblyend              = MatAssemblyEnd_AIJ_MUMPS;
619   B->ops->lufactorsymbolic         = MatLUFactorSymbolic_AIJ_MUMPS;
620   B->ops->choleskyfactorsymbolic   = MatCholeskyFactorSymbolic_AIJ_MUMPS;
621   B->ops->destroy                  = MatDestroy_AIJ_MUMPS;
622 
623   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
624   /* This switch is brutal and should probably be changed, but I didn't want 4 routines. */
625   if (newtype == MATAIJMUMPS) {
626     mumps->isAIJ = PETSC_TRUE;
627     if (size == 1) {
628       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_aijmumps_C",
629                                              "MatConvert_Base_MUMPS",MatConvert_Base_MUMPS);CHKERRQ(ierr);
630       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_aijmumps_seqaij_C",
631                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
632     } else {
633       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mpiaij_aijmumps_C",
634                                              "MatConvert_Base_MUMPS",MatConvert_Base_MUMPS);CHKERRQ(ierr);
635       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_aijmumps_mpiaij_C",
636                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
637     }
638   } else {
639     mumps->isAIJ = PETSC_FALSE;
640     if (size == 1) {
641       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqsbaij_mumps_C",
642                                              "MatConvert_Base_MUMPS",MatConvert_Base_MUMPS);CHKERRQ(ierr);
643       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mumps_seqsbaij_C",
644                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
645     } else {
646       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mpisbaij_mumps_C",
647                                              "MatConvert_Base_MUMPS",MatConvert_Base_MUMPS);CHKERRQ(ierr);
648       ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_mumps_mpisbaij_C",
649                                              "MatConvert_MUMPS_Base",MatConvert_MUMPS_Base);CHKERRQ(ierr);
650     }
651   }
652 
653   PetscLogInfo(0,"Using MUMPS for factorization and solves.");
654   ierr = PetscObjectChangeTypeName((PetscObject)B,newtype);CHKERRQ(ierr);
655   *newmat = B;
656   PetscFunctionReturn(0);
657 }
658 EXTERN_C_END
659 
660 /*MC
661   MATAIJMUMPS - a matrix type providing direct solvers (LU, Cholesky) for distributed
662   and sequential matrices via the external package MUMPS.
663 
664   If MUMPS is installed (see the manual for instructions
665   on how to declare the existence of external packages),
666   a matrix type can be constructed which invokes MUMPS solvers.
667   After calling MatCreate(...,A), simply call MatSetType(A,MATAIJMUMPS).
668   This matrix type is only supported for double precision real.
669 
670   If created with a single process communicator, this matrix type inherits from MATSEQAIJ.
671   Otherwise, this matrix type inherits from MATMPIAIJ.  Hence for single process communicators,
672   MatSeqAIJSetPreallocation is supported, and similarly MatMPIAIJSetPreallocation is supported
673   for communicators controlling multiple processes.  It is recommended that you call both of
674   the above preallocation routines for simplicity.
675 
676   Options Database Keys:
677 + -mat_type aijmumps
678 . -mat_mumps_sym <0,1,2> - 0 the matrix is unsymmetric, 1 symmetric positive definite, 2 symmetric
679 . -mat_mumps_icntl_4 <0,1,2,3,4> - print level
680 . -mat_mumps_icntl_6 <0,...,7> - matrix prescaling options (see MUMPS User's Guide)
681 . -mat_mumps_icntl_7 <0,...,7> - matrix orderings (see MUMPS User's Guide)
682 . -mat_mumps_icntl_9 <1,2> - A or A^T x=b to be solved: 1 denotes A, 2 denotes A^T
683 . -mat_mumps_icntl_10 <n> - maximum number of iterative refinements
684 . -mat_mumps_icntl_11 <n> - error analysis, a positive value returns statistics during -sles_view
685 . -mat_mumps_icntl_12 <n> - efficiency control (see MUMPS User's Guide)
686 . -mat_mumps_icntl_13 <n> - efficiency control (see MUMPS User's Guide)
687 . -mat_mumps_icntl_14 <n> - efficiency control (see MUMPS User's Guide)
688 . -mat_mumps_icntl_15 <n> - efficiency control (see MUMPS User's Guide)
689 . -mat_mumps_cntl_1 <delta> - relative pivoting threshold
690 . -mat_mumps_cntl_2 <tol> - stopping criterion for refinement
691 - -mat_mumps_cntl_3 <adelta> - absolute pivoting threshold
692 
693   Level: beginner
694 
695 .seealso: MATSBAIJMUMPS
696 M*/
697 
698 EXTERN_C_BEGIN
699 #undef __FUNCT__
700 #define __FUNCT__ "MatCreate_AIJ_MUMPS"
701 int MatCreate_AIJ_MUMPS(Mat A) {
702   int           ierr,size;
703   MPI_Comm      comm;
704 
705   PetscFunctionBegin;
706   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
707   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
708   if (size == 1) {
709     ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr);
710   } else {
711     ierr = MatSetType(A,MATMPIAIJ);CHKERRQ(ierr);
712   }
713   ierr = MatConvert_Base_MUMPS(A,MATAIJMUMPS,&A);CHKERRQ(ierr);
714   PetscFunctionReturn(0);
715 }
716 EXTERN_C_END
717 
718 /*MC
719   MATSBAIJMUMPS - a symmetric matrix type providing direct solvers (LU, Cholesky) for
720   distributed and sequential matrices via the external package MUMPS.
721 
722   If MUMPS is installed (see the manual for instructions
723   on how to declare the existence of external packages),
724   a matrix type can be constructed which invokes MUMPS solvers.
725   After calling MatCreate(...,A), simply call MatSetType(A,MATSBAIJMUMPS).
726   This matrix type is only supported for double precision real.
727 
728   If created with a single process communicator, this matrix type inherits from MATSEQSBAIJ.
729   Otherwise, this matrix type inherits from MATMPISBAIJ.  Hence for single process communicators,
730   MatSeqSBAIJSetPreallocation is supported, and similarly MatMPISBAIJSetPreallocation is supported
731   for communicators controlling multiple processes.  It is recommended that you call both of
732   the above preallocation routines for simplicity.
733 
734   Options Database Keys:
735 + -mat_type aijmumps
736 . -mat_mumps_sym <0,1,2> - 0 the matrix is unsymmetric, 1 symmetric positive definite, 2 symmetric
737 . -mat_mumps_icntl_4 <0,...,4> - print level
738 . -mat_mumps_icntl_6 <0,...,7> - matrix prescaling options (see MUMPS User's Guide)
739 . -mat_mumps_icntl_7 <0,...,7> - matrix orderings (see MUMPS User's Guide)
740 . -mat_mumps_icntl_9 <1,2> - A or A^T x=b to be solved: 1 denotes A, 2 denotes A^T
741 . -mat_mumps_icntl_10 <n> - maximum number of iterative refinements
742 . -mat_mumps_icntl_11 <n> - error analysis, a positive value returns statistics during -sles_view
743 . -mat_mumps_icntl_12 <n> - efficiency control (see MUMPS User's Guide)
744 . -mat_mumps_icntl_13 <n> - efficiency control (see MUMPS User's Guide)
745 . -mat_mumps_icntl_14 <n> - efficiency control (see MUMPS User's Guide)
746 . -mat_mumps_icntl_15 <n> - efficiency control (see MUMPS User's Guide)
747 . -mat_mumps_cntl_1 <delta> - relative pivoting threshold
748 . -mat_mumps_cntl_2 <tol> - stopping criterion for refinement
749 - -mat_mumps_cntl_3 <adelta> - absolute pivoting threshold
750 
751   Level: beginner
752 
753 .seealso: MATAIJMUMPS
754 M*/
755 
756 EXTERN_C_BEGIN
757 #undef __FUNCT__
758 #define __FUNCT__ "MatCreate_SBAIJ_MUMPS"
759 int MatCreate_SBAIJ_MUMPS(Mat A) {
760   int           ierr,size;
761   MPI_Comm      comm;
762 
763   PetscFunctionBegin;
764   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
765   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);CHKERRQ(ierr);
766   if (size == 1) {
767     ierr = MatSetType(A,MATSEQSBAIJ);CHKERRQ(ierr);
768   } else {
769     ierr = MatSetType(A,MATMPISBAIJ);CHKERRQ(ierr);
770   }
771   ierr = MatConvert_Base_MUMPS(A,MATSBAIJMUMPS,&A);CHKERRQ(ierr);
772   PetscFunctionReturn(0);
773 }
774 EXTERN_C_END
775 
776 EXTERN_C_BEGIN
777 #undef __FUNCT__
778 #define __FUNCT__ "MatLoad_AIJ_MUMPS"
779 int MatLoad_AIJ_MUMPS(PetscViewer viewer,MatType type,Mat *A) {
780   int ierr,size,(*r)(PetscViewer,MatType,Mat*);
781   MPI_Comm comm;
782 
783   PetscFunctionBegin;
784   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
785   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
786   if (size == 1) {
787     ierr = PetscFListFind(comm,MatLoadList,MATSEQAIJ,(void(**)(void))&r);CHKERRQ(ierr);
788   } else {
789     ierr = PetscFListFind(comm,MatLoadList,MATMPIAIJ,(void(**)(void))&r);CHKERRQ(ierr);
790   }
791   ierr = (*r)(viewer,type,A);CHKERRQ(ierr);
792   PetscFunctionReturn(0);
793 }
794 EXTERN_C_END
795 
796 EXTERN_C_BEGIN
797 #undef __FUNCT__
798 #define __FUNCT__ "MatLoad_SBAIJ_MUMPS"
799 int MatLoad_SBAIJ_MUMPS(PetscViewer viewer,MatType type,Mat *A) {
800   int ierr,size,(*r)(PetscViewer,MatType,Mat*);
801   MPI_Comm comm;
802 
803   PetscFunctionBegin;
804   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
805   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
806   if (size == 1) {
807     ierr = PetscFListFind(comm,MatLoadList,MATSEQSBAIJ,(void(**)(void))&r);CHKERRQ(ierr);
808   } else {
809     ierr = PetscFListFind(comm,MatLoadList,MATMPISBAIJ,(void(**)(void))&r);CHKERRQ(ierr);
810   }
811   ierr = (*r)(viewer,type,A);CHKERRQ(ierr);
812   PetscFunctionReturn(0);
813 }
814 EXTERN_C_END
815