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