xref: /petsc/src/mat/impls/is/matis.c (revision 3cfa4ea460eed5c3d3ab4210924c568cabc7705a)
1 
2 /*
3     Creates a matrix class for using the Neumann-Neumann type preconditioners.
4    This stores the matrices in globally unassembled form. Each processor
5    assembles only its local Neumann problem and the parallel matrix vector
6    product is handled "implicitly".
7 
8      We provide:
9          MatMult()
10 
11     Currently this allows for only one subdomain per processor.
12 
13 */
14 
15 #include <../src/mat/impls/is/matis.h>      /*I "petscmat.h" I*/
16 
17 static PetscErrorCode MatISComputeSF_Private(Mat);
18 
19 #undef __FUNCT__
20 #define __FUNCT__ "MatISComputeSF_Private"
21 static PetscErrorCode MatISComputeSF_Private(Mat B)
22 {
23   Mat_IS         *matis = (Mat_IS*)(B->data);
24   const PetscInt *gidxs;
25   PetscErrorCode ierr;
26 
27   PetscFunctionBegin;
28   ierr = MatGetSize(matis->A,&matis->sf_nleaves,NULL);CHKERRQ(ierr);
29   ierr = MatGetLocalSize(B,&matis->sf_nroots,NULL);CHKERRQ(ierr);
30   ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);CHKERRQ(ierr);
31   ierr = ISLocalToGlobalMappingGetIndices(matis->mapping,&gidxs);CHKERRQ(ierr);
32   /* PETSC_OWN_POINTER refers to ilocal which is NULL */
33   ierr = PetscSFSetGraphLayout(matis->sf,B->rmap,matis->sf_nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr);
34   ierr = ISLocalToGlobalMappingRestoreIndices(matis->mapping,&gidxs);CHKERRQ(ierr);
35   ierr = PetscMalloc2(matis->sf_nroots,&matis->sf_rootdata,matis->sf_nleaves,&matis->sf_leafdata);CHKERRQ(ierr);
36   PetscFunctionReturn(0);
37 }
38 
39 #undef __FUNCT__
40 #define __FUNCT__ "MatISSetPreallocation"
41 /*
42    MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.
43 
44    Collective on MPI_Comm
45 
46    Input Parameters:
47 +  B - the matrix
48 .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
49            (same value is used for all local rows)
50 .  d_nnz - array containing the number of nonzeros in the various rows of the
51            DIAGONAL portion of the local submatrix (possibly different for each row)
52            or NULL, if d_nz is used to specify the nonzero structure.
53            The size of this array is equal to the number of local rows, i.e 'm'.
54            For matrices that will be factored, you must leave room for (and set)
55            the diagonal entry even if it is zero.
56 .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
57            submatrix (same value is used for all local rows).
58 -  o_nnz - array containing the number of nonzeros in the various rows of the
59            OFF-DIAGONAL portion of the local submatrix (possibly different for
60            each row) or NULL, if o_nz is used to specify the nonzero
61            structure. The size of this array is equal to the number
62            of local rows, i.e 'm'.
63 
64    If the *_nnz parameter is given then the *_nz parameter is ignored
65 
66    Level: intermediate
67 
68    Notes: This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
69           from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
70           matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
71 
72 .keywords: matrix
73 
74 .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat()
75 @*/
76 PetscErrorCode  MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
77 {
78   PetscErrorCode ierr;
79 
80   PetscFunctionBegin;
81   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
82   PetscValidType(B,1);
83   ierr = PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));CHKERRQ(ierr);
84   PetscFunctionReturn(0);
85 }
86 
87 #undef __FUNCT__
88 #define __FUNCT__ "MatISSetPreallocation_IS"
89 PetscErrorCode  MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
90 {
91   Mat_IS         *matis = (Mat_IS*)(B->data);
92   PetscInt       bs,i,nlocalcols;
93   PetscErrorCode ierr;
94 
95   PetscFunctionBegin;
96   if (!matis->A) {
97     SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping");
98   }
99   if (!matis->sf) { /* setup SF if not yet created and allocate rootdata and leafdata */
100     ierr = MatISComputeSF_Private(B);CHKERRQ(ierr);
101   }
102   if (!d_nnz) {
103     for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] = d_nz;
104   } else {
105     for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] = d_nnz[i];
106   }
107   if (!o_nnz) {
108     for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] += o_nz;
109   } else {
110     for (i=0;i<matis->sf_nroots;i++) matis->sf_rootdata[i] += o_nnz[i];
111   }
112   ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
113   ierr = MatGetSize(matis->A,NULL,&nlocalcols);CHKERRQ(ierr);
114   ierr = MatGetBlockSize(matis->A,&bs);CHKERRQ(ierr);
115   ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
116   for (i=0;i<matis->sf_nleaves;i++) {
117     matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols);
118   }
119   ierr = MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);CHKERRQ(ierr);
120   for (i=0;i<matis->sf_nleaves/bs;i++) {
121     matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs;
122   }
123   ierr = MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
124   for (i=0;i<matis->sf_nleaves/bs;i++) {
125     matis->sf_leafdata[i] = matis->sf_leafdata[i]-i;
126   }
127   ierr = MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "MatISSetMPIXAIJPreallocation_Private"
133 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
134 {
135   Mat_IS          *matis = (Mat_IS*)(A->data);
136   PetscInt        *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership;
137   const PetscInt* global_indices;
138   PetscInt        i,j,bs,rows,cols;
139   PetscInt        lrows,lcols;
140   PetscInt        local_rows,local_cols;
141   PetscMPIInt     nsubdomains;
142   PetscBool       isdense,issbaij;
143   PetscErrorCode  ierr;
144 
145   PetscFunctionBegin;
146   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&nsubdomains);CHKERRQ(ierr);
147   ierr = MatGetSize(A,&rows,&cols);CHKERRQ(ierr);
148   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
149   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
150   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr);
151   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
152   ierr = ISLocalToGlobalMappingGetIndices(matis->mapping,&global_indices);CHKERRQ(ierr);
153   if (issbaij) {
154     ierr = MatGetRowUpperTriangular(matis->A);CHKERRQ(ierr);
155   }
156   /*
157      An SF reduce is needed to sum up properly on shared interface dofs.
158      Note that generally preallocation is not exact, since it overestimates nonzeros
159   */
160   if (!matis->sf) { /* setup SF if not yet created and allocate rootdata and leafdata */
161     ierr = MatISComputeSF_Private(A);CHKERRQ(ierr);
162   }
163   ierr = MatGetLocalSize(A,&lrows,&lcols);CHKERRQ(ierr);
164   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);CHKERRQ(ierr);
165   /* All processes need to compute entire row ownership */
166   ierr = PetscMalloc1(rows,&row_ownership);CHKERRQ(ierr);
167   ierr = MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr);
168   for (i=0;i<nsubdomains;i++) {
169     for (j=mat_ranges[i];j<mat_ranges[i+1];j++) {
170       row_ownership[j]=i;
171     }
172   }
173 
174   /*
175      my_dnz and my_onz contains exact contribution to preallocation from each local mat
176      then, they will be summed up properly. This way, preallocation is always sufficient
177   */
178   ierr = PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);CHKERRQ(ierr);
179   /* preallocation as a MATAIJ */
180   if (isdense) { /* special case for dense local matrices */
181     for (i=0;i<local_rows;i++) {
182       PetscInt index_row = global_indices[i];
183       for (j=i;j<local_rows;j++) {
184         PetscInt owner = row_ownership[index_row];
185         PetscInt index_col = global_indices[j];
186         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
187           my_dnz[i] += 1;
188         } else { /* offdiag block */
189           my_onz[i] += 1;
190         }
191         /* same as before, interchanging rows and cols */
192         if (i != j) {
193           owner = row_ownership[index_col];
194           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
195             my_dnz[j] += 1;
196           } else {
197             my_onz[j] += 1;
198           }
199         }
200       }
201     }
202   } else {
203     for (i=0;i<local_rows;i++) {
204       const PetscInt *cols;
205       PetscInt       ncols,index_row = global_indices[i];
206       ierr = MatGetRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
207       for (j=0;j<ncols;j++) {
208         PetscInt owner = row_ownership[index_row];
209         PetscInt index_col = global_indices[cols[j]];
210         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
211           my_dnz[i] += 1;
212         } else { /* offdiag block */
213           my_onz[i] += 1;
214         }
215         /* same as before, interchanging rows and cols */
216         if (issbaij) {
217           owner = row_ownership[index_col];
218           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
219             my_dnz[j] += 1;
220           } else {
221             my_onz[j] += 1;
222           }
223         }
224       }
225       ierr = MatRestoreRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
226     }
227   }
228   ierr = ISLocalToGlobalMappingRestoreIndices(matis->mapping,&global_indices);CHKERRQ(ierr);
229   ierr = PetscFree(row_ownership);CHKERRQ(ierr);
230   if (maxreduce) {
231     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
232     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
233     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
234     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
235   } else {
236     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
237     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
238     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
239     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
240   }
241   ierr = PetscFree2(my_dnz,my_onz);CHKERRQ(ierr);
242 
243   /* Resize preallocation if overestimated */
244   for (i=0;i<lrows;i++) {
245     dnz[i] = PetscMin(dnz[i],lcols);
246     onz[i] = PetscMin(onz[i],cols-lcols);
247   }
248   /* set preallocation */
249   ierr = MatMPIAIJSetPreallocation(B,0,dnz,0,onz);CHKERRQ(ierr);
250   for (i=0;i<lrows/bs;i++) {
251     dnz[i] = dnz[i*bs]/bs;
252     onz[i] = onz[i*bs]/bs;
253   }
254   ierr = MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
255   for (i=0;i<lrows/bs;i++) {
256     dnz[i] = dnz[i]-i;
257   }
258   ierr = MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
259   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
260   if (issbaij) {
261     ierr = MatRestoreRowUpperTriangular(matis->A);CHKERRQ(ierr);
262   }
263   PetscFunctionReturn(0);
264 }
265 
266 #undef __FUNCT__
267 #define __FUNCT__ "MatISGetMPIXAIJ_IS"
268 PetscErrorCode MatISGetMPIXAIJ_IS(Mat mat, MatReuse reuse, Mat *M)
269 {
270   Mat_IS                 *matis = (Mat_IS*)(mat->data);
271   /* info on mat */
272   /* ISLocalToGlobalMapping rmapping,cmapping; */
273   PetscInt               bs,rows,cols,lrows,lcols;
274   PetscInt               local_rows,local_cols;
275   PetscBool              isdense,issbaij,isseqaij;
276   const PetscInt         *global_indices_rows;
277   PetscMPIInt            nsubdomains;
278   /* values insertion */
279   PetscScalar            *array;
280   /* work */
281   PetscErrorCode         ierr;
282 
283   PetscFunctionBegin;
284   /* MISSING CHECKS
285     - rectangular case not covered (it is not allowed by MATIS)
286   */
287   /* get info from mat */
288   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)mat),&nsubdomains);CHKERRQ(ierr);
289   if (nsubdomains == 1) {
290     if (reuse == MAT_INITIAL_MATRIX) {
291       ierr = MatDuplicate(matis->A,MAT_COPY_VALUES,&(*M));CHKERRQ(ierr);
292     } else {
293       ierr = MatCopy(matis->A,*M,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
294     }
295     PetscFunctionReturn(0);
296   }
297   /* ierr = MatGetLocalToGlobalMapping(mat,&rmapping,&cmapping);CHKERRQ(ierr); */
298   ierr = MatGetSize(mat,&rows,&cols);CHKERRQ(ierr);
299   ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr);
300   ierr = MatGetLocalSize(mat,&lrows,&lcols);CHKERRQ(ierr);
301   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
302   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr);
303   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
304   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
305 
306   /* map indices of local mat rows to global values */
307   ierr = ISLocalToGlobalMappingGetIndices(matis->mapping,&global_indices_rows);CHKERRQ(ierr);
308 
309   if (issbaij) {
310     ierr = MatGetRowUpperTriangular(matis->A);CHKERRQ(ierr);
311   }
312 
313   if (reuse == MAT_INITIAL_MATRIX) {
314     MatType     new_mat_type;
315     PetscBool   issbaij_red;
316 
317     /* determining new matrix type */
318     ierr = MPI_Allreduce(&issbaij,&issbaij_red,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr);
319     if (issbaij_red) {
320       new_mat_type = MATSBAIJ;
321     } else {
322       if (bs>1) {
323         new_mat_type = MATBAIJ;
324       } else {
325         new_mat_type = MATAIJ;
326       }
327     }
328 
329     ierr = MatCreate(PetscObjectComm((PetscObject)mat),M);CHKERRQ(ierr);
330     ierr = MatSetSizes(*M,lrows,lcols,rows,cols);CHKERRQ(ierr);
331     ierr = MatSetBlockSize(*M,bs);CHKERRQ(ierr);
332     ierr = MatSetType(*M,new_mat_type);CHKERRQ(ierr);
333     ierr = MatISSetMPIXAIJPreallocation_Private(mat,*M,PETSC_FALSE);CHKERRQ(ierr);
334   } else {
335     PetscInt mbs,mrows,mcols,mlrows,mlcols;
336     /* some checks */
337     ierr = MatGetBlockSize(*M,&mbs);CHKERRQ(ierr);
338     ierr = MatGetSize(*M,&mrows,&mcols);CHKERRQ(ierr);
339     ierr = MatGetLocalSize(*M,&mlrows,&mlcols);CHKERRQ(ierr);
340     if (mrows != rows) {
341       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows);
342     }
343     if (mcols != cols) {
344       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols);
345     }
346     if (mlrows != lrows) {
347       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows);
348     }
349     if (mlcols != lcols) {
350       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols);
351     }
352     if (mbs != bs) {
353       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong block size (%d != %d)",bs,mbs);
354     }
355     ierr = MatZeroEntries(*M);CHKERRQ(ierr);
356   }
357   /* set local to global mappings */
358   /* ierr = MatSetLocalToGlobalMapping(*M,matis->mapping,matis->mapping);CHKERRQ(ierr); */
359 
360   /* Set values */
361   if (isdense) { /* special case for dense local matrices */
362     ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
363     ierr = MatDenseGetArray(matis->A,&array);CHKERRQ(ierr);
364     ierr = MatSetValues(*M,local_rows,global_indices_rows,local_cols,global_indices_rows,array,ADD_VALUES);CHKERRQ(ierr);
365     ierr = MatDenseRestoreArray(matis->A,&array);CHKERRQ(ierr);
366   } else if (isseqaij) {
367     PetscInt  i,nvtxs,*xadj,*adjncy,*global_indices_cols;
368     PetscBool done;
369 
370     ierr = MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
371     if (!done) {
372       SETERRQ1(PetscObjectComm((PetscObject)matis->A),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ called in %s\n",__FUNCT__);
373     }
374     ierr = MatSeqAIJGetArray(matis->A,&array);CHKERRQ(ierr);
375     ierr = PetscMalloc1(xadj[nvtxs],&global_indices_cols);CHKERRQ(ierr);
376     ierr = ISLocalToGlobalMappingApply(matis->mapping,xadj[nvtxs],adjncy,global_indices_cols);CHKERRQ(ierr);
377     for (i=0;i<nvtxs;i++) {
378       PetscInt    row,*cols,ncols;
379       PetscScalar *mat_vals;
380 
381       row = global_indices_rows[i];
382       ncols = xadj[i+1]-xadj[i];
383       cols = global_indices_cols+xadj[i];
384       mat_vals = array+xadj[i];
385       ierr = MatSetValues(*M,1,&row,ncols,cols,mat_vals,ADD_VALUES);CHKERRQ(ierr);
386     }
387     ierr = MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
388     if (!done) {
389       SETERRQ1(PetscObjectComm((PetscObject)matis->A),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ called in %s\n",__FUNCT__);
390     }
391     ierr = MatSeqAIJRestoreArray(matis->A,&array);CHKERRQ(ierr);
392     ierr = PetscFree(global_indices_cols);CHKERRQ(ierr);
393   } else { /* very basic values insertion for all other matrix types */
394     PetscInt i,*global_indices_cols;
395 
396     ierr = PetscMalloc1(local_cols,&global_indices_cols);CHKERRQ(ierr);
397     for (i=0;i<local_rows;i++) {
398       PetscInt       j;
399       const PetscInt *local_indices;
400 
401       ierr = MatGetRow(matis->A,i,&j,&local_indices,(const PetscScalar**)&array);CHKERRQ(ierr);
402       ierr = ISLocalToGlobalMappingApply(matis->mapping,j,local_indices,global_indices_cols);CHKERRQ(ierr);
403       ierr = MatSetValues(*M,1,&global_indices_rows[i],j,global_indices_cols,array,ADD_VALUES);CHKERRQ(ierr);
404       ierr = MatRestoreRow(matis->A,i,&j,&local_indices,(const PetscScalar**)&array);CHKERRQ(ierr);
405     }
406     ierr = PetscFree(global_indices_cols);CHKERRQ(ierr);
407   }
408   ierr = MatAssemblyBegin(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
409   ierr = MatAssemblyEnd(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
410   if (isdense) {
411     ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_TRUE);CHKERRQ(ierr);
412   }
413   if (issbaij) {
414     ierr = MatRestoreRowUpperTriangular(matis->A);CHKERRQ(ierr);
415   }
416   ierr = ISLocalToGlobalMappingRestoreIndices(matis->mapping,&global_indices_rows);CHKERRQ(ierr);
417   PetscFunctionReturn(0);
418 }
419 
420 #undef __FUNCT__
421 #define __FUNCT__ "MatISGetMPIXAIJ"
422 /*@
423     MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format
424 
425   Input Parameter:
426 .  mat - the matrix (should be of type MATIS)
427 .  reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
428 
429   Output Parameter:
430 .  newmat - the matrix in AIJ format
431 
432   Level: developer
433 
434   Notes:
435 
436 .seealso: MATIS
437 @*/
438 PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
439 {
440   PetscErrorCode ierr;
441 
442   PetscFunctionBegin;
443   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
444   PetscValidLogicalCollectiveEnum(mat,reuse,2);
445   PetscValidPointer(newmat,3);
446   if (reuse != MAT_INITIAL_MATRIX) {
447     PetscValidHeaderSpecific(*newmat,MAT_CLASSID,3);
448     PetscCheckSameComm(mat,1,*newmat,3);
449   }
450   ierr = PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatReuse,Mat*),(mat,reuse,newmat));CHKERRQ(ierr);
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "MatDuplicate_IS"
456 PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat)
457 {
458   PetscErrorCode ierr;
459   Mat_IS         *matis = (Mat_IS*)(mat->data);
460   PetscInt       bs,m,n,M,N;
461   Mat            B,localmat;
462 
463   PetscFunctionBegin;
464   ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr);
465   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
466   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
467   ierr = MatCreateIS(PetscObjectComm((PetscObject)mat),bs,m,n,M,N,matis->mapping,&B);CHKERRQ(ierr);
468   ierr = MatDuplicate(matis->A,op,&localmat);CHKERRQ(ierr);
469   ierr = MatISSetLocalMat(B,localmat);CHKERRQ(ierr);
470   ierr = MatDestroy(&localmat);CHKERRQ(ierr);
471   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
472   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
473   *newmat = B;
474   PetscFunctionReturn(0);
475 }
476 
477 #undef __FUNCT__
478 #define __FUNCT__ "MatIsHermitian_IS"
479 PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool  *flg)
480 {
481   PetscErrorCode ierr;
482   Mat_IS         *matis = (Mat_IS*)A->data;
483   PetscBool      local_sym;
484 
485   PetscFunctionBegin;
486   ierr = MatIsHermitian(matis->A,tol,&local_sym);CHKERRQ(ierr);
487   ierr = MPI_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
488   PetscFunctionReturn(0);
489 }
490 
491 #undef __FUNCT__
492 #define __FUNCT__ "MatIsSymmetric_IS"
493 PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool  *flg)
494 {
495   PetscErrorCode ierr;
496   Mat_IS         *matis = (Mat_IS*)A->data;
497   PetscBool      local_sym;
498 
499   PetscFunctionBegin;
500   ierr = MatIsSymmetric(matis->A,tol,&local_sym);CHKERRQ(ierr);
501   ierr = MPI_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
502   PetscFunctionReturn(0);
503 }
504 
505 #undef __FUNCT__
506 #define __FUNCT__ "MatDestroy_IS"
507 PetscErrorCode MatDestroy_IS(Mat A)
508 {
509   PetscErrorCode ierr;
510   Mat_IS         *b = (Mat_IS*)A->data;
511 
512   PetscFunctionBegin;
513   ierr = MatDestroy(&b->A);CHKERRQ(ierr);
514   ierr = VecScatterDestroy(&b->ctx);CHKERRQ(ierr);
515   ierr = VecDestroy(&b->x);CHKERRQ(ierr);
516   ierr = VecDestroy(&b->y);CHKERRQ(ierr);
517   ierr = ISLocalToGlobalMappingDestroy(&b->mapping);CHKERRQ(ierr);
518   ierr = PetscSFDestroy(&b->sf);CHKERRQ(ierr);
519   ierr = PetscFree2(b->sf_rootdata,b->sf_leafdata);CHKERRQ(ierr);
520   ierr = PetscFree(A->data);CHKERRQ(ierr);
521   ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr);
522   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);CHKERRQ(ierr);
523   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);CHKERRQ(ierr);
524   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);CHKERRQ(ierr);
525   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);CHKERRQ(ierr);
526   PetscFunctionReturn(0);
527 }
528 
529 #undef __FUNCT__
530 #define __FUNCT__ "MatMult_IS"
531 PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
532 {
533   PetscErrorCode ierr;
534   Mat_IS         *is  = (Mat_IS*)A->data;
535   PetscScalar    zero = 0.0;
536 
537   PetscFunctionBegin;
538   /*  scatter the global vector x into the local work vector */
539   ierr = VecScatterBegin(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
540   ierr = VecScatterEnd(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
541 
542   /* multiply the local matrix */
543   ierr = MatMult(is->A,is->x,is->y);CHKERRQ(ierr);
544 
545   /* scatter product back into global memory */
546   ierr = VecSet(y,zero);CHKERRQ(ierr);
547   ierr = VecScatterBegin(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
548   ierr = VecScatterEnd(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
549   PetscFunctionReturn(0);
550 }
551 
552 #undef __FUNCT__
553 #define __FUNCT__ "MatMultAdd_IS"
554 PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
555 {
556   Vec            temp_vec;
557   PetscErrorCode ierr;
558 
559   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
560   if (v3 != v2) {
561     ierr = MatMult(A,v1,v3);CHKERRQ(ierr);
562     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
563   } else {
564     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
565     ierr = MatMult(A,v1,temp_vec);CHKERRQ(ierr);
566     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
567     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
568     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
569   }
570   PetscFunctionReturn(0);
571 }
572 
573 #undef __FUNCT__
574 #define __FUNCT__ "MatMultTranspose_IS"
575 PetscErrorCode MatMultTranspose_IS(Mat A,Vec x,Vec y)
576 {
577   Mat_IS         *is = (Mat_IS*)A->data;
578   PetscErrorCode ierr;
579 
580   PetscFunctionBegin; /*  y = A' * x */
581   /*  scatter the global vector x into the local work vector */
582   ierr = VecScatterBegin(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
583   ierr = VecScatterEnd(is->ctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
584 
585   /* multiply the local matrix */
586   ierr = MatMultTranspose(is->A,is->x,is->y);CHKERRQ(ierr);
587 
588   /* scatter product back into global vector */
589   ierr = VecSet(y,0);CHKERRQ(ierr);
590   ierr = VecScatterBegin(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
591   ierr = VecScatterEnd(is->ctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
592   PetscFunctionReturn(0);
593 }
594 
595 #undef __FUNCT__
596 #define __FUNCT__ "MatMultTransposeAdd_IS"
597 PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
598 {
599   Vec            temp_vec;
600   PetscErrorCode ierr;
601 
602   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
603   if (v3 != v2) {
604     ierr = MatMultTranspose(A,v1,v3);CHKERRQ(ierr);
605     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
606   } else {
607     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
608     ierr = MatMultTranspose(A,v1,temp_vec);CHKERRQ(ierr);
609     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
610     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
611     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
612   }
613   PetscFunctionReturn(0);
614 }
615 
616 #undef __FUNCT__
617 #define __FUNCT__ "MatView_IS"
618 PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
619 {
620   Mat_IS         *a = (Mat_IS*)A->data;
621   PetscErrorCode ierr;
622   PetscViewer    sviewer;
623 
624   PetscFunctionBegin;
625   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
626   ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
627   ierr = MatView(a->A,sviewer);CHKERRQ(ierr);
628   ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
629   PetscFunctionReturn(0);
630 }
631 
632 #undef __FUNCT__
633 #define __FUNCT__ "MatSetLocalToGlobalMapping_IS"
634 PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
635 {
636   PetscErrorCode ierr;
637   PetscInt       n,bs;
638   Mat_IS         *is = (Mat_IS*)A->data;
639   IS             from,to;
640   Vec            global;
641 
642   PetscFunctionBegin;
643   PetscCheckSameComm(A,1,rmapping,2);
644   if (rmapping != cmapping) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"MATIS requires the row and column mappings to be identical");
645   if (is->mapping) { /* Currenly destroys the objects that will be created by this routine. Is there anything else that should be checked? */
646     ierr = ISLocalToGlobalMappingDestroy(&is->mapping);CHKERRQ(ierr);
647     ierr = VecDestroy(&is->x);CHKERRQ(ierr);
648     ierr = VecDestroy(&is->y);CHKERRQ(ierr);
649     ierr = VecScatterDestroy(&is->ctx);CHKERRQ(ierr);
650     ierr = MatDestroy(&is->A);CHKERRQ(ierr);
651     ierr = PetscSFDestroy(&is->sf);CHKERRQ(ierr);
652     ierr = PetscFree2(is->sf_rootdata,is->sf_leafdata);CHKERRQ(ierr);
653   }
654   ierr = PetscObjectReference((PetscObject)rmapping);CHKERRQ(ierr);
655   ierr = ISLocalToGlobalMappingDestroy(&is->mapping);CHKERRQ(ierr);
656   is->mapping = rmapping;
657 /*
658   ierr = PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);CHKERRQ(ierr);
659   ierr = PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);CHKERRQ(ierr);
660 */
661 
662   /* Create the local matrix A */
663   ierr = ISLocalToGlobalMappingGetSize(rmapping,&n);CHKERRQ(ierr);
664   ierr = ISLocalToGlobalMappingGetBlockSize(rmapping,&bs);CHKERRQ(ierr);
665   ierr = MatCreate(PETSC_COMM_SELF,&is->A);CHKERRQ(ierr);
666   if (bs > 1) {
667     ierr = MatSetType(is->A,MATSEQBAIJ);CHKERRQ(ierr);
668   } else {
669     ierr = MatSetType(is->A,MATSEQAIJ);CHKERRQ(ierr);
670   }
671   ierr = MatSetSizes(is->A,n,n,n,n);CHKERRQ(ierr);
672   ierr = MatSetBlockSize(is->A,bs);CHKERRQ(ierr);
673   ierr = MatSetOptionsPrefix(is->A,((PetscObject)A)->prefix);CHKERRQ(ierr);
674   ierr = MatAppendOptionsPrefix(is->A,"is_");CHKERRQ(ierr);
675   ierr = MatSetFromOptions(is->A);CHKERRQ(ierr);
676 
677   /* Create the local work vectors */
678   ierr = VecCreate(PETSC_COMM_SELF,&is->x);CHKERRQ(ierr);
679   ierr = VecSetBlockSize(is->x,bs);CHKERRQ(ierr);
680   ierr = VecSetSizes(is->x,n,n);CHKERRQ(ierr);
681   ierr = VecSetOptionsPrefix(is->x,((PetscObject)A)->prefix);CHKERRQ(ierr);
682   ierr = VecAppendOptionsPrefix(is->x,"is_");CHKERRQ(ierr);
683   ierr = VecSetFromOptions(is->x);CHKERRQ(ierr);
684   ierr = VecDuplicate(is->x,&is->y);CHKERRQ(ierr);
685 
686   /* setup the global to local scatter */
687   ierr = ISCreateStride(PETSC_COMM_SELF,n,0,1,&to);CHKERRQ(ierr);
688   ierr = ISLocalToGlobalMappingApplyIS(rmapping,to,&from);CHKERRQ(ierr);
689   ierr = MatCreateVecs(A,&global,NULL);CHKERRQ(ierr);
690   ierr = VecScatterCreate(global,from,is->x,to,&is->ctx);CHKERRQ(ierr);
691   ierr = VecDestroy(&global);CHKERRQ(ierr);
692   ierr = ISDestroy(&to);CHKERRQ(ierr);
693   ierr = ISDestroy(&from);CHKERRQ(ierr);
694   PetscFunctionReturn(0);
695 }
696 
697 #undef __FUNCT__
698 #define __FUNCT__ "MatSetValues_IS"
699 PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
700 {
701   Mat_IS         *is = (Mat_IS*)mat->data;
702   PetscInt       rows_l[2048],cols_l[2048];
703   PetscErrorCode ierr;
704 
705   PetscFunctionBegin;
706 #if defined(PETSC_USE_DEBUG)
707   if (m > 2048 || n > 2048) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= 2048: they are %D %D",m,n);
708 #endif
709   ierr = ISG2LMapApply(is->mapping,m,rows,rows_l);CHKERRQ(ierr);
710   ierr = ISG2LMapApply(is->mapping,n,cols,cols_l);CHKERRQ(ierr);
711   ierr = MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
712   PetscFunctionReturn(0);
713 }
714 
715 #undef ISG2LMapSetUp
716 #undef ISG2LMapApply
717 
718 #undef __FUNCT__
719 #define __FUNCT__ "MatSetValuesLocal_IS"
720 PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
721 {
722   PetscErrorCode ierr;
723   Mat_IS         *is = (Mat_IS*)A->data;
724 
725   PetscFunctionBegin;
726   ierr = MatSetValues(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
727   PetscFunctionReturn(0);
728 }
729 
730 #undef __FUNCT__
731 #define __FUNCT__ "MatSetValuesBlockedLocal_IS"
732 PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
733 {
734   PetscErrorCode ierr;
735   Mat_IS         *is = (Mat_IS*)A->data;
736 
737   PetscFunctionBegin;
738   ierr = MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
739   PetscFunctionReturn(0);
740 }
741 
742 #undef __FUNCT__
743 #define __FUNCT__ "MatZeroRows_IS"
744 PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
745 {
746   Mat_IS         *is = (Mat_IS*)A->data;
747   PetscInt       n_l = 0, *rows_l = NULL;
748   PetscErrorCode ierr;
749 
750   PetscFunctionBegin;
751   if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support");
752   if (n) {
753     ierr = PetscMalloc1(n,&rows_l);CHKERRQ(ierr);
754     ierr = ISGlobalToLocalMappingApply(is->mapping,IS_GTOLM_DROP,n,rows,&n_l,rows_l);CHKERRQ(ierr);
755   }
756   ierr = MatZeroRowsLocal(A,n_l,rows_l,diag,x,b);CHKERRQ(ierr);
757   ierr = PetscFree(rows_l);CHKERRQ(ierr);
758   PetscFunctionReturn(0);
759 }
760 
761 #undef __FUNCT__
762 #define __FUNCT__ "MatZeroRowsLocal_IS"
763 PetscErrorCode MatZeroRowsLocal_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
764 {
765   Mat_IS         *is = (Mat_IS*)A->data;
766   PetscErrorCode ierr;
767   PetscInt       i;
768   PetscScalar    *array;
769 
770   PetscFunctionBegin;
771   if (x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support");
772   {
773     /*
774        Set up is->x as a "counting vector". This is in order to MatMult_IS
775        work properly in the interface nodes.
776     */
777     Vec         counter;
778     PetscScalar one=1.0, zero=0.0;
779     ierr = MatCreateVecs(A,&counter,NULL);CHKERRQ(ierr);
780     ierr = VecSet(counter,zero);CHKERRQ(ierr);
781     ierr = VecSet(is->x,one);CHKERRQ(ierr);
782     ierr = VecScatterBegin(is->ctx,is->x,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
783     ierr = VecScatterEnd  (is->ctx,is->x,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
784     ierr = VecScatterBegin(is->ctx,counter,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
785     ierr = VecScatterEnd  (is->ctx,counter,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
786     ierr = VecDestroy(&counter);CHKERRQ(ierr);
787   }
788   if (!n) {
789     is->pure_neumann = PETSC_TRUE;
790   } else {
791     is->pure_neumann = PETSC_FALSE;
792 
793     ierr = VecGetArray(is->x,&array);CHKERRQ(ierr);
794     ierr = MatZeroRows(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
795     for (i=0; i<n; i++) {
796       ierr = MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);CHKERRQ(ierr);
797     }
798     ierr = MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
799     ierr = MatAssemblyEnd  (is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
800     ierr = VecRestoreArray(is->x,&array);CHKERRQ(ierr);
801   }
802   PetscFunctionReturn(0);
803 }
804 
805 #undef __FUNCT__
806 #define __FUNCT__ "MatAssemblyBegin_IS"
807 PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
808 {
809   Mat_IS         *is = (Mat_IS*)A->data;
810   PetscErrorCode ierr;
811 
812   PetscFunctionBegin;
813   ierr = MatAssemblyBegin(is->A,type);CHKERRQ(ierr);
814   PetscFunctionReturn(0);
815 }
816 
817 #undef __FUNCT__
818 #define __FUNCT__ "MatAssemblyEnd_IS"
819 PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
820 {
821   Mat_IS         *is = (Mat_IS*)A->data;
822   PetscErrorCode ierr;
823 
824   PetscFunctionBegin;
825   ierr = MatAssemblyEnd(is->A,type);CHKERRQ(ierr);
826   PetscFunctionReturn(0);
827 }
828 
829 #undef __FUNCT__
830 #define __FUNCT__ "MatISGetLocalMat_IS"
831 PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
832 {
833   Mat_IS *is = (Mat_IS*)mat->data;
834 
835   PetscFunctionBegin;
836   *local = is->A;
837   PetscFunctionReturn(0);
838 }
839 
840 #undef __FUNCT__
841 #define __FUNCT__ "MatISGetLocalMat"
842 /*@
843     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
844 
845   Input Parameter:
846 .  mat - the matrix
847 
848   Output Parameter:
849 .  local - the local matrix usually MATSEQAIJ
850 
851   Level: advanced
852 
853   Notes:
854     This can be called if you have precomputed the nonzero structure of the
855   matrix and want to provide it to the inner matrix object to improve the performance
856   of the MatSetValues() operation.
857 
858 .seealso: MATIS
859 @*/
860 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
861 {
862   PetscErrorCode ierr;
863 
864   PetscFunctionBegin;
865   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
866   PetscValidPointer(local,2);
867   ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
868   PetscFunctionReturn(0);
869 }
870 
871 #undef __FUNCT__
872 #define __FUNCT__ "MatISSetLocalMat_IS"
873 PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
874 {
875   Mat_IS         *is = (Mat_IS*)mat->data;
876   PetscInt       nrows,ncols,orows,ocols;
877   PetscErrorCode ierr;
878 
879   PetscFunctionBegin;
880   if (is->A) {
881     ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr);
882     ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr);
883     if (orows != nrows || ocols != ncols) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local MATIS matrix should be of size %dx%d (you passed a %dx%d matrix)\n",orows,ocols,nrows,ncols);
884   }
885   ierr  = PetscObjectReference((PetscObject)local);CHKERRQ(ierr);
886   ierr  = MatDestroy(&is->A);CHKERRQ(ierr);
887   is->A = local;
888   PetscFunctionReturn(0);
889 }
890 
891 #undef __FUNCT__
892 #define __FUNCT__ "MatISSetLocalMat"
893 /*@
894     MatISSetLocalMat - Set the local matrix stored inside a MATIS matrix.
895 
896   Input Parameter:
897 .  mat - the matrix
898 .  local - the local matrix usually MATSEQAIJ
899 
900   Output Parameter:
901 
902   Level: advanced
903 
904   Notes:
905     This can be called if you have precomputed the local matrix and
906   want to provide it to the matrix object MATIS.
907 
908 .seealso: MATIS
909 @*/
910 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
911 {
912   PetscErrorCode ierr;
913 
914   PetscFunctionBegin;
915   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
916   PetscValidHeaderSpecific(local,MAT_CLASSID,2);
917   ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr);
918   PetscFunctionReturn(0);
919 }
920 
921 #undef __FUNCT__
922 #define __FUNCT__ "MatZeroEntries_IS"
923 PetscErrorCode MatZeroEntries_IS(Mat A)
924 {
925   Mat_IS         *a = (Mat_IS*)A->data;
926   PetscErrorCode ierr;
927 
928   PetscFunctionBegin;
929   ierr = MatZeroEntries(a->A);CHKERRQ(ierr);
930   PetscFunctionReturn(0);
931 }
932 
933 #undef __FUNCT__
934 #define __FUNCT__ "MatScale_IS"
935 PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
936 {
937   Mat_IS         *is = (Mat_IS*)A->data;
938   PetscErrorCode ierr;
939 
940   PetscFunctionBegin;
941   ierr = MatScale(is->A,a);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "MatGetDiagonal_IS"
947 PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
948 {
949   Mat_IS         *is = (Mat_IS*)A->data;
950   PetscErrorCode ierr;
951 
952   PetscFunctionBegin;
953   /* get diagonal of the local matrix */
954   ierr = MatGetDiagonal(is->A,is->x);CHKERRQ(ierr);
955 
956   /* scatter diagonal back into global vector */
957   ierr = VecSet(v,0);CHKERRQ(ierr);
958   ierr = VecScatterBegin(is->ctx,is->x,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
959   ierr = VecScatterEnd  (is->ctx,is->x,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
960   PetscFunctionReturn(0);
961 }
962 
963 #undef __FUNCT__
964 #define __FUNCT__ "MatSetOption_IS"
965 PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
966 {
967   Mat_IS         *a = (Mat_IS*)A->data;
968   PetscErrorCode ierr;
969 
970   PetscFunctionBegin;
971   ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr);
972   PetscFunctionReturn(0);
973 }
974 
975 #undef __FUNCT__
976 #define __FUNCT__ "MatCreateIS"
977 /*@
978     MatCreateIS - Creates a "process" unassmembled matrix, it is assembled on each
979        process but not across processes.
980 
981    Input Parameters:
982 +     comm - MPI communicator that will share the matrix
983 .     bs - local and global block size of the matrix
984 .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
985 -     map - mapping that defines the global number for each local number
986 
987    Output Parameter:
988 .    A - the resulting matrix
989 
990    Level: advanced
991 
992    Notes: See MATIS for more details
993           m and n are NOT related to the size of the map, they are the size of the part of the vector owned
994           by that process. m + nghosts (or n + nghosts) is the length of map since map maps all local points
995           plus the ghost points to global indices.
996 
997 .seealso: MATIS, MatSetLocalToGlobalMapping()
998 @*/
999 PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping map,Mat *A)
1000 {
1001   PetscErrorCode ierr;
1002 
1003   PetscFunctionBegin;
1004   ierr = MatCreate(comm,A);CHKERRQ(ierr);
1005   ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr);
1006   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
1007   ierr = MatSetType(*A,MATIS);CHKERRQ(ierr);
1008   ierr = MatSetUp(*A);CHKERRQ(ierr);
1009   ierr = MatSetLocalToGlobalMapping(*A,map,map);CHKERRQ(ierr);
1010   PetscFunctionReturn(0);
1011 }
1012 
1013 /*MC
1014    MATIS - MATIS = "is" - A matrix type to be used for using the Neumann-Neumann type preconditioners, see PCBDDC.
1015    This stores the matrices in globally unassembled form. Each processor
1016    assembles only its local Neumann problem and the parallel matrix vector
1017    product is handled "implicitly".
1018 
1019    Operations Provided:
1020 +  MatMult()
1021 .  MatMultAdd()
1022 .  MatMultTranspose()
1023 .  MatMultTransposeAdd()
1024 .  MatZeroEntries()
1025 .  MatSetOption()
1026 .  MatZeroRows()
1027 .  MatZeroRowsLocal()
1028 .  MatSetValues()
1029 .  MatSetValuesLocal()
1030 .  MatScale()
1031 .  MatGetDiagonal()
1032 -  MatSetLocalToGlobalMapping()
1033 
1034    Options Database Keys:
1035 . -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
1036 
1037    Notes: Options prefix for the inner matrix are given by -is_mat_xxx
1038 
1039           You must call MatSetLocalToGlobalMapping() before using this matrix type.
1040 
1041           You can do matrix preallocation on the local matrix after you obtain it with
1042           MatISGetLocalMat()
1043 
1044   Level: advanced
1045 
1046 .seealso: PC, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), PCBDDC
1047 
1048 M*/
1049 
1050 #undef __FUNCT__
1051 #define __FUNCT__ "MatCreate_IS"
1052 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
1053 {
1054   PetscErrorCode ierr;
1055   Mat_IS         *b;
1056 
1057   PetscFunctionBegin;
1058   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
1059   A->data = (void*)b;
1060   ierr    = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
1061 
1062   A->ops->mult                    = MatMult_IS;
1063   A->ops->multadd                 = MatMultAdd_IS;
1064   A->ops->multtranspose           = MatMultTranspose_IS;
1065   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
1066   A->ops->destroy                 = MatDestroy_IS;
1067   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
1068   A->ops->setvalues               = MatSetValues_IS;
1069   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
1070   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
1071   A->ops->zerorows                = MatZeroRows_IS;
1072   A->ops->zerorowslocal           = MatZeroRowsLocal_IS;
1073   A->ops->assemblybegin           = MatAssemblyBegin_IS;
1074   A->ops->assemblyend             = MatAssemblyEnd_IS;
1075   A->ops->view                    = MatView_IS;
1076   A->ops->zeroentries             = MatZeroEntries_IS;
1077   A->ops->scale                   = MatScale_IS;
1078   A->ops->getdiagonal             = MatGetDiagonal_IS;
1079   A->ops->setoption               = MatSetOption_IS;
1080   A->ops->ishermitian             = MatIsHermitian_IS;
1081   A->ops->issymmetric             = MatIsSymmetric_IS;
1082   A->ops->duplicate               = MatDuplicate_IS;
1083 
1084   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1085   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1086 
1087   /* zeros pointer */
1088   b->A           = 0;
1089   b->ctx         = 0;
1090   b->x           = 0;
1091   b->y           = 0;
1092   b->mapping     = 0;
1093   b->sf          = 0;
1094   b->sf_rootdata = 0;
1095   b->sf_leafdata = 0;
1096 
1097   /* special MATIS functions */
1098   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr);
1099   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr);
1100   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatISGetMPIXAIJ_IS);CHKERRQ(ierr);
1101   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);CHKERRQ(ierr);
1102   ierr = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr);
1103   PetscFunctionReturn(0);
1104 }
1105