xref: /petsc/src/mat/impls/aij/mpi/pastix/pastix.c (revision 37eeb8152ec6a2cf24186d3591c2c5de5dfd8fa5)
1 /*
2  Provides an interface to the PaStiX sparse solver
3  */
4 #include <../src/mat/impls/aij/seq/aij.h>
5 #include <../src/mat/impls/aij/mpi/mpiaij.h>
6 #include <../src/mat/impls/sbaij/seq/sbaij.h>
7 #include <../src/mat/impls/sbaij/mpi/mpisbaij.h>
8 
9 #if defined(PETSC_USE_COMPLEX)
10 #define _H_COMPLEX
11 #endif
12 
13 EXTERN_C_BEGIN
14 #include <pastix.h>
15 EXTERN_C_END
16 
17 #if defined(PETSC_USE_COMPLEX)
18 #if defined(PETSC_USE_REAL_SINGLE)
19 #define PASTIX_CALL c_pastix
20 #else
21 #define PASTIX_CALL z_pastix
22 #endif
23 
24 #else /* PETSC_USE_COMPLEX */
25 
26 #if defined(PETSC_USE_REAL_SINGLE)
27 #define PASTIX_CALL s_pastix
28 #else
29 #define PASTIX_CALL d_pastix
30 #endif
31 
32 #endif /* PETSC_USE_COMPLEX */
33 
34 typedef PetscScalar PastixScalar;
35 
36 typedef struct Mat_Pastix_ {
37   pastix_data_t *pastix_data;    /* Pastix data storage structure                        */
38   MatStructure  matstruc;
39   PetscInt      n;               /* Number of columns in the matrix                      */
40   PetscInt      *colptr;         /* Index of first element of each column in row and val */
41   PetscInt      *row;            /* Row of each element of the matrix                    */
42   PetscScalar   *val;            /* Value of each element of the matrix                  */
43   PetscInt      *perm;           /* Permutation tabular                                  */
44   PetscInt      *invp;           /* Reverse permutation tabular                          */
45   PetscScalar   *rhs;            /* Rhight-hand-side member                              */
46   PetscInt      rhsnbr;          /* Rhight-hand-side number (must be 1)                  */
47   PetscInt      iparm[IPARM_SIZE];       /* Integer parameters                                   */
48   double        dparm[DPARM_SIZE];       /* Floating point parameters                            */
49   MPI_Comm      pastix_comm;     /* PaStiX MPI communicator                              */
50   PetscMPIInt   commRank;        /* MPI rank                                             */
51   PetscMPIInt   commSize;        /* MPI communicator size                                */
52   PetscBool     CleanUpPastix;   /* Boolean indicating if we call PaStiX clean step      */
53   VecScatter    scat_rhs;
54   VecScatter    scat_sol;
55   Vec           b_seq;
56 } Mat_Pastix;
57 
58 extern PetscErrorCode MatDuplicate_Pastix(Mat,MatDuplicateOption,Mat*);
59 
60 /*
61    convert Petsc seqaij matrix to CSC: colptr[n], row[nz], val[nz]
62 
63   input:
64     A       - matrix in seqaij or mpisbaij (bs=1) format
65     valOnly - FALSE: spaces are allocated and values are set for the CSC
66               TRUE:  Only fill values
67   output:
68     n       - Size of the matrix
69     colptr  - Index of first element of each column in row and val
70     row     - Row of each element of the matrix
71     values  - Value of each element of the matrix
72  */
73 PetscErrorCode MatConvertToCSC(Mat A,PetscBool valOnly,PetscInt *n,PetscInt **colptr,PetscInt **row,PetscScalar **values)
74 {
75   Mat_SeqAIJ     *aa      = (Mat_SeqAIJ*)A->data;
76   PetscInt       *rowptr  = aa->i;
77   PetscInt       *col     = aa->j;
78   PetscScalar    *rvalues = aa->a;
79   PetscInt       m        = A->rmap->N;
80   PetscInt       nnz;
81   PetscInt       i,j, k;
82   PetscInt       base = 1;
83   PetscInt       idx;
84   PetscErrorCode ierr;
85   PetscInt       colidx;
86   PetscInt       *colcount;
87   PetscBool      isSBAIJ;
88   PetscBool      isSeqSBAIJ;
89   PetscBool      isMpiSBAIJ;
90   PetscBool      isSym;
91 
92   PetscFunctionBegin;
93   ierr = MatIsSymmetric(A,0.0,&isSym);CHKERRQ(ierr);
94   ierr = PetscObjectTypeCompare((PetscObject)A,MATSBAIJ,&isSBAIJ);CHKERRQ(ierr);
95   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQSBAIJ,&isSeqSBAIJ);CHKERRQ(ierr);
96   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPISBAIJ,&isMpiSBAIJ);CHKERRQ(ierr);
97 
98   *n = A->cmap->N;
99 
100   /* PaStiX only needs triangular matrix if matrix is symmetric
101    */
102   if (isSym && !(isSBAIJ || isSeqSBAIJ || isMpiSBAIJ)) nnz = (aa->nz - *n)/2 + *n;
103   else nnz = aa->nz;
104 
105   if (!valOnly) {
106     ierr = PetscMalloc1((*n)+1,colptr);CHKERRQ(ierr);
107     ierr = PetscMalloc1(nnz,row);CHKERRQ(ierr);
108     ierr = PetscMalloc1(nnz,values);CHKERRQ(ierr);
109 
110     if (isSBAIJ || isSeqSBAIJ || isMpiSBAIJ) {
111       ierr = PetscArraycpy (*colptr, rowptr, (*n)+1);CHKERRQ(ierr);
112       for (i = 0; i < *n+1; i++) (*colptr)[i] += base;
113       ierr = PetscArraycpy (*row, col, nnz);CHKERRQ(ierr);
114       for (i = 0; i < nnz; i++) (*row)[i] += base;
115       ierr = PetscArraycpy (*values, rvalues, nnz);CHKERRQ(ierr);
116     } else {
117       ierr = PetscMalloc1(*n,&colcount);CHKERRQ(ierr);
118 
119       for (i = 0; i < m; i++) colcount[i] = 0;
120       /* Fill-in colptr */
121       for (i = 0; i < m; i++) {
122         for (j = rowptr[i]; j < rowptr[i+1]; j++) {
123           if (!isSym || col[j] <= i)  colcount[col[j]]++;
124         }
125       }
126 
127       (*colptr)[0] = base;
128       for (j = 0; j < *n; j++) {
129         (*colptr)[j+1] = (*colptr)[j] + colcount[j];
130         /* in next loop we fill starting from (*colptr)[colidx] - base */
131         colcount[j] = -base;
132       }
133 
134       /* Fill-in rows and values */
135       for (i = 0; i < m; i++) {
136         for (j = rowptr[i]; j < rowptr[i+1]; j++) {
137           if (!isSym || col[j] <= i) {
138             colidx         = col[j];
139             idx            = (*colptr)[colidx] + colcount[colidx];
140             (*row)[idx]    = i + base;
141             (*values)[idx] = rvalues[j];
142             colcount[colidx]++;
143           }
144         }
145       }
146       ierr = PetscFree(colcount);CHKERRQ(ierr);
147     }
148   } else {
149     /* Fill-in only values */
150     for (i = 0; i < m; i++) {
151       for (j = rowptr[i]; j < rowptr[i+1]; j++) {
152         colidx = col[j];
153         if ((isSBAIJ || isSeqSBAIJ || isMpiSBAIJ) ||!isSym || col[j] <= i) {
154           /* look for the value to fill */
155           for (k = (*colptr)[colidx] - base; k < (*colptr)[colidx + 1] - base; k++) {
156             if (((*row)[k]-base) == i) {
157               (*values)[k] = rvalues[j];
158               break;
159             }
160           }
161           /* data structure of sparse matrix has changed */
162           if (k == (*colptr)[colidx + 1] - base) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"overflow on k %D",k);
163         }
164       }
165     }
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 /*
171   Call clean step of PaStiX if lu->CleanUpPastix == true.
172   Free the CSC matrix.
173  */
174 PetscErrorCode MatDestroy_Pastix(Mat A)
175 {
176   Mat_Pastix     *lu=(Mat_Pastix*)A->data;
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   if (lu->CleanUpPastix) {
181     /* Terminate instance, deallocate memories */
182     ierr = VecScatterDestroy(&lu->scat_rhs);CHKERRQ(ierr);
183     ierr = VecDestroy(&lu->b_seq);CHKERRQ(ierr);
184     ierr = VecScatterDestroy(&lu->scat_sol);CHKERRQ(ierr);
185 
186     lu->iparm[IPARM_START_TASK]=API_TASK_CLEAN;
187     lu->iparm[IPARM_END_TASK]  =API_TASK_CLEAN;
188 
189     PASTIX_CALL(&(lu->pastix_data),
190                 lu->pastix_comm,
191                 lu->n,
192                 lu->colptr,
193                 lu->row,
194                 (PastixScalar*)lu->val,
195                 lu->perm,
196                 lu->invp,
197                 (PastixScalar*)lu->rhs,
198                 lu->rhsnbr,
199                 lu->iparm,
200                 lu->dparm);
201     if (lu->iparm[IPARM_ERROR_NUMBER] != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by PaStiX in destroy: iparm(IPARM_ERROR_NUMBER)=%d\n",lu->iparm[IPARM_ERROR_NUMBER]);
202     ierr = PetscFree(lu->colptr);CHKERRQ(ierr);
203     ierr = PetscFree(lu->row);CHKERRQ(ierr);
204     ierr = PetscFree(lu->val);CHKERRQ(ierr);
205     ierr = PetscFree(lu->perm);CHKERRQ(ierr);
206     ierr = PetscFree(lu->invp);CHKERRQ(ierr);
207     ierr = MPI_Comm_free(&(lu->pastix_comm));CHKERRQ(ierr);
208   }
209   ierr = PetscFree(A->data);CHKERRQ(ierr);
210   PetscFunctionReturn(0);
211 }
212 
213 /*
214   Gather right-hand-side.
215   Call for Solve step.
216   Scatter solution.
217  */
218 PetscErrorCode MatSolve_PaStiX(Mat A,Vec b,Vec x)
219 {
220   Mat_Pastix     *lu=(Mat_Pastix*)A->data;
221   PetscScalar    *array;
222   Vec            x_seq;
223   PetscErrorCode ierr;
224 
225   PetscFunctionBegin;
226   lu->rhsnbr = 1;
227   x_seq      = lu->b_seq;
228   if (lu->commSize > 1) {
229     /* PaStiX only supports centralized rhs. Scatter b into a seqential rhs vector */
230     ierr = VecScatterBegin(lu->scat_rhs,b,x_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
231     ierr = VecScatterEnd(lu->scat_rhs,b,x_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
232     ierr = VecGetArray(x_seq,&array);CHKERRQ(ierr);
233   } else {  /* size == 1 */
234     ierr = VecCopy(b,x);CHKERRQ(ierr);
235     ierr = VecGetArray(x,&array);CHKERRQ(ierr);
236   }
237   lu->rhs = array;
238   if (lu->commSize == 1) {
239     ierr = VecRestoreArray(x,&array);CHKERRQ(ierr);
240   } else {
241     ierr = VecRestoreArray(x_seq,&array);CHKERRQ(ierr);
242   }
243 
244   /* solve phase */
245   /*-------------*/
246   lu->iparm[IPARM_START_TASK] = API_TASK_SOLVE;
247   lu->iparm[IPARM_END_TASK]   = API_TASK_REFINE;
248   lu->iparm[IPARM_RHS_MAKING] = API_RHS_B;
249 
250   PASTIX_CALL(&(lu->pastix_data),
251               lu->pastix_comm,
252               lu->n,
253               lu->colptr,
254               lu->row,
255               (PastixScalar*)lu->val,
256               lu->perm,
257               lu->invp,
258               (PastixScalar*)lu->rhs,
259               lu->rhsnbr,
260               lu->iparm,
261               lu->dparm);
262   if (lu->iparm[IPARM_ERROR_NUMBER] != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by PaStiX in solve phase: lu->iparm[IPARM_ERROR_NUMBER] = %d\n",lu->iparm[IPARM_ERROR_NUMBER]);
263 
264   if (lu->commSize == 1) {
265     ierr = VecRestoreArray(x,&(lu->rhs));CHKERRQ(ierr);
266   } else {
267     ierr = VecRestoreArray(x_seq,&(lu->rhs));CHKERRQ(ierr);
268   }
269 
270   if (lu->commSize > 1) { /* convert PaStiX centralized solution to petsc mpi x */
271     ierr = VecScatterBegin(lu->scat_sol,x_seq,x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
272     ierr = VecScatterEnd(lu->scat_sol,x_seq,x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
273   }
274   PetscFunctionReturn(0);
275 }
276 
277 /*
278   Numeric factorisation using PaStiX solver.
279 
280  */
281 PetscErrorCode MatFactorNumeric_PaStiX(Mat F,Mat A,const MatFactorInfo *info)
282 {
283   Mat_Pastix     *lu =(Mat_Pastix*)(F)->data;
284   Mat            *tseq;
285   PetscErrorCode ierr = 0;
286   PetscInt       icntl;
287   PetscInt       M=A->rmap->N;
288   PetscBool      valOnly,flg, isSym;
289   IS             is_iden;
290   Vec            b;
291   IS             isrow;
292   PetscBool      isSeqAIJ,isSeqSBAIJ,isMPIAIJ;
293 
294   PetscFunctionBegin;
295   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isSeqAIJ);CHKERRQ(ierr);
296   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&isMPIAIJ);CHKERRQ(ierr);
297   ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQSBAIJ,&isSeqSBAIJ);CHKERRQ(ierr);
298   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN) {
299     (F)->ops->solve = MatSolve_PaStiX;
300 
301     /* Initialize a PASTIX instance */
302     ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)A),&(lu->pastix_comm));CHKERRQ(ierr);
303     ierr = MPI_Comm_rank(lu->pastix_comm, &lu->commRank);CHKERRQ(ierr);
304     ierr = MPI_Comm_size(lu->pastix_comm, &lu->commSize);CHKERRQ(ierr);
305 
306     /* Set pastix options */
307     lu->iparm[IPARM_MODIFY_PARAMETER] = API_NO;
308     lu->iparm[IPARM_START_TASK]       = API_TASK_INIT;
309     lu->iparm[IPARM_END_TASK]         = API_TASK_INIT;
310 
311     lu->rhsnbr = 1;
312 
313     /* Call to set default pastix options */
314     PASTIX_CALL(&(lu->pastix_data),
315                 lu->pastix_comm,
316                 lu->n,
317                 lu->colptr,
318                 lu->row,
319                 (PastixScalar*)lu->val,
320                 lu->perm,
321                 lu->invp,
322                 (PastixScalar*)lu->rhs,
323                 lu->rhsnbr,
324                 lu->iparm,
325                 lu->dparm);
326     if (lu->iparm[IPARM_ERROR_NUMBER] != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by PaStiX in MatFactorNumeric: iparm(IPARM_ERROR_NUMBER)=%d\n",lu->iparm[IPARM_ERROR_NUMBER]);
327 
328     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"PaStiX Options","Mat");CHKERRQ(ierr);
329     icntl = -1;
330     lu->iparm[IPARM_VERBOSE] = API_VERBOSE_NOT;
331     ierr = PetscOptionsInt("-mat_pastix_verbose","iparm[IPARM_VERBOSE] : level of printing (0 to 2)","None",lu->iparm[IPARM_VERBOSE],&icntl,&flg);CHKERRQ(ierr);
332     if ((flg && icntl >= 0) || PetscLogPrintInfo) {
333       lu->iparm[IPARM_VERBOSE] =  icntl;
334     }
335     icntl=-1;
336     ierr = PetscOptionsInt("-mat_pastix_threadnbr","iparm[IPARM_THREAD_NBR] : Number of thread by MPI node","None",lu->iparm[IPARM_THREAD_NBR],&icntl,&flg);CHKERRQ(ierr);
337     if ((flg && icntl > 0)) {
338       lu->iparm[IPARM_THREAD_NBR] = icntl;
339     }
340     PetscOptionsEnd();
341     valOnly = PETSC_FALSE;
342   } else {
343     if (isSeqAIJ || isMPIAIJ) {
344       ierr    = PetscFree(lu->colptr);CHKERRQ(ierr);
345       ierr    = PetscFree(lu->row);CHKERRQ(ierr);
346       ierr    = PetscFree(lu->val);CHKERRQ(ierr);
347       valOnly = PETSC_FALSE;
348     } else valOnly = PETSC_TRUE;
349   }
350 
351   lu->iparm[IPARM_MATRIX_VERIFICATION] = API_YES;
352 
353   /* convert mpi A to seq mat A */
354   ierr = ISCreateStride(PETSC_COMM_SELF,M,0,1,&isrow);CHKERRQ(ierr);
355   ierr = MatCreateSubMatrices(A,1,&isrow,&isrow,MAT_INITIAL_MATRIX,&tseq);CHKERRQ(ierr);
356   ierr = ISDestroy(&isrow);CHKERRQ(ierr);
357 
358   ierr = MatConvertToCSC(*tseq,valOnly, &lu->n, &lu->colptr, &lu->row, &lu->val);CHKERRQ(ierr);
359   ierr = MatIsSymmetric(*tseq,0.0,&isSym);CHKERRQ(ierr);
360   ierr = MatDestroyMatrices(1,&tseq);CHKERRQ(ierr);
361 
362   if (!lu->perm) {
363     ierr = PetscMalloc1(lu->n,&(lu->perm));CHKERRQ(ierr);
364     ierr = PetscMalloc1(lu->n,&(lu->invp));CHKERRQ(ierr);
365   }
366 
367   if (isSym) {
368     /* On symmetric matrix, LLT */
369     lu->iparm[IPARM_SYM]           = API_SYM_YES;
370     lu->iparm[IPARM_FACTORIZATION] = API_FACT_LDLT;
371   } else {
372     /* On unsymmetric matrix, LU */
373     lu->iparm[IPARM_SYM]           = API_SYM_NO;
374     lu->iparm[IPARM_FACTORIZATION] = API_FACT_LU;
375   }
376 
377   /*----------------*/
378   if (lu->matstruc == DIFFERENT_NONZERO_PATTERN) {
379     if (!(isSeqAIJ || isSeqSBAIJ) && !lu->b_seq) {
380       /* PaStiX only supports centralized rhs. Create scatter scat_rhs for repeated use in MatSolve() */
381       ierr = VecCreateSeq(PETSC_COMM_SELF,A->cmap->N,&lu->b_seq);CHKERRQ(ierr);
382       ierr = ISCreateStride(PETSC_COMM_SELF,A->cmap->N,0,1,&is_iden);CHKERRQ(ierr);
383       ierr = MatCreateVecs(A,NULL,&b);CHKERRQ(ierr);
384       ierr = VecScatterCreate(b,is_iden,lu->b_seq,is_iden,&lu->scat_rhs);CHKERRQ(ierr);
385       ierr = VecScatterCreate(lu->b_seq,is_iden,b,is_iden,&lu->scat_sol);CHKERRQ(ierr);
386       ierr = ISDestroy(&is_iden);CHKERRQ(ierr);
387       ierr = VecDestroy(&b);CHKERRQ(ierr);
388     }
389     lu->iparm[IPARM_START_TASK] = API_TASK_ORDERING;
390     lu->iparm[IPARM_END_TASK]   = API_TASK_NUMFACT;
391 
392     PASTIX_CALL(&(lu->pastix_data),
393                 lu->pastix_comm,
394                 lu->n,
395                 lu->colptr,
396                 lu->row,
397                 (PastixScalar*)lu->val,
398                 lu->perm,
399                 lu->invp,
400                 (PastixScalar*)lu->rhs,
401                 lu->rhsnbr,
402                 lu->iparm,
403                 lu->dparm);
404     if (lu->iparm[IPARM_ERROR_NUMBER] != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by PaStiX in analysis phase: iparm(IPARM_ERROR_NUMBER)=%d\n",lu->iparm[IPARM_ERROR_NUMBER]);
405   } else {
406     lu->iparm[IPARM_START_TASK] = API_TASK_NUMFACT;
407     lu->iparm[IPARM_END_TASK]   = API_TASK_NUMFACT;
408     PASTIX_CALL(&(lu->pastix_data),
409                 lu->pastix_comm,
410                 lu->n,
411                 lu->colptr,
412                 lu->row,
413                 (PastixScalar*)lu->val,
414                 lu->perm,
415                 lu->invp,
416                 (PastixScalar*)lu->rhs,
417                 lu->rhsnbr,
418                 lu->iparm,
419                 lu->dparm);
420     if (lu->iparm[IPARM_ERROR_NUMBER] != 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error reported by PaStiX in analysis phase: iparm(IPARM_ERROR_NUMBER)=%d\n",lu->iparm[IPARM_ERROR_NUMBER]);
421   }
422 
423   (F)->assembled    = PETSC_TRUE;
424   lu->matstruc      = SAME_NONZERO_PATTERN;
425   lu->CleanUpPastix = PETSC_TRUE;
426   PetscFunctionReturn(0);
427 }
428 
429 /* Note the Petsc r and c permutations are ignored */
430 PetscErrorCode MatLUFactorSymbolic_AIJPASTIX(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info)
431 {
432   Mat_Pastix *lu = (Mat_Pastix*)F->data;
433 
434   PetscFunctionBegin;
435   lu->iparm[IPARM_FACTORIZATION] = API_FACT_LU;
436   lu->iparm[IPARM_SYM]           = API_SYM_YES;
437   lu->matstruc                   = DIFFERENT_NONZERO_PATTERN;
438   F->ops->lufactornumeric        = MatFactorNumeric_PaStiX;
439   PetscFunctionReturn(0);
440 }
441 
442 
443 /* Note the Petsc r permutation is ignored */
444 PetscErrorCode MatCholeskyFactorSymbolic_SBAIJPASTIX(Mat F,Mat A,IS r,const MatFactorInfo *info)
445 {
446   Mat_Pastix *lu = (Mat_Pastix*)(F)->data;
447 
448   PetscFunctionBegin;
449   lu->iparm[IPARM_FACTORIZATION]  = API_FACT_LLT;
450   lu->iparm[IPARM_SYM]            = API_SYM_NO;
451   lu->matstruc                    = DIFFERENT_NONZERO_PATTERN;
452   (F)->ops->choleskyfactornumeric = MatFactorNumeric_PaStiX;
453   PetscFunctionReturn(0);
454 }
455 
456 PetscErrorCode MatView_PaStiX(Mat A,PetscViewer viewer)
457 {
458   PetscErrorCode    ierr;
459   PetscBool         iascii;
460   PetscViewerFormat format;
461 
462   PetscFunctionBegin;
463   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
464   if (iascii) {
465     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
466     if (format == PETSC_VIEWER_ASCII_INFO) {
467       Mat_Pastix *lu=(Mat_Pastix*)A->data;
468 
469       ierr = PetscViewerASCIIPrintf(viewer,"PaStiX run parameters:\n");CHKERRQ(ierr);
470       ierr = PetscViewerASCIIPrintf(viewer,"  Matrix type :                      %s \n",((lu->iparm[IPARM_SYM] == API_SYM_YES) ? "Symmetric" : "Unsymmetric"));CHKERRQ(ierr);
471       ierr = PetscViewerASCIIPrintf(viewer,"  Level of printing (0,1,2):         %d \n",lu->iparm[IPARM_VERBOSE]);CHKERRQ(ierr);
472       ierr = PetscViewerASCIIPrintf(viewer,"  Number of refinements iterations : %d \n",lu->iparm[IPARM_NBITER]);CHKERRQ(ierr);
473       ierr = PetscPrintf(PETSC_COMM_SELF,"  Error :                        %g \n",lu->dparm[DPARM_RELATIVE_ERROR]);CHKERRQ(ierr);
474     }
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 
480 /*MC
481      MATSOLVERPASTIX  - A solver package providing direct solvers (LU) for distributed
482   and sequential matrices via the external package PaStiX.
483 
484   Use ./configure --download-pastix --download-ptscotch  to have PETSc installed with PasTiX
485 
486   Use -pc_type lu -pc_factor_mat_solver_type pastix to use this direct solver
487 
488   Options Database Keys:
489 + -mat_pastix_verbose   <0,1,2>   - print level
490 - -mat_pastix_threadnbr <integer> - Set the thread number by MPI task.
491 
492   Notes:
493     This only works for matrices with symmetric nonzero structure, if you pass it a matrix with
494    nonsymmetric structure PasTiX and hence PETSc return with an error.
495 
496   Level: beginner
497 
498 .seealso: PCFactorSetMatSolverType(), MatSolverType
499 
500 M*/
501 
502 
503 PetscErrorCode MatGetInfo_PaStiX(Mat A,MatInfoType flag,MatInfo *info)
504 {
505   Mat_Pastix *lu =(Mat_Pastix*)A->data;
506 
507   PetscFunctionBegin;
508   info->block_size        = 1.0;
509   info->nz_allocated      = lu->iparm[IPARM_NNZEROS];
510   info->nz_used           = lu->iparm[IPARM_NNZEROS];
511   info->nz_unneeded       = 0.0;
512   info->assemblies        = 0.0;
513   info->mallocs           = 0.0;
514   info->memory            = 0.0;
515   info->fill_ratio_given  = 0;
516   info->fill_ratio_needed = 0;
517   info->factor_mallocs    = 0;
518   PetscFunctionReturn(0);
519 }
520 
521 static PetscErrorCode MatFactorGetSolverType_pastix(Mat A,MatSolverType *type)
522 {
523   PetscFunctionBegin;
524   *type = MATSOLVERPASTIX;
525   PetscFunctionReturn(0);
526 }
527 
528 /*
529     The seq and mpi versions of this function are the same
530 */
531 static PetscErrorCode MatGetFactor_seqaij_pastix(Mat A,MatFactorType ftype,Mat *F)
532 {
533   Mat            B;
534   PetscErrorCode ierr;
535   Mat_Pastix     *pastix;
536 
537   PetscFunctionBegin;
538   if (ftype != MAT_FACTOR_LU) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot use PETSc AIJ matrices with PaStiX Cholesky, use SBAIJ matrix");
539   /* Create the factorization matrix */
540   ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
541   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
542   ierr = PetscStrallocpy("pastix",&((PetscObject)B)->type_name);CHKERRQ(ierr);
543   ierr = MatSetUp(B);CHKERRQ(ierr);
544 
545   B->ops->lufactorsymbolic = MatLUFactorSymbolic_AIJPASTIX;
546   B->ops->view             = MatView_PaStiX;
547   B->ops->getinfo          = MatGetInfo_PaStiX;
548 
549   ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_pastix);CHKERRQ(ierr);
550 
551   B->factortype = MAT_FACTOR_LU;
552 
553   /* set solvertype */
554   ierr = PetscFree(B->solvertype);CHKERRQ(ierr);
555   ierr = PetscStrallocpy(MATSOLVERPASTIX,&B->solvertype);CHKERRQ(ierr);
556 
557   ierr = PetscNewLog(B,&pastix);CHKERRQ(ierr);
558 
559   pastix->CleanUpPastix = PETSC_FALSE;
560   pastix->scat_rhs      = NULL;
561   pastix->scat_sol      = NULL;
562   B->ops->getinfo       = MatGetInfo_External;
563   B->ops->destroy       = MatDestroy_Pastix;
564   B->data               = (void*)pastix;
565 
566   *F = B;
567   PetscFunctionReturn(0);
568 }
569 
570 static PetscErrorCode MatGetFactor_mpiaij_pastix(Mat A,MatFactorType ftype,Mat *F)
571 {
572   Mat            B;
573   PetscErrorCode ierr;
574   Mat_Pastix     *pastix;
575 
576   PetscFunctionBegin;
577   if (ftype != MAT_FACTOR_LU) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot use PETSc AIJ matrices with PaStiX Cholesky, use SBAIJ matrix");
578   /* Create the factorization matrix */
579   ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
580   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
581   ierr = PetscStrallocpy("pastix",&((PetscObject)B)->type_name);CHKERRQ(ierr);
582   ierr = MatSetUp(B);CHKERRQ(ierr);
583 
584   B->ops->lufactorsymbolic = MatLUFactorSymbolic_AIJPASTIX;
585   B->ops->view             = MatView_PaStiX;
586   B->ops->getinfo          = MatGetInfo_PaStiX;
587   ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_pastix);CHKERRQ(ierr);
588 
589   B->factortype = MAT_FACTOR_LU;
590 
591   /* set solvertype */
592   ierr = PetscFree(B->solvertype);CHKERRQ(ierr);
593   ierr = PetscStrallocpy(MATSOLVERPASTIX,&B->solvertype);CHKERRQ(ierr);
594 
595   ierr = PetscNewLog(B,&pastix);CHKERRQ(ierr);
596 
597   pastix->CleanUpPastix = PETSC_FALSE;
598   pastix->scat_rhs      = NULL;
599   pastix->scat_sol      = NULL;
600   B->ops->getinfo       = MatGetInfo_External;
601   B->ops->destroy       = MatDestroy_Pastix;
602   B->data               = (void*)pastix;
603 
604   *F = B;
605   PetscFunctionReturn(0);
606 }
607 
608 static PetscErrorCode MatGetFactor_seqsbaij_pastix(Mat A,MatFactorType ftype,Mat *F)
609 {
610   Mat            B;
611   PetscErrorCode ierr;
612   Mat_Pastix     *pastix;
613 
614   PetscFunctionBegin;
615   if (ftype != MAT_FACTOR_CHOLESKY) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot use PETSc SBAIJ matrices with PaStiX LU, use AIJ matrix");
616   /* Create the factorization matrix */
617   ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
618   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
619   ierr = PetscStrallocpy("pastix",&((PetscObject)B)->type_name);CHKERRQ(ierr);
620   ierr = MatSetUp(B);CHKERRQ(ierr);
621 
622   B->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_SBAIJPASTIX;
623   B->ops->view                   = MatView_PaStiX;
624   B->ops->getinfo                = MatGetInfo_PaStiX;
625   ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_pastix);CHKERRQ(ierr);
626 
627   B->factortype = MAT_FACTOR_CHOLESKY;
628 
629   /* set solvertype */
630   ierr = PetscFree(B->solvertype);CHKERRQ(ierr);
631   ierr = PetscStrallocpy(MATSOLVERPASTIX,&B->solvertype);CHKERRQ(ierr);
632 
633   ierr = PetscNewLog(B,&pastix);CHKERRQ(ierr);
634 
635   pastix->CleanUpPastix = PETSC_FALSE;
636   pastix->scat_rhs      = NULL;
637   pastix->scat_sol      = NULL;
638   B->ops->getinfo       = MatGetInfo_External;
639   B->ops->destroy       = MatDestroy_Pastix;
640   B->data               = (void*)pastix;
641 
642   *F = B;
643   PetscFunctionReturn(0);
644 }
645 
646 static PetscErrorCode MatGetFactor_mpisbaij_pastix(Mat A,MatFactorType ftype,Mat *F)
647 {
648   Mat            B;
649   PetscErrorCode ierr;
650   Mat_Pastix     *pastix;
651 
652   PetscFunctionBegin;
653   if (ftype != MAT_FACTOR_CHOLESKY) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot use PETSc SBAIJ matrices with PaStiX LU, use AIJ matrix");
654 
655   /* Create the factorization matrix */
656   ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr);
657   ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
658   ierr = PetscStrallocpy("pastix",&((PetscObject)B)->type_name);CHKERRQ(ierr);
659   ierr = MatSetUp(B);CHKERRQ(ierr);
660 
661   B->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_SBAIJPASTIX;
662   B->ops->view                   = MatView_PaStiX;
663   B->ops->getinfo                = MatGetInfo_PaStiX;
664   B->ops->destroy                = MatDestroy_Pastix;
665   ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_pastix);CHKERRQ(ierr);
666 
667   B->factortype = MAT_FACTOR_CHOLESKY;
668 
669   /* set solvertype */
670   ierr = PetscFree(B->solvertype);CHKERRQ(ierr);
671   ierr = PetscStrallocpy(MATSOLVERPASTIX,&B->solvertype);CHKERRQ(ierr);
672 
673   ierr = PetscNewLog(B,&pastix);CHKERRQ(ierr);
674 
675   pastix->CleanUpPastix = PETSC_FALSE;
676   pastix->scat_rhs      = NULL;
677   pastix->scat_sol      = NULL;
678   B->data               = (void*)pastix;
679 
680   *F = B;
681   PetscFunctionReturn(0);
682 }
683 
684 PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Pastix(void)
685 {
686   PetscErrorCode ierr;
687 
688   PetscFunctionBegin;
689   ierr = MatSolverTypeRegister(MATSOLVERPASTIX,MATMPIAIJ,        MAT_FACTOR_LU,MatGetFactor_mpiaij_pastix);CHKERRQ(ierr);
690   ierr = MatSolverTypeRegister(MATSOLVERPASTIX,MATSEQAIJ,        MAT_FACTOR_LU,MatGetFactor_seqaij_pastix);CHKERRQ(ierr);
691   ierr = MatSolverTypeRegister(MATSOLVERPASTIX,MATMPISBAIJ,      MAT_FACTOR_CHOLESKY,MatGetFactor_mpisbaij_pastix);CHKERRQ(ierr);
692   ierr = MatSolverTypeRegister(MATSOLVERPASTIX,MATSEQSBAIJ,      MAT_FACTOR_CHOLESKY,MatGetFactor_seqsbaij_pastix);CHKERRQ(ierr);
693   PetscFunctionReturn(0);
694 }
695