xref: /petsc/src/mat/impls/is/matis.c (revision 65f8aed5f7eaa1e2ef2ddeffe666264e0669c876)
1 /*
2     Creates a matrix class for using the Neumann-Neumann type preconditioners.
3     This stores the matrices in globally unassembled form. Each processor
4     assembles only its local Neumann problem and the parallel matrix vector
5     product is handled "implicitly".
6 
7     Currently this allows for only one subdomain per processor.
8 */
9 
10 #include <../src/mat/impls/is/matis.h>      /*I "petscmat.h" I*/
11 #include <petsc/private/sfimpl.h>
12 
13 #define MATIS_MAX_ENTRIES_INSERTION 2048
14 static PetscErrorCode MatSetValuesLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
15 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
16 
17 static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr)
18 {
19   MatISPtAP      ptap = (MatISPtAP)ptr;
20   PetscErrorCode ierr;
21 
22   PetscFunctionBegin;
23   ierr = MatDestroySubMatrices(ptap->ris1 ? 2 : 1,&ptap->lP);CHKERRQ(ierr);
24   ierr = ISDestroy(&ptap->cis0);CHKERRQ(ierr);
25   ierr = ISDestroy(&ptap->cis1);CHKERRQ(ierr);
26   ierr = ISDestroy(&ptap->ris0);CHKERRQ(ierr);
27   ierr = ISDestroy(&ptap->ris1);CHKERRQ(ierr);
28   ierr = PetscFree(ptap);CHKERRQ(ierr);
29   PetscFunctionReturn(0);
30 }
31 
32 static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
33 {
34   MatISPtAP      ptap;
35   Mat_IS         *matis = (Mat_IS*)A->data;
36   Mat            lA,lC;
37   MatReuse       reuse;
38   IS             ris[2],cis[2];
39   PetscContainer c;
40   PetscInt       n;
41   PetscErrorCode ierr;
42 
43   PetscFunctionBegin;
44   ierr = PetscObjectQuery((PetscObject)(C),"_MatIS_PtAP",(PetscObject*)&c);CHKERRQ(ierr);
45   if (!c) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing PtAP information");
46   ierr   = PetscContainerGetPointer(c,(void**)&ptap);CHKERRQ(ierr);
47   ris[0] = ptap->ris0;
48   ris[1] = ptap->ris1;
49   cis[0] = ptap->cis0;
50   cis[1] = ptap->cis1;
51   n      = ptap->ris1 ? 2 : 1;
52   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
53   ierr   = MatCreateSubMatrices(P,n,ris,cis,reuse,&ptap->lP);CHKERRQ(ierr);
54 
55   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
56   ierr = MatISGetLocalMat(C,&lC);CHKERRQ(ierr);
57   if (ptap->ris1) { /* unsymmetric A mapping */
58     Mat lPt;
59 
60     ierr = MatTranspose(ptap->lP[1],MAT_INITIAL_MATRIX,&lPt);CHKERRQ(ierr);
61     ierr = MatMatMatMult(lPt,lA,ptap->lP[0],reuse,ptap->fill,&lC);CHKERRQ(ierr);
62     if (matis->storel2l) {
63       ierr = PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",(PetscObject)lPt);CHKERRQ(ierr);
64     }
65     ierr = MatDestroy(&lPt);CHKERRQ(ierr);
66   } else {
67     ierr = MatPtAP(lA,ptap->lP[0],reuse,ptap->fill,&lC);CHKERRQ(ierr);
68     if (matis->storel2l) {
69      ierr = PetscObjectCompose((PetscObject)(C),"_MatIS_PtAP_l2l",(PetscObject)ptap->lP[0]);CHKERRQ(ierr);
70     }
71   }
72   if (reuse == MAT_INITIAL_MATRIX) {
73     ierr = MatISSetLocalMat(C,lC);CHKERRQ(ierr);
74     ierr = MatDestroy(&lC);CHKERRQ(ierr);
75   }
76   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
77   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
78   PetscFunctionReturn(0);
79 }
80 
81 static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT,IS *cis)
82 {
83   Mat            Po,Pd;
84   IS             zd,zo;
85   const PetscInt *garray;
86   PetscInt       *aux,i,bs;
87   PetscInt       dc,stc,oc,ctd,cto;
88   PetscBool      ismpiaij,ismpibaij,isseqaij,isseqbaij;
89   MPI_Comm       comm;
90   PetscErrorCode ierr;
91 
92   PetscFunctionBegin;
93   PetscValidHeaderSpecific(PT,MAT_CLASSID,1);
94   PetscValidPointer(cis,2);
95   ierr = PetscObjectGetComm((PetscObject)PT,&comm);CHKERRQ(ierr);
96   bs   = 1;
97   ierr = PetscObjectTypeCompare((PetscObject)PT,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr);
98   ierr = PetscObjectTypeCompare((PetscObject)PT,MATMPIBAIJ,&ismpibaij);CHKERRQ(ierr);
99   ierr = PetscObjectBaseTypeCompare((PetscObject)PT,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
100   ierr = PetscObjectTypeCompare((PetscObject)PT,MATSEQBAIJ,&isseqbaij);CHKERRQ(ierr);
101   if (isseqaij || isseqbaij) {
102     Pd = PT;
103     Po = NULL;
104     garray = NULL;
105   } else if (ismpiaij) {
106     ierr = MatMPIAIJGetSeqAIJ(PT,&Pd,&Po,&garray);CHKERRQ(ierr);
107   } else if (ismpibaij) {
108     ierr = MatMPIBAIJGetSeqBAIJ(PT,&Pd,&Po,&garray);CHKERRQ(ierr);
109     ierr = MatGetBlockSize(PT,&bs);CHKERRQ(ierr);
110   } else SETERRQ1(comm,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(PT))->type_name);
111 
112   /* identify any null columns in Pd or Po */
113   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
114      some of the columns are not really zero, but very close to */
115   zo = zd = NULL;
116   if (Po) {
117     ierr = MatFindNonzeroRowsOrCols_Basic(Po,PETSC_TRUE,PETSC_SMALL,&zo);CHKERRQ(ierr);
118   }
119   ierr = MatFindNonzeroRowsOrCols_Basic(Pd,PETSC_TRUE,PETSC_SMALL,&zd);CHKERRQ(ierr);
120 
121   ierr = MatGetLocalSize(PT,NULL,&dc);CHKERRQ(ierr);
122   ierr = MatGetOwnershipRangeColumn(PT,&stc,NULL);CHKERRQ(ierr);
123   if (Po) { ierr = MatGetLocalSize(Po,NULL,&oc);CHKERRQ(ierr); }
124   else oc = 0;
125   ierr = PetscMalloc1((dc+oc)/bs,&aux);CHKERRQ(ierr);
126   if (zd) {
127     const PetscInt *idxs;
128     PetscInt       nz;
129 
130     /* this will throw an error if bs is not valid */
131     ierr = ISSetBlockSize(zd,bs);CHKERRQ(ierr);
132     ierr = ISGetLocalSize(zd,&nz);CHKERRQ(ierr);
133     ierr = ISGetIndices(zd,&idxs);CHKERRQ(ierr);
134     ctd  = nz/bs;
135     for (i=0; i<ctd; i++) aux[i] = (idxs[bs*i]+stc)/bs;
136     ierr = ISRestoreIndices(zd,&idxs);CHKERRQ(ierr);
137   } else {
138     ctd = dc/bs;
139     for (i=0; i<ctd; i++) aux[i] = i+stc/bs;
140   }
141   if (zo) {
142     const PetscInt *idxs;
143     PetscInt       nz;
144 
145     /* this will throw an error if bs is not valid */
146     ierr = ISSetBlockSize(zo,bs);CHKERRQ(ierr);
147     ierr = ISGetLocalSize(zo,&nz);CHKERRQ(ierr);
148     ierr = ISGetIndices(zo,&idxs);CHKERRQ(ierr);
149     cto  = nz/bs;
150     for (i=0; i<cto; i++) aux[i+ctd] = garray[idxs[bs*i]/bs];
151     ierr = ISRestoreIndices(zo,&idxs);CHKERRQ(ierr);
152   } else {
153     cto = oc/bs;
154     for (i=0; i<cto; i++) aux[i+ctd] = garray[i];
155   }
156   ierr = ISCreateBlock(comm,bs,ctd+cto,aux,PETSC_OWN_POINTER,cis);CHKERRQ(ierr);
157   ierr = ISDestroy(&zd);CHKERRQ(ierr);
158   ierr = ISDestroy(&zo);CHKERRQ(ierr);
159   PetscFunctionReturn(0);
160 }
161 
162 static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A,Mat P,PetscReal fill,Mat *C)
163 {
164   Mat                    PT;
165   MatISPtAP              ptap;
166   ISLocalToGlobalMapping Crl2g,Ccl2g,rl2g,cl2g;
167   PetscContainer         c;
168   const PetscInt         *garray;
169   PetscInt               ibs,N,dc;
170   MPI_Comm               comm;
171   PetscErrorCode         ierr;
172 
173   PetscFunctionBegin;
174   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
175   ierr = MatCreate(comm,C);CHKERRQ(ierr);
176   ierr = MatSetType(*C,MATIS);CHKERRQ(ierr);
177   ierr = MatGetSize(P,NULL,&N);CHKERRQ(ierr);
178   ierr = MatGetLocalSize(P,NULL,&dc);CHKERRQ(ierr);
179   ierr = MatSetSizes(*C,dc,dc,N,N);CHKERRQ(ierr);
180 /* Not sure about this
181   ierr = MatGetBlockSizes(P,NULL,&ibs);CHKERRQ(ierr);
182   ierr = MatSetBlockSize(*C,ibs);CHKERRQ(ierr);
183 */
184 
185   ierr = PetscNew(&ptap);CHKERRQ(ierr);
186   ierr = PetscContainerCreate(PETSC_COMM_SELF,&c);CHKERRQ(ierr);
187   ierr = PetscContainerSetPointer(c,ptap);CHKERRQ(ierr);
188   ierr = PetscContainerSetUserDestroy(c,MatISContainerDestroyPtAP_Private);CHKERRQ(ierr);
189   ierr = PetscObjectCompose((PetscObject)(*C),"_MatIS_PtAP",(PetscObject)c);CHKERRQ(ierr);
190   ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
191   ptap->fill = fill;
192 
193   ierr = MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);CHKERRQ(ierr);
194 
195   ierr = ISLocalToGlobalMappingGetBlockSize(cl2g,&ibs);CHKERRQ(ierr);
196   ierr = ISLocalToGlobalMappingGetSize(cl2g,&N);CHKERRQ(ierr);
197   ierr = ISLocalToGlobalMappingGetBlockIndices(cl2g,&garray);CHKERRQ(ierr);
198   ierr = ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris0);CHKERRQ(ierr);
199   ierr = ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&garray);CHKERRQ(ierr);
200 
201   ierr = MatCreateSubMatrix(P,ptap->ris0,NULL,MAT_INITIAL_MATRIX,&PT);CHKERRQ(ierr);
202   ierr = MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis0);CHKERRQ(ierr);
203   ierr = ISLocalToGlobalMappingCreateIS(ptap->cis0,&Ccl2g);CHKERRQ(ierr);
204   ierr = MatDestroy(&PT);CHKERRQ(ierr);
205 
206   Crl2g = NULL;
207   if (rl2g != cl2g) { /* unsymmetric A mapping */
208     PetscBool same,lsame = PETSC_FALSE;
209     PetscInt  N1,ibs1;
210 
211     ierr = ISLocalToGlobalMappingGetSize(rl2g,&N1);CHKERRQ(ierr);
212     ierr = ISLocalToGlobalMappingGetBlockSize(rl2g,&ibs1);CHKERRQ(ierr);
213     ierr = ISLocalToGlobalMappingGetBlockIndices(rl2g,&garray);CHKERRQ(ierr);
214     ierr = ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris1);CHKERRQ(ierr);
215     ierr = ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&garray);CHKERRQ(ierr);
216     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
217       const PetscInt *i1,*i2;
218 
219       ierr = ISBlockGetIndices(ptap->ris0,&i1);CHKERRQ(ierr);
220       ierr = ISBlockGetIndices(ptap->ris1,&i2);CHKERRQ(ierr);
221       ierr = PetscMemcmp(i1,i2,N*sizeof(*i1),&lsame);CHKERRQ(ierr);
222     }
223     ierr = MPIU_Allreduce(&lsame,&same,1,MPIU_BOOL,MPI_LAND,comm);CHKERRQ(ierr);
224     if (same) {
225       ierr = ISDestroy(&ptap->ris1);CHKERRQ(ierr);
226     } else {
227       ierr = MatCreateSubMatrix(P,ptap->ris1,NULL,MAT_INITIAL_MATRIX,&PT);CHKERRQ(ierr);
228       ierr = MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis1);CHKERRQ(ierr);
229       ierr = ISLocalToGlobalMappingCreateIS(ptap->cis1,&Crl2g);CHKERRQ(ierr);
230       ierr = MatDestroy(&PT);CHKERRQ(ierr);
231     }
232   }
233 /* Not sure about this
234   if (!Crl2g) {
235     ierr = MatGetBlockSize(*C,&ibs);CHKERRQ(ierr);
236     ierr = ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs);CHKERRQ(ierr);
237   }
238 */
239   ierr = MatSetLocalToGlobalMapping(*C,Crl2g ? Crl2g : Ccl2g,Ccl2g);CHKERRQ(ierr);
240   ierr = ISLocalToGlobalMappingDestroy(&Crl2g);CHKERRQ(ierr);
241   ierr = ISLocalToGlobalMappingDestroy(&Ccl2g);CHKERRQ(ierr);
242 
243   (*C)->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
244   PetscFunctionReturn(0);
245 }
246 
247 PETSC_INTERN PetscErrorCode MatPtAP_IS_XAIJ(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C)
248 {
249   PetscErrorCode ierr;
250 
251   PetscFunctionBegin;
252   if (scall == MAT_INITIAL_MATRIX) {
253     ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
254     ierr = MatPtAPSymbolic_IS_XAIJ(A,P,fill,C);CHKERRQ(ierr);
255     ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
256   }
257   ierr = PetscLogEventBegin(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
258   ierr = ((*C)->ops->ptapnumeric)(A,P,*C);CHKERRQ(ierr);
259   ierr = PetscLogEventEnd(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
260   PetscFunctionReturn(0);
261 }
262 
263 static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
264 {
265   MatISLocalFields lf = (MatISLocalFields)ptr;
266   PetscInt         i;
267   PetscErrorCode   ierr;
268 
269   PetscFunctionBegin;
270   for (i=0;i<lf->nr;i++) {
271     ierr = ISDestroy(&lf->rf[i]);CHKERRQ(ierr);
272   }
273   for (i=0;i<lf->nc;i++) {
274     ierr = ISDestroy(&lf->cf[i]);CHKERRQ(ierr);
275   }
276   ierr = PetscFree2(lf->rf,lf->cf);CHKERRQ(ierr);
277   ierr = PetscFree(lf);CHKERRQ(ierr);
278   PetscFunctionReturn(0);
279 }
280 
281 static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
282 {
283   Mat            B,lB;
284   PetscErrorCode ierr;
285 
286   PetscFunctionBegin;
287   if (reuse != MAT_REUSE_MATRIX) {
288     ISLocalToGlobalMapping rl2g,cl2g;
289     PetscInt               bs;
290     IS                     is;
291 
292     ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
293     ierr = ISCreateStride(PetscObjectComm((PetscObject)A),A->rmap->n/bs,0,1,&is);CHKERRQ(ierr);
294     if (bs > 1) {
295       IS       is2;
296       PetscInt i,*aux;
297 
298       ierr = ISGetLocalSize(is,&i);CHKERRQ(ierr);
299       ierr = ISGetIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
300       ierr = ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);CHKERRQ(ierr);
301       ierr = ISRestoreIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
302       ierr = ISDestroy(&is);CHKERRQ(ierr);
303       is   = is2;
304     }
305     ierr = ISSetIdentity(is);CHKERRQ(ierr);
306     ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
307     ierr = ISDestroy(&is);CHKERRQ(ierr);
308     ierr = ISCreateStride(PetscObjectComm((PetscObject)A),A->cmap->n/bs,0,1,&is);CHKERRQ(ierr);
309     if (bs > 1) {
310       IS       is2;
311       PetscInt i,*aux;
312 
313       ierr = ISGetLocalSize(is,&i);CHKERRQ(ierr);
314       ierr = ISGetIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
315       ierr = ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);CHKERRQ(ierr);
316       ierr = ISRestoreIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
317       ierr = ISDestroy(&is);CHKERRQ(ierr);
318       is   = is2;
319     }
320     ierr = ISSetIdentity(is);CHKERRQ(ierr);
321     ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
322     ierr = ISDestroy(&is);CHKERRQ(ierr);
323     ierr = MatCreateIS(PetscObjectComm((PetscObject)A),bs,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N,rl2g,cl2g,&B);CHKERRQ(ierr);
324     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
325     ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
326     ierr = MatDuplicate(A,MAT_COPY_VALUES,&lB);CHKERRQ(ierr);
327     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
328   } else {
329     B    = *newmat;
330     ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
331     lB   = A;
332   }
333   ierr = MatISSetLocalMat(B,lB);CHKERRQ(ierr);
334   ierr = MatDestroy(&lB);CHKERRQ(ierr);
335   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
336   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
337   if (reuse == MAT_INPLACE_MATRIX) {
338     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
339   }
340   PetscFunctionReturn(0);
341 }
342 
343 static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
344 {
345   Mat_IS         *matis = (Mat_IS*)(A->data);
346   PetscScalar    *aa;
347   const PetscInt *ii,*jj;
348   PetscInt       i,n,m;
349   PetscInt       *ecount,**eneighs;
350   PetscBool      flg;
351   PetscErrorCode ierr;
352 
353   PetscFunctionBegin;
354   ierr = MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);CHKERRQ(ierr);
355   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
356   ierr = ISLocalToGlobalMappingGetNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);CHKERRQ(ierr);
357   if (m != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",m,n);
358   ierr = MatSeqAIJGetArray(matis->A,&aa);CHKERRQ(ierr);
359   for (i=0;i<n;i++) {
360     if (ecount[i] > 1) {
361       PetscInt j;
362 
363       for (j=ii[i];j<ii[i+1];j++) {
364         PetscInt    i2 = jj[j],p,p2;
365         PetscReal   scal = 0.0;
366 
367         for (p=0;p<ecount[i];p++) {
368           for (p2=0;p2<ecount[i2];p2++) {
369             if (eneighs[i][p] == eneighs[i2][p2]) { scal += 1.0; break; }
370           }
371         }
372         if (scal) aa[j] /= scal;
373       }
374     }
375   }
376   ierr = ISLocalToGlobalMappingRestoreNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);CHKERRQ(ierr);
377   ierr = MatSeqAIJRestoreArray(matis->A,&aa);CHKERRQ(ierr);
378   ierr = MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);CHKERRQ(ierr);
379   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
380   PetscFunctionReturn(0);
381 }
382 
383 typedef enum {MAT_IS_DISASSEMBLE_L2G_NATURAL,MAT_IS_DISASSEMBLE_L2G_MAT, MAT_IS_DISASSEMBLE_L2G_ND} MatISDisassemblel2gType;
384 
385 static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
386 {
387   Mat                     Ad,Ao;
388   IS                      is,ndmap,ndsub;
389   MPI_Comm                comm;
390   const PetscInt          *garray,*ndmapi;
391   PetscInt                bs,i,cnt,nl,*ncount,*ndmapc;
392   PetscBool               ismpiaij,ismpibaij;
393   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL","MAT","ND","MatISDisassemblel2gType","MAT_IS_DISASSEMBLE_L2G_",0};
394   MatISDisassemblel2gType mode = MAT_IS_DISASSEMBLE_L2G_NATURAL;
395   MatPartitioning         part;
396   PetscSF                 sf;
397   PetscErrorCode          ierr;
398 
399   PetscFunctionBegin;
400   ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"MatIS l2g disassembling options","Mat");CHKERRQ(ierr);
401   ierr = PetscOptionsEnum("-mat_is_disassemble_l2g_type","Type of local-to-global mapping to be used for disassembling","MatISDisassemblel2gType",MatISDisassemblel2gTypes,(PetscEnum)mode,(PetscEnum*)&mode,NULL);CHKERRQ(ierr);
402   ierr = PetscOptionsEnd();CHKERRQ(ierr);
403   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
404     ierr = MatGetLocalToGlobalMapping(A,l2g,NULL);CHKERRQ(ierr);
405     PetscFunctionReturn(0);
406   }
407   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
408   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);CHKERRQ(ierr);
409   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);CHKERRQ(ierr);
410   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
411   switch (mode) {
412   case MAT_IS_DISASSEMBLE_L2G_ND:
413     ierr = MatPartitioningCreate(comm,&part);CHKERRQ(ierr);
414     ierr = MatPartitioningSetAdjacency(part,A);CHKERRQ(ierr);
415     ierr = PetscObjectSetOptionsPrefix((PetscObject)part,((PetscObject)A)->prefix);CHKERRQ(ierr);
416     ierr = MatPartitioningSetFromOptions(part);CHKERRQ(ierr);
417     ierr = MatPartitioningApplyND(part,&ndmap);CHKERRQ(ierr);
418     ierr = MatPartitioningDestroy(&part);CHKERRQ(ierr);
419     ierr = ISBuildTwoSided(ndmap,NULL,&ndsub);CHKERRQ(ierr);
420     ierr = MatMPIAIJSetUseScalableIncreaseOverlap(A,PETSC_TRUE);CHKERRQ(ierr);
421     ierr = MatIncreaseOverlap(A,1,&ndsub,1);CHKERRQ(ierr);
422     ierr = ISLocalToGlobalMappingCreateIS(ndsub,l2g);CHKERRQ(ierr);
423 
424     /* it may happen that a separator node is not properly shared */
425     ierr = ISLocalToGlobalMappingGetNodeInfo(*l2g,&nl,&ncount,NULL);CHKERRQ(ierr);
426     ierr = PetscSFCreate(comm,&sf);CHKERRQ(ierr);
427     ierr = ISLocalToGlobalMappingGetIndices(*l2g,&garray);CHKERRQ(ierr);
428     ierr = PetscSFSetGraphLayout(sf,A->rmap,nl,NULL,PETSC_OWN_POINTER,garray);CHKERRQ(ierr);
429     ierr = ISLocalToGlobalMappingRestoreIndices(*l2g,&garray);CHKERRQ(ierr);
430     ierr = PetscCalloc1(A->rmap->n,&ndmapc);CHKERRQ(ierr);
431     ierr = PetscSFReduceBegin(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);CHKERRQ(ierr);
432     ierr = PetscSFReduceEnd(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);CHKERRQ(ierr);
433     ierr = ISLocalToGlobalMappingRestoreNodeInfo(*l2g,NULL,&ncount,NULL);CHKERRQ(ierr);
434     ierr = ISGetIndices(ndmap,&ndmapi);CHKERRQ(ierr);
435     for (i = 0, cnt = 0; i < A->rmap->n; i++)
436       if (ndmapi[i] < 0 && ndmapc[i] < 2)
437         cnt++;
438 
439     ierr = MPIU_Allreduce(&cnt,&i,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
440     if (i) { /* we detected isolated separator nodes */
441       Mat                    A2,A3;
442       IS                     *workis,is2;
443       PetscScalar            *vals;
444       PetscInt               gcnt = i,*dnz,*onz,j,*lndmapi;
445       ISLocalToGlobalMapping ll2g;
446       PetscBool              flg;
447       const PetscInt         *ii,*jj;
448 
449       /* communicate global id of separators */
450       ierr = MatPreallocateInitialize(comm,A->rmap->n,A->cmap->n,dnz,onz);CHKERRQ(ierr);
451       for (i = 0, cnt = 0; i < A->rmap->n; i++)
452         dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
453 
454       ierr = PetscMalloc1(nl,&lndmapi);CHKERRQ(ierr);
455       ierr = PetscSFBcastBegin(sf,MPIU_INT,dnz,lndmapi);CHKERRQ(ierr);
456 
457       /* compute adjacency of isolated separators node */
458       ierr = PetscMalloc1(gcnt,&workis);CHKERRQ(ierr);
459       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
460         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
461           ierr = ISCreateStride(comm,1,i+A->rmap->rstart,1,&workis[cnt++]);CHKERRQ(ierr);
462         }
463       }
464       for (i = cnt; i < gcnt; i++) {
465         ierr = ISCreateStride(comm,0,0,1,&workis[i]);CHKERRQ(ierr);
466       }
467       for (i = 0; i < gcnt; i++) {
468         ierr = PetscObjectSetName((PetscObject)workis[i],"ISOLATED");CHKERRQ(ierr);
469         ierr = ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");CHKERRQ(ierr);
470       }
471 
472       /* no communications since all the ISes correspond to locally owned rows */
473       ierr = MatIncreaseOverlap(A,gcnt,workis,1);CHKERRQ(ierr);
474 
475       /* end communicate global id of separators */
476       ierr = PetscSFBcastEnd(sf,MPIU_INT,dnz,lndmapi);CHKERRQ(ierr);
477 
478       /* communicate new layers : create a matrix and transpose it */
479       ierr = PetscMemzero(dnz,A->rmap->n*sizeof(*dnz));CHKERRQ(ierr);
480       ierr = PetscMemzero(onz,A->rmap->n*sizeof(*onz));CHKERRQ(ierr);
481       for (i = 0, j = 0; i < A->rmap->n; i++) {
482         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
483           const PetscInt* idxs;
484           PetscInt        s;
485 
486           ierr = ISGetLocalSize(workis[j],&s);CHKERRQ(ierr);
487           ierr = ISGetIndices(workis[j],&idxs);CHKERRQ(ierr);
488           ierr = MatPreallocateSet(i+A->rmap->rstart,s,idxs,dnz,onz);CHKERRQ(ierr);
489           j++;
490         }
491       }
492       if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);
493 
494       for (i = 0; i < gcnt; i++) {
495         ierr = PetscObjectSetName((PetscObject)workis[i],"EXTENDED");CHKERRQ(ierr);
496         ierr = ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");CHKERRQ(ierr);
497       }
498 
499       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j,dnz[i]+onz[i]);
500       ierr = PetscMalloc1(j,&vals);CHKERRQ(ierr);
501       for (i = 0; i < j; i++) vals[i] = 1.0;
502 
503       ierr = MatCreate(comm,&A2);CHKERRQ(ierr);
504       ierr = MatSetType(A2,MATMPIAIJ);CHKERRQ(ierr);
505       ierr = MatSetSizes(A2,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
506       ierr = MatMPIAIJSetPreallocation(A2,0,dnz,0,onz);CHKERRQ(ierr);
507       ierr = MatSetOption(A2,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
508       for (i = 0, j = 0; i < A2->rmap->n; i++) {
509         PetscInt        row = i+A2->rmap->rstart,s = dnz[i] + onz[i];
510         const PetscInt* idxs;
511 
512         if (s) {
513           ierr = ISGetIndices(workis[j],&idxs);CHKERRQ(ierr);
514           ierr = MatSetValues(A2,1,&row,s,idxs,vals,INSERT_VALUES);CHKERRQ(ierr);
515           ierr = ISRestoreIndices(workis[j],&idxs);CHKERRQ(ierr);
516           j++;
517         }
518       }
519       if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);
520       ierr = PetscFree(vals);CHKERRQ(ierr);
521       ierr = MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
522       ierr = MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
523       ierr = MatTranspose(A2,MAT_INPLACE_MATRIX,&A2);CHKERRQ(ierr);
524 
525       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
526       for (i = 0, j = 0; i < nl; i++)
527         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
528       ierr = ISCreateGeneral(comm,j,lndmapi,PETSC_USE_POINTER,&is);CHKERRQ(ierr);
529       ierr = MatMPIAIJGetLocalMatCondensed(A2,MAT_INITIAL_MATRIX,&is,NULL,&A3);CHKERRQ(ierr);
530       ierr = ISDestroy(&is);CHKERRQ(ierr);
531       ierr = MatDestroy(&A2);CHKERRQ(ierr);
532 
533       /* extend local to global map to include connected isolated separators */
534       ierr = PetscObjectQuery((PetscObject)A3,"_petsc_GetLocalMatCondensed_iscol",(PetscObject*)&is);CHKERRQ(ierr);
535       if (!is) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing column map");
536       ierr = ISLocalToGlobalMappingCreateIS(is,&ll2g);CHKERRQ(ierr);
537       ierr = MatGetRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);CHKERRQ(ierr);
538       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
539       ierr = ISCreateGeneral(PETSC_COMM_SELF,ii[i],jj,PETSC_COPY_VALUES,&is);CHKERRQ(ierr);
540       ierr = MatRestoreRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);CHKERRQ(ierr);
541       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
542       ierr = ISLocalToGlobalMappingApplyIS(ll2g,is,&is2);CHKERRQ(ierr);
543       ierr = ISDestroy(&is);CHKERRQ(ierr);
544       ierr = ISLocalToGlobalMappingDestroy(&ll2g);CHKERRQ(ierr);
545 
546       /* add new nodes to the local-to-global map */
547       ierr = ISLocalToGlobalMappingDestroy(l2g);CHKERRQ(ierr);
548       ierr = ISExpand(ndsub,is2,&is);CHKERRQ(ierr);
549       ierr = ISDestroy(&is2);CHKERRQ(ierr);
550       ierr = ISLocalToGlobalMappingCreateIS(is,l2g);CHKERRQ(ierr);
551       ierr = ISDestroy(&is);CHKERRQ(ierr);
552 
553       ierr = MatDestroy(&A3);CHKERRQ(ierr);
554       ierr = PetscFree(lndmapi);CHKERRQ(ierr);
555       ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
556       for (i = 0; i < gcnt; i++) {
557         ierr = ISDestroy(&workis[i]);CHKERRQ(ierr);
558       }
559       ierr = PetscFree(workis);CHKERRQ(ierr);
560     }
561     ierr = ISRestoreIndices(ndmap,&ndmapi);CHKERRQ(ierr);
562     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
563     ierr = PetscFree(ndmapc);CHKERRQ(ierr);
564     ierr = ISDestroy(&ndmap);CHKERRQ(ierr);
565     ierr = ISDestroy(&ndsub);CHKERRQ(ierr);
566     ierr = ISLocalToGlobalMappingSetBlockSize(*l2g,bs);CHKERRQ(ierr);
567     ierr = ISLocalToGlobalMappingViewFromOptions(*l2g,NULL,"-matis_nd_l2g_view");CHKERRQ(ierr);
568     break;
569   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
570     if (ismpiaij) {
571       ierr = MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);CHKERRQ(ierr);
572     } else if (ismpibaij) {
573       ierr = MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);CHKERRQ(ierr);
574     } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
575     if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");
576     if (A->rmap->n) {
577       PetscInt dc,oc,stc,*aux;
578 
579       ierr = MatGetLocalSize(A,NULL,&dc);CHKERRQ(ierr);
580       ierr = MatGetLocalSize(Ao,NULL,&oc);CHKERRQ(ierr);
581       ierr = MatGetOwnershipRangeColumn(A,&stc,NULL);CHKERRQ(ierr);
582       ierr = PetscMalloc1((dc+oc)/bs,&aux);CHKERRQ(ierr);
583       for (i=0; i<dc/bs; i++) aux[i]       = i+stc/bs;
584       for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
585       ierr = ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
586     } else {
587       ierr = ISCreateBlock(comm,1,0,NULL,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
588     }
589     ierr = ISLocalToGlobalMappingCreateIS(is,l2g);CHKERRQ(ierr);
590     ierr = ISDestroy(&is);CHKERRQ(ierr);
591     break;
592   default:
593     SETERRQ1(comm,PETSC_ERR_ARG_WRONG,"Unsupported l2g disassembling type %D",mode);
594   }
595   PetscFunctionReturn(0);
596 }
597 
598 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
599 {
600   Mat                    lA,Ad,Ao,B = NULL;
601   ISLocalToGlobalMapping rl2g,cl2g;
602   IS                     is;
603   MPI_Comm               comm;
604   void                   *ptrs[2];
605   const char             *names[2] = {"_convert_csr_aux","_convert_csr_data"};
606   const PetscInt         *garray;
607   PetscScalar            *dd,*od,*aa,*data;
608   const PetscInt         *di,*dj,*oi,*oj;
609   const PetscInt         *odi,*odj,*ooi,*ooj;
610   PetscInt               *aux,*ii,*jj;
611   PetscInt               bs,lc,dr,dc,oc,str,stc,nnz,i,jd,jo,cum;
612   PetscBool              flg,ismpiaij,ismpibaij,was_inplace = PETSC_FALSE;
613   PetscMPIInt            size;
614   PetscErrorCode         ierr;
615 
616   PetscFunctionBegin;
617   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
618   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
619   if (size == 1) {
620     ierr = MatConvert_SeqXAIJ_IS(A,type,reuse,newmat);CHKERRQ(ierr);
621     PetscFunctionReturn(0);
622   }
623   if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
624     ierr = MatMPIXAIJComputeLocalToGlobalMapping_Private(A,&rl2g);CHKERRQ(ierr);
625     ierr = MatCreate(comm,&B);CHKERRQ(ierr);
626     ierr = MatSetType(B,MATIS);CHKERRQ(ierr);
627     ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
628     ierr = MatSetLocalToGlobalMapping(B,rl2g,rl2g);CHKERRQ(ierr);
629     ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
630     ierr = MatSetBlockSize(B,bs);CHKERRQ(ierr);
631     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
632     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
633     reuse = MAT_REUSE_MATRIX;
634   }
635   if (reuse == MAT_REUSE_MATRIX) {
636     Mat            *newlA, lA;
637     IS             rows, cols;
638     const PetscInt *ridx, *cidx;
639     PetscInt       rbs, cbs, nr, nc;
640 
641     if (!B) B = *newmat;
642     ierr = MatGetLocalToGlobalMapping(B,&rl2g,&cl2g);CHKERRQ(ierr);
643     ierr = ISLocalToGlobalMappingGetBlockIndices(rl2g,&ridx);CHKERRQ(ierr);
644     ierr = ISLocalToGlobalMappingGetBlockIndices(cl2g,&cidx);CHKERRQ(ierr);
645     ierr = ISLocalToGlobalMappingGetSize(rl2g,&nr);CHKERRQ(ierr);
646     ierr = ISLocalToGlobalMappingGetSize(cl2g,&nc);CHKERRQ(ierr);
647     ierr = ISLocalToGlobalMappingGetBlockSize(rl2g,&rbs);CHKERRQ(ierr);
648     ierr = ISLocalToGlobalMappingGetBlockSize(cl2g,&cbs);CHKERRQ(ierr);
649     ierr = ISCreateBlock(comm,rbs,nr/rbs,ridx,PETSC_USE_POINTER,&rows);CHKERRQ(ierr);
650     if (rl2g != cl2g) {
651       ierr = ISCreateBlock(comm,cbs,nc/cbs,cidx,PETSC_USE_POINTER,&cols);CHKERRQ(ierr);
652     } else {
653       ierr = PetscObjectReference((PetscObject)rows);CHKERRQ(ierr);
654       cols = rows;
655     }
656     ierr = MatISGetLocalMat(B,&lA);CHKERRQ(ierr);
657     ierr = MatCreateSubMatrices(A,1,&rows,&cols,MAT_INITIAL_MATRIX,&newlA);CHKERRQ(ierr);
658     ierr = MatConvert(newlA[0],MATSEQAIJ,MAT_INPLACE_MATRIX,&newlA[0]);CHKERRQ(ierr);
659     ierr = ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&ridx);CHKERRQ(ierr);
660     ierr = ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&cidx);CHKERRQ(ierr);
661     ierr = ISDestroy(&rows);CHKERRQ(ierr);
662     ierr = ISDestroy(&cols);CHKERRQ(ierr);
663     if (!lA->preallocated) { /* first time */
664       ierr = MatDuplicate(newlA[0],MAT_COPY_VALUES,&lA);CHKERRQ(ierr);
665       ierr = MatISSetLocalMat(B,lA);CHKERRQ(ierr);
666       ierr = PetscObjectDereference((PetscObject)lA);CHKERRQ(ierr);
667     }
668     ierr = MatCopy(newlA[0],lA,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
669     ierr = MatDestroySubMatrices(1,&newlA);CHKERRQ(ierr);
670     ierr = MatISScaleDisassembling_Private(B);CHKERRQ(ierr);
671     ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
672     ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
673     if (was_inplace) { ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr); }
674     else *newmat = B;
675     PetscFunctionReturn(0);
676   }
677   /* rectangular case, just compress out the column space */
678   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);CHKERRQ(ierr);
679   ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);CHKERRQ(ierr);
680   if (ismpiaij) {
681     bs   = 1;
682     ierr = MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);CHKERRQ(ierr);
683   } else if (ismpibaij) {
684     ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
685     ierr = MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);CHKERRQ(ierr);
686     ierr = MatConvert(Ad,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ad);CHKERRQ(ierr);
687     ierr = MatConvert(Ao,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ao);CHKERRQ(ierr);
688   } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
689   ierr = MatSeqAIJGetArray(Ad,&dd);CHKERRQ(ierr);
690   ierr = MatSeqAIJGetArray(Ao,&od);CHKERRQ(ierr);
691   if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");
692 
693   /* access relevant information from MPIAIJ */
694   ierr = MatGetOwnershipRange(A,&str,NULL);CHKERRQ(ierr);
695   ierr = MatGetOwnershipRangeColumn(A,&stc,NULL);CHKERRQ(ierr);
696   ierr = MatGetLocalSize(A,&dr,&dc);CHKERRQ(ierr);
697   ierr = MatGetLocalSize(Ao,NULL,&oc);CHKERRQ(ierr);
698   ierr = MatGetRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&di,&dj,&flg);CHKERRQ(ierr);
699   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
700   ierr = MatGetRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&oi,&oj,&flg);CHKERRQ(ierr);
701   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
702   nnz = di[dr] + oi[dr];
703   /* store original pointers to be restored later */
704   odi = di; odj = dj; ooi = oi; ooj = oj;
705 
706   /* generate l2g maps for rows and cols */
707   ierr = ISCreateStride(comm,dr/bs,str/bs,1,&is);CHKERRQ(ierr);
708   if (bs > 1) {
709     IS is2;
710 
711     ierr = ISGetLocalSize(is,&i);CHKERRQ(ierr);
712     ierr = ISGetIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
713     ierr = ISCreateBlock(comm,bs,i,aux,PETSC_COPY_VALUES,&is2);CHKERRQ(ierr);
714     ierr = ISRestoreIndices(is,(const PetscInt**)&aux);CHKERRQ(ierr);
715     ierr = ISDestroy(&is);CHKERRQ(ierr);
716     is   = is2;
717   }
718   ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
719   ierr = ISDestroy(&is);CHKERRQ(ierr);
720   if (dr) {
721     ierr = PetscMalloc1((dc+oc)/bs,&aux);CHKERRQ(ierr);
722     for (i=0; i<dc/bs; i++) aux[i]       = i+stc/bs;
723     for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
724     ierr = ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
725     lc   = dc+oc;
726   } else {
727     ierr = ISCreateBlock(comm,bs,0,NULL,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
728     lc   = 0;
729   }
730   ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
731   ierr = ISDestroy(&is);CHKERRQ(ierr);
732 
733   /* create MATIS object */
734   ierr = MatCreate(comm,&B);CHKERRQ(ierr);
735   ierr = MatSetSizes(B,dr,dc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
736   ierr = MatSetType(B,MATIS);CHKERRQ(ierr);
737   ierr = MatSetBlockSize(B,bs);CHKERRQ(ierr);
738   ierr = MatSetLocalToGlobalMapping(B,rl2g,cl2g);CHKERRQ(ierr);
739   ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
740   ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
741 
742   /* merge local matrices */
743   ierr = PetscMalloc1(nnz+dr+1,&aux);CHKERRQ(ierr);
744   ierr = PetscMalloc1(nnz,&data);CHKERRQ(ierr);
745   ii   = aux;
746   jj   = aux+dr+1;
747   aa   = data;
748   *ii  = *(di++) + *(oi++);
749   for (jd=0,jo=0,cum=0;*ii<nnz;cum++)
750   {
751      for (;jd<*di;jd++) { *jj++ = *dj++;      *aa++ = *dd++; }
752      for (;jo<*oi;jo++) { *jj++ = *oj++ + dc; *aa++ = *od++; }
753      *(++ii) = *(di++) + *(oi++);
754   }
755   for (;cum<dr;cum++) *(++ii) = nnz;
756 
757   ierr = MatRestoreRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&odi,&odj,&flg);CHKERRQ(ierr);
758   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
759   ierr = MatRestoreRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&ooi,&ooj,&flg);CHKERRQ(ierr);
760   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
761   ierr = MatSeqAIJRestoreArray(Ad,&dd);CHKERRQ(ierr);
762   ierr = MatSeqAIJRestoreArray(Ao,&od);CHKERRQ(ierr);
763 
764   ii   = aux;
765   jj   = aux+dr+1;
766   aa   = data;
767   ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,lc,ii,jj,aa,&lA);CHKERRQ(ierr);
768 
769   /* create containers to destroy the data */
770   ptrs[0] = aux;
771   ptrs[1] = data;
772   for (i=0; i<2; i++) {
773     PetscContainer c;
774 
775     ierr = PetscContainerCreate(PETSC_COMM_SELF,&c);CHKERRQ(ierr);
776     ierr = PetscContainerSetPointer(c,ptrs[i]);CHKERRQ(ierr);
777     ierr = PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault);CHKERRQ(ierr);
778     ierr = PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);CHKERRQ(ierr);
779     ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
780   }
781   if (ismpibaij) { /* destroy converted local matrices */
782     ierr = MatDestroy(&Ad);CHKERRQ(ierr);
783     ierr = MatDestroy(&Ao);CHKERRQ(ierr);
784   }
785 
786   /* finalize matrix */
787   ierr = MatISSetLocalMat(B,lA);CHKERRQ(ierr);
788   ierr = MatDestroy(&lA);CHKERRQ(ierr);
789   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
790   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
791   if (reuse == MAT_INPLACE_MATRIX) {
792     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
793   } else *newmat = B;
794   PetscFunctionReturn(0);
795 }
796 
797 /*@
798    MatISSetUpSF - Setup star forest objects used by MatIS.
799 
800    Collective on MPI_Comm
801 
802    Input Parameters:
803 +  A - the matrix
804 
805    Level: advanced
806 
807    Notes:
808     This function does not need to be called by the user.
809 
810 .keywords: matrix
811 
812 .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatISGetLocalMat()
813 @*/
814 PetscErrorCode  MatISSetUpSF(Mat A)
815 {
816   PetscErrorCode ierr;
817 
818   PetscFunctionBegin;
819   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
820   PetscValidType(A,1);
821   ierr = PetscTryMethod(A,"MatISSetUpSF_C",(Mat),(A));CHKERRQ(ierr);
822   PetscFunctionReturn(0);
823 }
824 
825 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
826 {
827   Mat                    **nest,*snest,**rnest,lA,B;
828   IS                     *iscol,*isrow,*islrow,*islcol;
829   ISLocalToGlobalMapping rl2g,cl2g;
830   MPI_Comm               comm;
831   PetscInt               *lr,*lc,*l2gidxs;
832   PetscInt               i,j,nr,nc,rbs,cbs;
833   PetscBool              convert,lreuse,*istrans;
834   PetscErrorCode         ierr;
835 
836   PetscFunctionBegin;
837   ierr   = MatNestGetSubMats(A,&nr,&nc,&nest);CHKERRQ(ierr);
838   lreuse = PETSC_FALSE;
839   rnest  = NULL;
840   if (reuse == MAT_REUSE_MATRIX) {
841     PetscBool ismatis,isnest;
842 
843     ierr = PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);CHKERRQ(ierr);
844     if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_USER,"Cannot reuse matrix of type %s",((PetscObject)(*newmat))->type);
845     ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
846     ierr = PetscObjectTypeCompare((PetscObject)lA,MATNEST,&isnest);CHKERRQ(ierr);
847     if (isnest) {
848       ierr   = MatNestGetSubMats(lA,&i,&j,&rnest);CHKERRQ(ierr);
849       lreuse = (PetscBool)(i == nr && j == nc);
850       if (!lreuse) rnest = NULL;
851     }
852   }
853   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
854   ierr = PetscCalloc2(nr,&lr,nc,&lc);CHKERRQ(ierr);
855   ierr = PetscCalloc6(nr,&isrow,nc,&iscol,
856                       nr,&islrow,nc,&islcol,
857                       nr*nc,&snest,nr*nc,&istrans);CHKERRQ(ierr);
858   ierr = MatNestGetISs(A,isrow,iscol);CHKERRQ(ierr);
859   for (i=0;i<nr;i++) {
860     for (j=0;j<nc;j++) {
861       PetscBool ismatis;
862       PetscInt  l1,l2,lb1,lb2,ij=i*nc+j;
863 
864       /* Null matrix pointers are allowed in MATNEST */
865       if (!nest[i][j]) continue;
866 
867       /* Nested matrices should be of type MATIS */
868       ierr = PetscObjectTypeCompare((PetscObject)nest[i][j],MATTRANSPOSEMAT,&istrans[ij]);CHKERRQ(ierr);
869       if (istrans[ij]) {
870         Mat T,lT;
871         ierr = MatTransposeGetMat(nest[i][j],&T);CHKERRQ(ierr);
872         ierr = PetscObjectTypeCompare((PetscObject)T,MATIS,&ismatis);CHKERRQ(ierr);
873         if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) (transposed) is not of type MATIS",i,j);
874         ierr = MatISGetLocalMat(T,&lT);CHKERRQ(ierr);
875         ierr = MatCreateTranspose(lT,&snest[ij]);CHKERRQ(ierr);
876       } else {
877         ierr = PetscObjectTypeCompare((PetscObject)nest[i][j],MATIS,&ismatis);CHKERRQ(ierr);
878         if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) is not of type MATIS",i,j);
879         ierr = MatISGetLocalMat(nest[i][j],&snest[ij]);CHKERRQ(ierr);
880       }
881 
882       /* Check compatibility of local sizes */
883       ierr = MatGetSize(snest[ij],&l1,&l2);CHKERRQ(ierr);
884       ierr = MatGetBlockSizes(snest[ij],&lb1,&lb2);CHKERRQ(ierr);
885       if (!l1 || !l2) continue;
886       if (lr[i] && l1 != lr[i]) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid local size %D != %D",i,j,lr[i],l1);
887       if (lc[j] && l2 != lc[j]) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid local size %D != %D",i,j,lc[j],l2);
888       lr[i] = l1;
889       lc[j] = l2;
890 
891       /* check compatibilty for local matrix reusage */
892       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
893     }
894   }
895 
896 #if defined (PETSC_USE_DEBUG)
897   /* Check compatibility of l2g maps for rows */
898   for (i=0;i<nr;i++) {
899     rl2g = NULL;
900     for (j=0;j<nc;j++) {
901       PetscInt n1,n2;
902 
903       if (!nest[i][j]) continue;
904       if (istrans[i*nc+j]) {
905         Mat T;
906 
907         ierr = MatTransposeGetMat(nest[i][j],&T);CHKERRQ(ierr);
908         ierr = MatGetLocalToGlobalMapping(T,NULL,&cl2g);CHKERRQ(ierr);
909       } else {
910         ierr = MatGetLocalToGlobalMapping(nest[i][j],&cl2g,NULL);CHKERRQ(ierr);
911       }
912       ierr = ISLocalToGlobalMappingGetSize(cl2g,&n1);CHKERRQ(ierr);
913       if (!n1) continue;
914       if (!rl2g) {
915         rl2g = cl2g;
916       } else {
917         const PetscInt *idxs1,*idxs2;
918         PetscBool      same;
919 
920         ierr = ISLocalToGlobalMappingGetSize(rl2g,&n2);CHKERRQ(ierr);
921         if (n1 != n2) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid row l2gmap size %D != %D",i,j,n1,n2);
922         ierr = ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);CHKERRQ(ierr);
923         ierr = ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);CHKERRQ(ierr);
924         ierr = PetscMemcmp(idxs1,idxs2,n1*sizeof(PetscInt),&same);CHKERRQ(ierr);
925         ierr = ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);CHKERRQ(ierr);
926         ierr = ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);CHKERRQ(ierr);
927         if (!same) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid row l2gmap",i,j);
928       }
929     }
930   }
931   /* Check compatibility of l2g maps for columns */
932   for (i=0;i<nc;i++) {
933     rl2g = NULL;
934     for (j=0;j<nr;j++) {
935       PetscInt n1,n2;
936 
937       if (!nest[j][i]) continue;
938       if (istrans[j*nc+i]) {
939         Mat T;
940 
941         ierr = MatTransposeGetMat(nest[j][i],&T);CHKERRQ(ierr);
942         ierr = MatGetLocalToGlobalMapping(T,&cl2g,NULL);CHKERRQ(ierr);
943       } else {
944         ierr = MatGetLocalToGlobalMapping(nest[j][i],NULL,&cl2g);CHKERRQ(ierr);
945       }
946       ierr = ISLocalToGlobalMappingGetSize(cl2g,&n1);CHKERRQ(ierr);
947       if (!n1) continue;
948       if (!rl2g) {
949         rl2g = cl2g;
950       } else {
951         const PetscInt *idxs1,*idxs2;
952         PetscBool      same;
953 
954         ierr = ISLocalToGlobalMappingGetSize(rl2g,&n2);CHKERRQ(ierr);
955         if (n1 != n2) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid column l2gmap size %D != %D",j,i,n1,n2);
956         ierr = ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);CHKERRQ(ierr);
957         ierr = ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);CHKERRQ(ierr);
958         ierr = PetscMemcmp(idxs1,idxs2,n1*sizeof(PetscInt),&same);CHKERRQ(ierr);
959         ierr = ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);CHKERRQ(ierr);
960         ierr = ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);CHKERRQ(ierr);
961         if (!same) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid column l2gmap",j,i);
962       }
963     }
964   }
965 #endif
966 
967   B = NULL;
968   if (reuse != MAT_REUSE_MATRIX) {
969     PetscInt stl;
970 
971     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
972     for (i=0,stl=0;i<nr;i++) stl += lr[i];
973     ierr = PetscMalloc1(stl,&l2gidxs);CHKERRQ(ierr);
974     for (i=0,stl=0;i<nr;i++) {
975       Mat            usedmat;
976       Mat_IS         *matis;
977       const PetscInt *idxs;
978 
979       /* local IS for local NEST */
980       ierr  = ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);CHKERRQ(ierr);
981 
982       /* l2gmap */
983       j = 0;
984       usedmat = nest[i][j];
985       while (!usedmat && j < nc-1) usedmat = nest[i][++j];
986       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid row mat");
987 
988       if (istrans[i*nc+j]) {
989         Mat T;
990         ierr    = MatTransposeGetMat(usedmat,&T);CHKERRQ(ierr);
991         usedmat = T;
992       }
993       ierr  = MatISSetUpSF(usedmat);CHKERRQ(ierr);
994       matis = (Mat_IS*)(usedmat->data);
995       ierr  = ISGetIndices(isrow[i],&idxs);CHKERRQ(ierr);
996       if (istrans[i*nc+j]) {
997         ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
998         ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
999       } else {
1000         ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1001         ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1002       }
1003       ierr = ISRestoreIndices(isrow[i],&idxs);CHKERRQ(ierr);
1004       stl += lr[i];
1005     }
1006     ierr = ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&rl2g);CHKERRQ(ierr);
1007 
1008     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
1009     for (i=0,stl=0;i<nc;i++) stl += lc[i];
1010     ierr = PetscMalloc1(stl,&l2gidxs);CHKERRQ(ierr);
1011     for (i=0,stl=0;i<nc;i++) {
1012       Mat            usedmat;
1013       Mat_IS         *matis;
1014       const PetscInt *idxs;
1015 
1016       /* local IS for local NEST */
1017       ierr  = ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);CHKERRQ(ierr);
1018 
1019       /* l2gmap */
1020       j = 0;
1021       usedmat = nest[j][i];
1022       while (!usedmat && j < nr-1) usedmat = nest[++j][i];
1023       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid column mat");
1024       if (istrans[j*nc+i]) {
1025         Mat T;
1026         ierr    = MatTransposeGetMat(usedmat,&T);CHKERRQ(ierr);
1027         usedmat = T;
1028       }
1029       ierr  = MatISSetUpSF(usedmat);CHKERRQ(ierr);
1030       matis = (Mat_IS*)(usedmat->data);
1031       ierr  = ISGetIndices(iscol[i],&idxs);CHKERRQ(ierr);
1032       if (istrans[j*nc+i]) {
1033         ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1034         ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1035       } else {
1036         ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1037         ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
1038       }
1039       ierr = ISRestoreIndices(iscol[i],&idxs);CHKERRQ(ierr);
1040       stl += lc[i];
1041     }
1042     ierr = ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&cl2g);CHKERRQ(ierr);
1043 
1044     /* Create MATIS */
1045     ierr = MatCreate(comm,&B);CHKERRQ(ierr);
1046     ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
1047     ierr = MatGetBlockSizes(A,&rbs,&cbs);CHKERRQ(ierr);
1048     ierr = MatSetBlockSizes(B,rbs,cbs);CHKERRQ(ierr);
1049     ierr = MatSetType(B,MATIS);CHKERRQ(ierr);
1050     ierr = MatSetLocalToGlobalMapping(B,rl2g,cl2g);CHKERRQ(ierr);
1051     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
1052     ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
1053     ierr = MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);CHKERRQ(ierr);
1054     for (i=0;i<nr*nc;i++) {
1055       if (istrans[i]) {
1056         ierr = MatDestroy(&snest[i]);CHKERRQ(ierr);
1057       }
1058     }
1059     ierr = MatISSetLocalMat(B,lA);CHKERRQ(ierr);
1060     ierr = MatDestroy(&lA);CHKERRQ(ierr);
1061     ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1062     ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1063     if (reuse == MAT_INPLACE_MATRIX) {
1064       ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1065     } else {
1066       *newmat = B;
1067     }
1068   } else {
1069     if (lreuse) {
1070       ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
1071       for (i=0;i<nr;i++) {
1072         for (j=0;j<nc;j++) {
1073           if (snest[i*nc+j]) {
1074             ierr = MatNestSetSubMat(lA,i,j,snest[i*nc+j]);CHKERRQ(ierr);
1075             if (istrans[i*nc+j]) {
1076               ierr = MatDestroy(&snest[i*nc+j]);CHKERRQ(ierr);
1077             }
1078           }
1079         }
1080       }
1081     } else {
1082       PetscInt stl;
1083       for (i=0,stl=0;i<nr;i++) {
1084         ierr  = ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);CHKERRQ(ierr);
1085         stl  += lr[i];
1086       }
1087       for (i=0,stl=0;i<nc;i++) {
1088         ierr  = ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);CHKERRQ(ierr);
1089         stl  += lc[i];
1090       }
1091       ierr = MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);CHKERRQ(ierr);
1092       for (i=0;i<nr*nc;i++) {
1093         if (istrans[i]) {
1094           ierr = MatDestroy(&snest[i]);CHKERRQ(ierr);
1095         }
1096       }
1097       ierr = MatISSetLocalMat(*newmat,lA);CHKERRQ(ierr);
1098       ierr = MatDestroy(&lA);CHKERRQ(ierr);
1099     }
1100     ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1101     ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1102   }
1103 
1104   /* Create local matrix in MATNEST format */
1105   convert = PETSC_FALSE;
1106   ierr = PetscOptionsGetBool(NULL,((PetscObject)A)->prefix,"-matis_convert_local_nest",&convert,NULL);CHKERRQ(ierr);
1107   if (convert) {
1108     Mat              M;
1109     MatISLocalFields lf;
1110     PetscContainer   c;
1111 
1112     ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
1113     ierr = MatConvert(lA,MATAIJ,MAT_INITIAL_MATRIX,&M);CHKERRQ(ierr);
1114     ierr = MatISSetLocalMat(*newmat,M);CHKERRQ(ierr);
1115     ierr = MatDestroy(&M);CHKERRQ(ierr);
1116 
1117     /* attach local fields to the matrix */
1118     ierr = PetscNew(&lf);CHKERRQ(ierr);
1119     ierr = PetscCalloc2(nr,&lf->rf,nc,&lf->cf);CHKERRQ(ierr);
1120     for (i=0;i<nr;i++) {
1121       PetscInt n,st;
1122 
1123       ierr = ISGetLocalSize(islrow[i],&n);CHKERRQ(ierr);
1124       ierr = ISStrideGetInfo(islrow[i],&st,NULL);CHKERRQ(ierr);
1125       ierr = ISCreateStride(comm,n,st,1,&lf->rf[i]);CHKERRQ(ierr);
1126     }
1127     for (i=0;i<nc;i++) {
1128       PetscInt n,st;
1129 
1130       ierr = ISGetLocalSize(islcol[i],&n);CHKERRQ(ierr);
1131       ierr = ISStrideGetInfo(islcol[i],&st,NULL);CHKERRQ(ierr);
1132       ierr = ISCreateStride(comm,n,st,1,&lf->cf[i]);CHKERRQ(ierr);
1133     }
1134     lf->nr = nr;
1135     lf->nc = nc;
1136     ierr = PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)),&c);CHKERRQ(ierr);
1137     ierr = PetscContainerSetPointer(c,lf);CHKERRQ(ierr);
1138     ierr = PetscContainerSetUserDestroy(c,MatISContainerDestroyFields_Private);CHKERRQ(ierr);
1139     ierr = PetscObjectCompose((PetscObject)(*newmat),"_convert_nest_lfields",(PetscObject)c);CHKERRQ(ierr);
1140     ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
1141   }
1142 
1143   /* Free workspace */
1144   for (i=0;i<nr;i++) {
1145     ierr = ISDestroy(&islrow[i]);CHKERRQ(ierr);
1146   }
1147   for (i=0;i<nc;i++) {
1148     ierr = ISDestroy(&islcol[i]);CHKERRQ(ierr);
1149   }
1150   ierr = PetscFree6(isrow,iscol,islrow,islcol,snest,istrans);CHKERRQ(ierr);
1151   ierr = PetscFree2(lr,lc);CHKERRQ(ierr);
1152   PetscFunctionReturn(0);
1153 }
1154 
1155 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1156 {
1157   Mat_IS            *matis = (Mat_IS*)A->data;
1158   Vec               ll,rr;
1159   const PetscScalar *Y,*X;
1160   PetscScalar       *x,*y;
1161   PetscErrorCode    ierr;
1162 
1163   PetscFunctionBegin;
1164   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
1165   if (l) {
1166     ll   = matis->y;
1167     ierr = VecGetArrayRead(l,&Y);CHKERRQ(ierr);
1168     ierr = VecGetArray(ll,&y);CHKERRQ(ierr);
1169     ierr = PetscSFBcastBegin(matis->sf,MPIU_SCALAR,Y,y);CHKERRQ(ierr);
1170   } else {
1171     ll = NULL;
1172   }
1173   if (r) {
1174     rr   = matis->x;
1175     ierr = VecGetArrayRead(r,&X);CHKERRQ(ierr);
1176     ierr = VecGetArray(rr,&x);CHKERRQ(ierr);
1177     ierr = PetscSFBcastBegin(matis->csf,MPIU_SCALAR,X,x);CHKERRQ(ierr);
1178   } else {
1179     rr = NULL;
1180   }
1181   if (ll) {
1182     ierr = PetscSFBcastEnd(matis->sf,MPIU_SCALAR,Y,y);CHKERRQ(ierr);
1183     ierr = VecRestoreArrayRead(l,&Y);CHKERRQ(ierr);
1184     ierr = VecRestoreArray(ll,&y);CHKERRQ(ierr);
1185   }
1186   if (rr) {
1187     ierr = PetscSFBcastEnd(matis->csf,MPIU_SCALAR,X,x);CHKERRQ(ierr);
1188     ierr = VecRestoreArrayRead(r,&X);CHKERRQ(ierr);
1189     ierr = VecRestoreArray(rr,&x);CHKERRQ(ierr);
1190   }
1191   ierr = MatDiagonalScale(matis->A,ll,rr);CHKERRQ(ierr);
1192   PetscFunctionReturn(0);
1193 }
1194 
1195 static PetscErrorCode MatGetInfo_IS(Mat A,MatInfoType flag,MatInfo *ginfo)
1196 {
1197   Mat_IS         *matis = (Mat_IS*)A->data;
1198   MatInfo        info;
1199   PetscReal      isend[6],irecv[6];
1200   PetscInt       bs;
1201   PetscErrorCode ierr;
1202 
1203   PetscFunctionBegin;
1204   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1205   if (matis->A->ops->getinfo) {
1206     ierr     = MatGetInfo(matis->A,MAT_LOCAL,&info);CHKERRQ(ierr);
1207     isend[0] = info.nz_used;
1208     isend[1] = info.nz_allocated;
1209     isend[2] = info.nz_unneeded;
1210     isend[3] = info.memory;
1211     isend[4] = info.mallocs;
1212   } else {
1213     isend[0] = 0.;
1214     isend[1] = 0.;
1215     isend[2] = 0.;
1216     isend[3] = 0.;
1217     isend[4] = 0.;
1218   }
1219   isend[5] = matis->A->num_ass;
1220   if (flag == MAT_LOCAL) {
1221     ginfo->nz_used      = isend[0];
1222     ginfo->nz_allocated = isend[1];
1223     ginfo->nz_unneeded  = isend[2];
1224     ginfo->memory       = isend[3];
1225     ginfo->mallocs      = isend[4];
1226     ginfo->assemblies   = isend[5];
1227   } else if (flag == MAT_GLOBAL_MAX) {
1228     ierr = MPIU_Allreduce(isend,irecv,6,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1229 
1230     ginfo->nz_used      = irecv[0];
1231     ginfo->nz_allocated = irecv[1];
1232     ginfo->nz_unneeded  = irecv[2];
1233     ginfo->memory       = irecv[3];
1234     ginfo->mallocs      = irecv[4];
1235     ginfo->assemblies   = irecv[5];
1236   } else if (flag == MAT_GLOBAL_SUM) {
1237     ierr = MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1238 
1239     ginfo->nz_used      = irecv[0];
1240     ginfo->nz_allocated = irecv[1];
1241     ginfo->nz_unneeded  = irecv[2];
1242     ginfo->memory       = irecv[3];
1243     ginfo->mallocs      = irecv[4];
1244     ginfo->assemblies   = A->num_ass;
1245   }
1246   ginfo->block_size        = bs;
1247   ginfo->fill_ratio_given  = 0;
1248   ginfo->fill_ratio_needed = 0;
1249   ginfo->factor_mallocs    = 0;
1250   PetscFunctionReturn(0);
1251 }
1252 
1253 PetscErrorCode MatTranspose_IS(Mat A,MatReuse reuse,Mat *B)
1254 {
1255   Mat                    C,lC,lA;
1256   PetscErrorCode         ierr;
1257 
1258   PetscFunctionBegin;
1259   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1260     ISLocalToGlobalMapping rl2g,cl2g;
1261     ierr = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
1262     ierr = MatSetSizes(C,A->cmap->n,A->rmap->n,A->cmap->N,A->rmap->N);CHKERRQ(ierr);
1263     ierr = MatSetBlockSizes(C,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs));CHKERRQ(ierr);
1264     ierr = MatSetType(C,MATIS);CHKERRQ(ierr);
1265     ierr = MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);CHKERRQ(ierr);
1266     ierr = MatSetLocalToGlobalMapping(C,cl2g,rl2g);CHKERRQ(ierr);
1267   } else {
1268     C = *B;
1269   }
1270 
1271   /* perform local transposition */
1272   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
1273   ierr = MatTranspose(lA,MAT_INITIAL_MATRIX,&lC);CHKERRQ(ierr);
1274   ierr = MatISSetLocalMat(C,lC);CHKERRQ(ierr);
1275   ierr = MatDestroy(&lC);CHKERRQ(ierr);
1276 
1277   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1278     *B = C;
1279   } else {
1280     ierr = MatHeaderMerge(A,&C);CHKERRQ(ierr);
1281   }
1282   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1283   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1284   PetscFunctionReturn(0);
1285 }
1286 
1287 PetscErrorCode  MatDiagonalSet_IS(Mat A,Vec D,InsertMode insmode)
1288 {
1289   Mat_IS         *is = (Mat_IS*)A->data;
1290   PetscErrorCode ierr;
1291 
1292   PetscFunctionBegin;
1293   if (D) { /* MatShift_IS pass D = NULL */
1294     ierr = VecScatterBegin(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1295     ierr = VecScatterEnd(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1296   }
1297   ierr = VecPointwiseDivide(is->y,is->y,is->counter);CHKERRQ(ierr);
1298   ierr = MatDiagonalSet(is->A,is->y,insmode);CHKERRQ(ierr);
1299   PetscFunctionReturn(0);
1300 }
1301 
1302 PetscErrorCode  MatShift_IS(Mat A,PetscScalar a)
1303 {
1304   Mat_IS         *is = (Mat_IS*)A->data;
1305   PetscErrorCode ierr;
1306 
1307   PetscFunctionBegin;
1308   ierr = VecSet(is->y,a);CHKERRQ(ierr);
1309   ierr = MatDiagonalSet_IS(A,NULL,ADD_VALUES);CHKERRQ(ierr);
1310   PetscFunctionReturn(0);
1311 }
1312 
1313 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1314 {
1315   PetscErrorCode ierr;
1316   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1317 
1318   PetscFunctionBegin;
1319 #if defined(PETSC_USE_DEBUG)
1320   if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
1321 #endif
1322   ierr = ISLocalToGlobalMappingApply(A->rmap->mapping,m,rows,rows_l);CHKERRQ(ierr);
1323   ierr = ISLocalToGlobalMappingApply(A->cmap->mapping,n,cols,cols_l);CHKERRQ(ierr);
1324   ierr = MatSetValuesLocal_IS(A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
1325   PetscFunctionReturn(0);
1326 }
1327 
1328 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1329 {
1330   PetscErrorCode ierr;
1331   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1332 
1333   PetscFunctionBegin;
1334 #if defined(PETSC_USE_DEBUG)
1335   if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column block indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
1336 #endif
1337   ierr = ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,m,rows,rows_l);CHKERRQ(ierr);
1338   ierr = ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,n,cols,cols_l);CHKERRQ(ierr);
1339   ierr = MatSetValuesBlockedLocal_IS(A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
1340   PetscFunctionReturn(0);
1341 }
1342 
1343 static PetscErrorCode PetscLayoutMapLocal_Private(PetscLayout map,PetscInt N,const PetscInt idxs[], PetscInt *on,PetscInt **oidxs,PetscInt **ogidxs)
1344 {
1345   PetscInt      *owners = map->range;
1346   PetscInt       n      = map->n;
1347   PetscSF        sf;
1348   PetscInt      *lidxs,*work = NULL;
1349   PetscSFNode   *ridxs;
1350   PetscMPIInt    rank;
1351   PetscInt       r, p = 0, len = 0;
1352   PetscErrorCode ierr;
1353 
1354   PetscFunctionBegin;
1355   if (on) *on = 0;              /* squelch -Wmaybe-uninitialized */
1356   /* Create SF where leaves are input idxs and roots are owned idxs (code adapted from MatZeroRowsMapLocal_Private) */
1357   ierr = MPI_Comm_rank(map->comm,&rank);CHKERRQ(ierr);
1358   ierr = PetscMalloc1(n,&lidxs);CHKERRQ(ierr);
1359   for (r = 0; r < n; ++r) lidxs[r] = -1;
1360   ierr = PetscMalloc1(N,&ridxs);CHKERRQ(ierr);
1361   for (r = 0; r < N; ++r) {
1362     const PetscInt idx = idxs[r];
1363     if (idx < 0 || map->N <= idx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D out of range [0,%D)",idx,map->N);
1364     if (idx < owners[p] || owners[p+1] <= idx) { /* short-circuit the search if the last p owns this idx too */
1365       ierr = PetscLayoutFindOwner(map,idx,&p);CHKERRQ(ierr);
1366     }
1367     ridxs[r].rank = p;
1368     ridxs[r].index = idxs[r] - owners[p];
1369   }
1370   ierr = PetscSFCreate(map->comm,&sf);CHKERRQ(ierr);
1371   ierr = PetscSFSetGraph(sf,n,N,NULL,PETSC_OWN_POINTER,ridxs,PETSC_OWN_POINTER);CHKERRQ(ierr);
1372   ierr = PetscSFReduceBegin(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
1373   ierr = PetscSFReduceEnd(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
1374   if (ogidxs) { /* communicate global idxs */
1375     PetscInt cum = 0,start,*work2;
1376 
1377     ierr = PetscMalloc1(n,&work);CHKERRQ(ierr);
1378     ierr = PetscCalloc1(N,&work2);CHKERRQ(ierr);
1379     for (r = 0; r < N; ++r) if (idxs[r] >=0) cum++;
1380     ierr = MPI_Scan(&cum,&start,1,MPIU_INT,MPI_SUM,map->comm);CHKERRQ(ierr);
1381     start -= cum;
1382     cum = 0;
1383     for (r = 0; r < N; ++r) if (idxs[r] >=0) work2[r] = start+cum++;
1384     ierr = PetscSFReduceBegin(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
1385     ierr = PetscSFReduceEnd(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
1386     ierr = PetscFree(work2);CHKERRQ(ierr);
1387   }
1388   ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1389   /* Compress and put in indices */
1390   for (r = 0; r < n; ++r)
1391     if (lidxs[r] >= 0) {
1392       if (work) work[len] = work[r];
1393       lidxs[len++] = r;
1394     }
1395   if (on) *on = len;
1396   if (oidxs) *oidxs = lidxs;
1397   if (ogidxs) *ogidxs = work;
1398   PetscFunctionReturn(0);
1399 }
1400 
1401 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat,IS irow,IS icol,MatReuse scall,Mat *newmat)
1402 {
1403   Mat               locmat,newlocmat;
1404   Mat_IS            *newmatis;
1405 #if defined(PETSC_USE_DEBUG)
1406   Vec               rtest,ltest;
1407   const PetscScalar *array;
1408 #endif
1409   const PetscInt    *idxs;
1410   PetscInt          i,m,n;
1411   PetscErrorCode    ierr;
1412 
1413   PetscFunctionBegin;
1414   if (scall == MAT_REUSE_MATRIX) {
1415     PetscBool ismatis;
1416 
1417     ierr = PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);CHKERRQ(ierr);
1418     if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Not of MATIS type");
1419     newmatis = (Mat_IS*)(*newmat)->data;
1420     if (!newmatis->getsub_ris) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local row IS");
1421     if (!newmatis->getsub_cis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local col IS");
1422   }
1423   /* irow and icol may not have duplicate entries */
1424 #if defined(PETSC_USE_DEBUG)
1425   ierr = MatCreateVecs(mat,&ltest,&rtest);CHKERRQ(ierr);
1426   ierr = ISGetLocalSize(irow,&n);CHKERRQ(ierr);
1427   ierr = ISGetIndices(irow,&idxs);CHKERRQ(ierr);
1428   for (i=0;i<n;i++) {
1429     ierr = VecSetValue(rtest,idxs[i],1.0,ADD_VALUES);CHKERRQ(ierr);
1430   }
1431   ierr = VecAssemblyBegin(rtest);CHKERRQ(ierr);
1432   ierr = VecAssemblyEnd(rtest);CHKERRQ(ierr);
1433   ierr = VecGetLocalSize(rtest,&n);CHKERRQ(ierr);
1434   ierr = VecGetOwnershipRange(rtest,&m,NULL);CHKERRQ(ierr);
1435   ierr = VecGetArrayRead(rtest,&array);CHKERRQ(ierr);
1436   for (i=0;i<n;i++) if (array[i] != 0. && array[i] != 1.) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %D counted %D times! Irow may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i]));
1437   ierr = VecRestoreArrayRead(rtest,&array);CHKERRQ(ierr);
1438   ierr = ISRestoreIndices(irow,&idxs);CHKERRQ(ierr);
1439   ierr = ISGetLocalSize(icol,&n);CHKERRQ(ierr);
1440   ierr = ISGetIndices(icol,&idxs);CHKERRQ(ierr);
1441   for (i=0;i<n;i++) {
1442     ierr = VecSetValue(ltest,idxs[i],1.0,ADD_VALUES);CHKERRQ(ierr);
1443   }
1444   ierr = VecAssemblyBegin(ltest);CHKERRQ(ierr);
1445   ierr = VecAssemblyEnd(ltest);CHKERRQ(ierr);
1446   ierr = VecGetLocalSize(ltest,&n);CHKERRQ(ierr);
1447   ierr = VecGetOwnershipRange(ltest,&m,NULL);CHKERRQ(ierr);
1448   ierr = VecGetArrayRead(ltest,&array);CHKERRQ(ierr);
1449   for (i=0;i<n;i++) if (array[i] != 0. && array[i] != 1.) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %D counted %D times! Icol may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i]));
1450   ierr = VecRestoreArrayRead(ltest,&array);CHKERRQ(ierr);
1451   ierr = ISRestoreIndices(icol,&idxs);CHKERRQ(ierr);
1452   ierr = VecDestroy(&rtest);CHKERRQ(ierr);
1453   ierr = VecDestroy(&ltest);CHKERRQ(ierr);
1454 #endif
1455   if (scall == MAT_INITIAL_MATRIX) {
1456     Mat_IS                 *matis = (Mat_IS*)mat->data;
1457     ISLocalToGlobalMapping rl2g;
1458     IS                     is;
1459     PetscInt               *lidxs,*lgidxs,*newgidxs;
1460     PetscInt               ll,newloc,irbs,icbs,arbs,acbs,rbs,cbs;
1461     PetscBool              cong;
1462     MPI_Comm               comm;
1463 
1464     ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
1465     ierr = MatGetBlockSizes(mat,&arbs,&acbs);CHKERRQ(ierr);
1466     ierr = ISGetBlockSize(irow,&irbs);CHKERRQ(ierr);
1467     ierr = ISGetBlockSize(icol,&icbs);CHKERRQ(ierr);
1468     rbs  = arbs == irbs ? irbs : 1;
1469     cbs  = acbs == icbs ? icbs : 1;
1470     ierr = ISGetLocalSize(irow,&m);CHKERRQ(ierr);
1471     ierr = ISGetLocalSize(icol,&n);CHKERRQ(ierr);
1472     ierr = MatCreate(comm,newmat);CHKERRQ(ierr);
1473     ierr = MatSetType(*newmat,MATIS);CHKERRQ(ierr);
1474     ierr = MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
1475     ierr = MatSetBlockSizes(*newmat,rbs,cbs);CHKERRQ(ierr);
1476     /* communicate irow to their owners in the layout */
1477     ierr = ISGetIndices(irow,&idxs);CHKERRQ(ierr);
1478     ierr = PetscLayoutMapLocal_Private(mat->rmap,m,idxs,&ll,&lidxs,&lgidxs);CHKERRQ(ierr);
1479     ierr = ISRestoreIndices(irow,&idxs);CHKERRQ(ierr);
1480     ierr = MatISSetUpSF(mat);CHKERRQ(ierr);
1481     ierr = PetscMemzero(matis->sf_rootdata,matis->sf->nroots*sizeof(PetscInt));CHKERRQ(ierr);
1482     for (i=0;i<ll;i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i]+1;
1483     ierr = PetscFree(lidxs);CHKERRQ(ierr);
1484     ierr = PetscFree(lgidxs);CHKERRQ(ierr);
1485     ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1486     ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1487     for (i=0,newloc=0;i<matis->sf->nleaves;i++) if (matis->sf_leafdata[i]) newloc++;
1488     ierr = PetscMalloc1(newloc,&newgidxs);CHKERRQ(ierr);
1489     ierr = PetscMalloc1(newloc,&lidxs);CHKERRQ(ierr);
1490     for (i=0,newloc=0;i<matis->sf->nleaves;i++)
1491       if (matis->sf_leafdata[i]) {
1492         lidxs[newloc] = i;
1493         newgidxs[newloc++] = matis->sf_leafdata[i]-1;
1494       }
1495     ierr = ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
1496     ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
1497     ierr = ISLocalToGlobalMappingSetBlockSize(rl2g,rbs);CHKERRQ(ierr);
1498     ierr = ISDestroy(&is);CHKERRQ(ierr);
1499     /* local is to extract local submatrix */
1500     newmatis = (Mat_IS*)(*newmat)->data;
1501     ierr = ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_ris);CHKERRQ(ierr);
1502     ierr = MatHasCongruentLayouts(mat,&cong);CHKERRQ(ierr);
1503     if (cong && irow == icol && matis->csf == matis->sf) {
1504       ierr = MatSetLocalToGlobalMapping(*newmat,rl2g,rl2g);CHKERRQ(ierr);
1505       ierr = PetscObjectReference((PetscObject)newmatis->getsub_ris);CHKERRQ(ierr);
1506       newmatis->getsub_cis = newmatis->getsub_ris;
1507     } else {
1508       ISLocalToGlobalMapping cl2g;
1509 
1510       /* communicate icol to their owners in the layout */
1511       ierr = ISGetIndices(icol,&idxs);CHKERRQ(ierr);
1512       ierr = PetscLayoutMapLocal_Private(mat->cmap,n,idxs,&ll,&lidxs,&lgidxs);CHKERRQ(ierr);
1513       ierr = ISRestoreIndices(icol,&idxs);CHKERRQ(ierr);
1514       ierr = PetscMemzero(matis->csf_rootdata,matis->csf->nroots*sizeof(PetscInt));CHKERRQ(ierr);
1515       for (i=0;i<ll;i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i]+1;
1516       ierr = PetscFree(lidxs);CHKERRQ(ierr);
1517       ierr = PetscFree(lgidxs);CHKERRQ(ierr);
1518       ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);CHKERRQ(ierr);
1519       ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);CHKERRQ(ierr);
1520       for (i=0,newloc=0;i<matis->csf->nleaves;i++) if (matis->csf_leafdata[i]) newloc++;
1521       ierr = PetscMalloc1(newloc,&newgidxs);CHKERRQ(ierr);
1522       ierr = PetscMalloc1(newloc,&lidxs);CHKERRQ(ierr);
1523       for (i=0,newloc=0;i<matis->csf->nleaves;i++)
1524         if (matis->csf_leafdata[i]) {
1525           lidxs[newloc] = i;
1526           newgidxs[newloc++] = matis->csf_leafdata[i]-1;
1527         }
1528       ierr = ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
1529       ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
1530       ierr = ISLocalToGlobalMappingSetBlockSize(cl2g,cbs);CHKERRQ(ierr);
1531       ierr = ISDestroy(&is);CHKERRQ(ierr);
1532       /* local is to extract local submatrix */
1533       ierr = ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_cis);CHKERRQ(ierr);
1534       ierr = MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g);CHKERRQ(ierr);
1535       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
1536     }
1537     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
1538   } else {
1539     ierr = MatISGetLocalMat(*newmat,&newlocmat);CHKERRQ(ierr);
1540   }
1541   ierr = MatISGetLocalMat(mat,&locmat);CHKERRQ(ierr);
1542   newmatis = (Mat_IS*)(*newmat)->data;
1543   ierr = MatCreateSubMatrix(locmat,newmatis->getsub_ris,newmatis->getsub_cis,scall,&newlocmat);CHKERRQ(ierr);
1544   if (scall == MAT_INITIAL_MATRIX) {
1545     ierr = MatISSetLocalMat(*newmat,newlocmat);CHKERRQ(ierr);
1546     ierr = MatDestroy(&newlocmat);CHKERRQ(ierr);
1547   }
1548   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1549   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1550   PetscFunctionReturn(0);
1551 }
1552 
1553 static PetscErrorCode MatCopy_IS(Mat A,Mat B,MatStructure str)
1554 {
1555   Mat_IS         *a = (Mat_IS*)A->data,*b;
1556   PetscBool      ismatis;
1557   PetscErrorCode ierr;
1558 
1559   PetscFunctionBegin;
1560   ierr = PetscObjectTypeCompare((PetscObject)B,MATIS,&ismatis);CHKERRQ(ierr);
1561   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Need to be implemented");
1562   b = (Mat_IS*)B->data;
1563   ierr = MatCopy(a->A,b->A,str);CHKERRQ(ierr);
1564   ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr);
1565   PetscFunctionReturn(0);
1566 }
1567 
1568 static PetscErrorCode MatMissingDiagonal_IS(Mat A,PetscBool  *missing,PetscInt *d)
1569 {
1570   Vec               v;
1571   const PetscScalar *array;
1572   PetscInt          i,n;
1573   PetscErrorCode    ierr;
1574 
1575   PetscFunctionBegin;
1576   *missing = PETSC_FALSE;
1577   ierr = MatCreateVecs(A,NULL,&v);CHKERRQ(ierr);
1578   ierr = MatGetDiagonal(A,v);CHKERRQ(ierr);
1579   ierr = VecGetLocalSize(v,&n);CHKERRQ(ierr);
1580   ierr = VecGetArrayRead(v,&array);CHKERRQ(ierr);
1581   for (i=0;i<n;i++) if (array[i] == 0.) break;
1582   ierr = VecRestoreArrayRead(v,&array);CHKERRQ(ierr);
1583   ierr = VecDestroy(&v);CHKERRQ(ierr);
1584   if (i != n) *missing = PETSC_TRUE;
1585   if (d) {
1586     *d = -1;
1587     if (*missing) {
1588       PetscInt rstart;
1589       ierr = MatGetOwnershipRange(A,&rstart,NULL);CHKERRQ(ierr);
1590       *d = i+rstart;
1591     }
1592   }
1593   PetscFunctionReturn(0);
1594 }
1595 
1596 static PetscErrorCode MatISSetUpSF_IS(Mat B)
1597 {
1598   Mat_IS         *matis = (Mat_IS*)(B->data);
1599   const PetscInt *gidxs;
1600   PetscInt       nleaves;
1601   PetscErrorCode ierr;
1602 
1603   PetscFunctionBegin;
1604   if (matis->sf) PetscFunctionReturn(0);
1605   ierr = PetscLayoutSetUp(B->rmap);CHKERRQ(ierr);
1606   ierr = PetscLayoutSetUp(B->cmap);CHKERRQ(ierr);
1607   ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);CHKERRQ(ierr);
1608   ierr = ISLocalToGlobalMappingGetIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr);
1609   ierr = ISLocalToGlobalMappingGetSize(B->rmap->mapping,&nleaves);CHKERRQ(ierr);
1610   ierr = PetscSFSetGraphLayout(matis->sf,B->rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr);
1611   ierr = ISLocalToGlobalMappingRestoreIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr);
1612   ierr = PetscMalloc2(matis->sf->nroots,&matis->sf_rootdata,matis->sf->nleaves,&matis->sf_leafdata);CHKERRQ(ierr);
1613   if (B->rmap->mapping != B->cmap->mapping) { /* setup SF for columns */
1614     ierr = ISLocalToGlobalMappingGetSize(B->cmap->mapping,&nleaves);CHKERRQ(ierr);
1615     ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->csf);CHKERRQ(ierr);
1616     ierr = ISLocalToGlobalMappingGetIndices(B->cmap->mapping,&gidxs);CHKERRQ(ierr);
1617     ierr = PetscSFSetGraphLayout(matis->csf,B->cmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr);
1618     ierr = ISLocalToGlobalMappingRestoreIndices(B->cmap->mapping,&gidxs);CHKERRQ(ierr);
1619     ierr = PetscMalloc2(matis->csf->nroots,&matis->csf_rootdata,matis->csf->nleaves,&matis->csf_leafdata);CHKERRQ(ierr);
1620   } else {
1621     matis->csf = matis->sf;
1622     matis->csf_leafdata = matis->sf_leafdata;
1623     matis->csf_rootdata = matis->sf_rootdata;
1624   }
1625   PetscFunctionReturn(0);
1626 }
1627 
1628 /*@
1629    MatISStoreL2L - Store local-to-local operators during the Galerkin process of MatPtAP.
1630 
1631    Collective on MPI_Comm
1632 
1633    Input Parameters:
1634 +  A - the matrix
1635 -  store - the boolean flag
1636 
1637    Level: advanced
1638 
1639    Notes:
1640 
1641 .keywords: matrix
1642 
1643 .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatPtAP()
1644 @*/
1645 PetscErrorCode  MatISStoreL2L(Mat A, PetscBool store)
1646 {
1647   PetscErrorCode ierr;
1648 
1649   PetscFunctionBegin;
1650   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1651   PetscValidType(A,1);
1652   PetscValidLogicalCollectiveBool(A,store,2);
1653   ierr = PetscTryMethod(A,"MatISStoreL2L_C",(Mat,PetscBool),(A,store));CHKERRQ(ierr);
1654   PetscFunctionReturn(0);
1655 }
1656 
1657 static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1658 {
1659   Mat_IS         *matis = (Mat_IS*)(A->data);
1660   PetscErrorCode ierr;
1661 
1662   PetscFunctionBegin;
1663   matis->storel2l = store;
1664   if (!store) {
1665     ierr = PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",NULL);CHKERRQ(ierr);
1666   }
1667   PetscFunctionReturn(0);
1668 }
1669 
1670 /*@
1671    MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1672 
1673    Collective on MPI_Comm
1674 
1675    Input Parameters:
1676 +  A - the matrix
1677 -  fix - the boolean flag
1678 
1679    Level: advanced
1680 
1681    Notes: When fix is true, new local matrices and l2g maps are generated during the final assembly process.
1682 
1683 .keywords: matrix
1684 
1685 .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatAssemblyEnd(), MAT_FINAL_ASSEMBLY
1686 @*/
1687 PetscErrorCode  MatISFixLocalEmpty(Mat A, PetscBool fix)
1688 {
1689   PetscErrorCode ierr;
1690 
1691   PetscFunctionBegin;
1692   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1693   PetscValidType(A,1);
1694   PetscValidLogicalCollectiveBool(A,fix,2);
1695   ierr = PetscTryMethod(A,"MatISFixLocalEmpty_C",(Mat,PetscBool),(A,fix));CHKERRQ(ierr);
1696   PetscFunctionReturn(0);
1697 }
1698 
1699 static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1700 {
1701   Mat_IS *matis = (Mat_IS*)(A->data);
1702 
1703   PetscFunctionBegin;
1704   matis->locempty = fix;
1705   PetscFunctionReturn(0);
1706 }
1707 
1708 /*@
1709    MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.
1710 
1711    Collective on MPI_Comm
1712 
1713    Input Parameters:
1714 +  B - the matrix
1715 .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1716            (same value is used for all local rows)
1717 .  d_nnz - array containing the number of nonzeros in the various rows of the
1718            DIAGONAL portion of the local submatrix (possibly different for each row)
1719            or NULL, if d_nz is used to specify the nonzero structure.
1720            The size of this array is equal to the number of local rows, i.e 'm'.
1721            For matrices that will be factored, you must leave room for (and set)
1722            the diagonal entry even if it is zero.
1723 .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1724            submatrix (same value is used for all local rows).
1725 -  o_nnz - array containing the number of nonzeros in the various rows of the
1726            OFF-DIAGONAL portion of the local submatrix (possibly different for
1727            each row) or NULL, if o_nz is used to specify the nonzero
1728            structure. The size of this array is equal to the number
1729            of local rows, i.e 'm'.
1730 
1731    If the *_nnz parameter is given then the *_nz parameter is ignored
1732 
1733    Level: intermediate
1734 
1735    Notes:
1736     This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
1737           from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
1738           matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1739 
1740 .keywords: matrix
1741 
1742 .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat(), MATIS
1743 @*/
1744 PetscErrorCode  MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1745 {
1746   PetscErrorCode ierr;
1747 
1748   PetscFunctionBegin;
1749   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
1750   PetscValidType(B,1);
1751   ierr = PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));CHKERRQ(ierr);
1752   PetscFunctionReturn(0);
1753 }
1754 
1755 /* this is used by DMDA */
1756 PETSC_EXTERN PetscErrorCode  MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1757 {
1758   Mat_IS         *matis = (Mat_IS*)(B->data);
1759   PetscInt       bs,i,nlocalcols;
1760   PetscErrorCode ierr;
1761 
1762   PetscFunctionBegin;
1763   if (!matis->A) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping");
1764   ierr = MatISSetUpSF(B);CHKERRQ(ierr);
1765 
1766   if (!d_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nz;
1767   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nnz[i];
1768 
1769   if (!o_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nz;
1770   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nnz[i];
1771 
1772   ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1773   ierr = MatGetSize(matis->A,NULL,&nlocalcols);CHKERRQ(ierr);
1774   ierr = MatGetBlockSize(matis->A,&bs);CHKERRQ(ierr);
1775   ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1776 
1777   for (i=0;i<matis->sf->nleaves;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols);
1778   ierr = MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);CHKERRQ(ierr);
1779 #if defined(PETSC_HAVE_HYPRE)
1780   ierr = MatHYPRESetPreallocation(matis->A,0,matis->sf_leafdata,0,NULL);CHKERRQ(ierr);
1781 #endif
1782 
1783   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs;
1784   ierr = MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
1785 
1786   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i]-i;
1787   ierr = MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
1788 
1789   /* for other matrix types */
1790   ierr = MatSetUp(matis->A);CHKERRQ(ierr);
1791   PetscFunctionReturn(0);
1792 }
1793 
1794 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1795 {
1796   Mat_IS          *matis = (Mat_IS*)(A->data);
1797   PetscInt        *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership;
1798   const PetscInt  *global_indices_r,*global_indices_c;
1799   PetscInt        i,j,bs,rows,cols;
1800   PetscInt        lrows,lcols;
1801   PetscInt        local_rows,local_cols;
1802   PetscMPIInt     size;
1803   PetscBool       isdense,issbaij;
1804   PetscErrorCode  ierr;
1805 
1806   PetscFunctionBegin;
1807   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1808   ierr = MatGetSize(A,&rows,&cols);CHKERRQ(ierr);
1809   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1810   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
1811   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr);
1812   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
1813   ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr);
1814   if (A->rmap->mapping != A->cmap->mapping) {
1815     ierr = ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&global_indices_c);CHKERRQ(ierr);
1816   } else {
1817     global_indices_c = global_indices_r;
1818   }
1819 
1820   if (issbaij) {
1821     ierr = MatGetRowUpperTriangular(matis->A);CHKERRQ(ierr);
1822   }
1823   /*
1824      An SF reduce is needed to sum up properly on shared rows.
1825      Note that generally preallocation is not exact, since it overestimates nonzeros
1826   */
1827   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
1828   ierr = MatGetLocalSize(A,&lrows,&lcols);CHKERRQ(ierr);
1829   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);CHKERRQ(ierr);
1830   /* All processes need to compute entire row ownership */
1831   ierr = PetscMalloc1(rows,&row_ownership);CHKERRQ(ierr);
1832   ierr = MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr);
1833   for (i=0;i<size;i++) {
1834     for (j=mat_ranges[i];j<mat_ranges[i+1];j++) {
1835       row_ownership[j] = i;
1836     }
1837   }
1838   ierr = MatGetOwnershipRangesColumn(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr);
1839 
1840   /*
1841      my_dnz and my_onz contains exact contribution to preallocation from each local mat
1842      then, they will be summed up properly. This way, preallocation is always sufficient
1843   */
1844   ierr = PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);CHKERRQ(ierr);
1845   /* preallocation as a MATAIJ */
1846   if (isdense) { /* special case for dense local matrices */
1847     for (i=0;i<local_rows;i++) {
1848       PetscInt owner = row_ownership[global_indices_r[i]];
1849       for (j=0;j<local_cols;j++) {
1850         PetscInt index_col = global_indices_c[j];
1851         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1852           my_dnz[i] += 1;
1853         } else { /* offdiag block */
1854           my_onz[i] += 1;
1855         }
1856       }
1857     }
1858   } else if (matis->A->ops->getrowij) {
1859     const PetscInt *ii,*jj,*jptr;
1860     PetscBool      done;
1861     ierr = MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);CHKERRQ(ierr);
1862     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
1863     jptr = jj;
1864     for (i=0;i<local_rows;i++) {
1865       PetscInt index_row = global_indices_r[i];
1866       for (j=0;j<ii[i+1]-ii[i];j++,jptr++) {
1867         PetscInt owner = row_ownership[index_row];
1868         PetscInt index_col = global_indices_c[*jptr];
1869         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1870           my_dnz[i] += 1;
1871         } else { /* offdiag block */
1872           my_onz[i] += 1;
1873         }
1874         /* same as before, interchanging rows and cols */
1875         if (issbaij && index_col != index_row) {
1876           owner = row_ownership[index_col];
1877           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1878             my_dnz[*jptr] += 1;
1879           } else {
1880             my_onz[*jptr] += 1;
1881           }
1882         }
1883       }
1884     }
1885     ierr = MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);CHKERRQ(ierr);
1886     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
1887   } else { /* loop over rows and use MatGetRow */
1888     for (i=0;i<local_rows;i++) {
1889       const PetscInt *cols;
1890       PetscInt       ncols,index_row = global_indices_r[i];
1891       ierr = MatGetRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
1892       for (j=0;j<ncols;j++) {
1893         PetscInt owner = row_ownership[index_row];
1894         PetscInt index_col = global_indices_c[cols[j]];
1895         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1896           my_dnz[i] += 1;
1897         } else { /* offdiag block */
1898           my_onz[i] += 1;
1899         }
1900         /* same as before, interchanging rows and cols */
1901         if (issbaij && index_col != index_row) {
1902           owner = row_ownership[index_col];
1903           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1904             my_dnz[cols[j]] += 1;
1905           } else {
1906             my_onz[cols[j]] += 1;
1907           }
1908         }
1909       }
1910       ierr = MatRestoreRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
1911     }
1912   }
1913   if (global_indices_c != global_indices_r) {
1914     ierr = ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&global_indices_c);CHKERRQ(ierr);
1915   }
1916   ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr);
1917   ierr = PetscFree(row_ownership);CHKERRQ(ierr);
1918 
1919   /* Reduce my_dnz and my_onz */
1920   if (maxreduce) {
1921     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
1922     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
1923     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
1924     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
1925   } else {
1926     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
1927     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
1928     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
1929     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
1930   }
1931   ierr = PetscFree2(my_dnz,my_onz);CHKERRQ(ierr);
1932 
1933 
1934 
1935   /* Resize preallocation if overestimated */
1936   for (i=0;i<lrows;i++) {
1937     dnz[i] = PetscMin(dnz[i],lcols);
1938     onz[i] = PetscMin(onz[i],cols-lcols);
1939   }
1940 
1941   /* Set preallocation */
1942   ierr = MatSeqAIJSetPreallocation(B,0,dnz);CHKERRQ(ierr);
1943   ierr = MatMPIAIJSetPreallocation(B,0,dnz,0,onz);CHKERRQ(ierr);
1944   for (i=0;i<lrows;i+=bs) {
1945     PetscInt b, d = dnz[i],o = onz[i];
1946 
1947     for (b=1;b<bs;b++) {
1948       d = PetscMax(d,dnz[i+b]);
1949       o = PetscMax(o,onz[i+b]);
1950     }
1951     dnz[i/bs] = PetscMin(d/bs + d%bs,lcols/bs);
1952     onz[i/bs] = PetscMin(o/bs + o%bs,(cols-lcols)/bs);
1953   }
1954   ierr = MatSeqBAIJSetPreallocation(B,bs,0,dnz);CHKERRQ(ierr);
1955   ierr = MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
1956   ierr = MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
1957   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
1958   if (issbaij) {
1959     ierr = MatRestoreRowUpperTriangular(matis->A);CHKERRQ(ierr);
1960   }
1961   ierr = MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1962   PetscFunctionReturn(0);
1963 }
1964 
1965 PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1966 {
1967   Mat_IS         *matis = (Mat_IS*)(mat->data);
1968   Mat            local_mat,MT;
1969   /* info on mat */
1970   PetscInt       rbs,cbs,rows,cols,lrows,lcols;
1971   PetscInt       local_rows,local_cols;
1972   PetscBool      isseqdense,isseqsbaij,isseqaij,isseqbaij;
1973 #if defined (PETSC_USE_DEBUG)
1974   PetscBool      lb[4],bb[4];
1975 #endif
1976   PetscMPIInt    size;
1977   /* values insertion */
1978   PetscScalar    *array;
1979   /* work */
1980   PetscErrorCode ierr;
1981 
1982   PetscFunctionBegin;
1983   /* get info from mat */
1984   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)mat),&size);CHKERRQ(ierr);
1985   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
1986     Mat      B;
1987     IS       irows = NULL,icols = NULL;
1988     PetscInt rbs,cbs;
1989 
1990     ierr = ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);CHKERRQ(ierr);
1991     ierr = ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);CHKERRQ(ierr);
1992     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
1993       IS             rows,cols;
1994       const PetscInt *ridxs,*cidxs;
1995       PetscInt       i,nw,*work;
1996 
1997       ierr = ISLocalToGlobalMappingGetBlockIndices(mat->rmap->mapping,&ridxs);CHKERRQ(ierr);
1998       ierr = ISLocalToGlobalMappingGetSize(mat->rmap->mapping,&nw);CHKERRQ(ierr);
1999       nw   = nw/rbs;
2000       ierr = PetscCalloc1(nw,&work);CHKERRQ(ierr);
2001       for (i=0;i<nw;i++) work[ridxs[i]] += 1;
2002       for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
2003       if (i == nw) {
2004         ierr = ISCreateBlock(PETSC_COMM_SELF,rbs,nw,ridxs,PETSC_USE_POINTER,&rows);CHKERRQ(ierr);
2005         ierr = ISSetPermutation(rows);CHKERRQ(ierr);
2006         ierr = ISInvertPermutation(rows,PETSC_DECIDE,&irows);CHKERRQ(ierr);
2007         ierr = ISDestroy(&rows);CHKERRQ(ierr);
2008       }
2009       ierr = ISLocalToGlobalMappingRestoreBlockIndices(mat->rmap->mapping,&ridxs);CHKERRQ(ierr);
2010       ierr = PetscFree(work);CHKERRQ(ierr);
2011       if (irows && mat->rmap->mapping != mat->cmap->mapping) {
2012         ierr = ISLocalToGlobalMappingGetBlockIndices(mat->cmap->mapping,&cidxs);CHKERRQ(ierr);
2013         ierr = ISLocalToGlobalMappingGetSize(mat->cmap->mapping,&nw);CHKERRQ(ierr);
2014         nw   = nw/cbs;
2015         ierr = PetscCalloc1(nw,&work);CHKERRQ(ierr);
2016         for (i=0;i<nw;i++) work[cidxs[i]] += 1;
2017         for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
2018         if (i == nw) {
2019           ierr = ISCreateBlock(PETSC_COMM_SELF,cbs,nw,cidxs,PETSC_USE_POINTER,&cols);CHKERRQ(ierr);
2020           ierr = ISSetPermutation(cols);CHKERRQ(ierr);
2021           ierr = ISInvertPermutation(cols,PETSC_DECIDE,&icols);CHKERRQ(ierr);
2022           ierr = ISDestroy(&cols);CHKERRQ(ierr);
2023         }
2024         ierr = ISLocalToGlobalMappingRestoreBlockIndices(mat->cmap->mapping,&cidxs);CHKERRQ(ierr);
2025         ierr = PetscFree(work);CHKERRQ(ierr);
2026       } else if (irows) {
2027         ierr  = PetscObjectReference((PetscObject)irows);CHKERRQ(ierr);
2028         icols = irows;
2029       }
2030     } else {
2031       ierr = PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject*)&irows);CHKERRQ(ierr);
2032       ierr = PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject*)&icols);CHKERRQ(ierr);
2033       if (irows) { ierr = PetscObjectReference((PetscObject)irows);CHKERRQ(ierr); }
2034       if (icols) { ierr = PetscObjectReference((PetscObject)icols);CHKERRQ(ierr); }
2035     }
2036     if (!irows || !icols) {
2037       ierr = ISDestroy(&icols);CHKERRQ(ierr);
2038       ierr = ISDestroy(&irows);CHKERRQ(ierr);
2039       goto general_assembly;
2040     }
2041     ierr = MatConvert(matis->A,(rbs == cbs && rbs > 1) ? MATSEQBAIJ : MATSEQAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
2042     if (reuse != MAT_INPLACE_MATRIX) {
2043       ierr = MatCreateSubMatrix(B,irows,icols,reuse,M);CHKERRQ(ierr);
2044       ierr = PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject)irows);CHKERRQ(ierr);
2045       ierr = PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject)icols);CHKERRQ(ierr);
2046     } else {
2047       Mat C;
2048 
2049       ierr = MatCreateSubMatrix(B,irows,icols,MAT_INITIAL_MATRIX,&C);CHKERRQ(ierr);
2050       ierr = MatHeaderReplace(mat,&C);CHKERRQ(ierr);
2051     }
2052     ierr = MatDestroy(&B);CHKERRQ(ierr);
2053     ierr = ISDestroy(&icols);CHKERRQ(ierr);
2054     ierr = ISDestroy(&irows);CHKERRQ(ierr);
2055     PetscFunctionReturn(0);
2056   }
2057 general_assembly:
2058   ierr = MatGetSize(mat,&rows,&cols);CHKERRQ(ierr);
2059   ierr = ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);CHKERRQ(ierr);
2060   ierr = ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);CHKERRQ(ierr);
2061   ierr = MatGetLocalSize(mat,&lrows,&lcols);CHKERRQ(ierr);
2062   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
2063   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isseqdense);CHKERRQ(ierr);
2064   ierr = PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
2065   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQBAIJ,&isseqbaij);CHKERRQ(ierr);
2066   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&isseqsbaij);CHKERRQ(ierr);
2067   if (!isseqdense && !isseqaij && !isseqbaij && !isseqsbaij) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(matis->A))->type_name);
2068 #if defined (PETSC_USE_DEBUG)
2069   lb[0] = isseqdense;
2070   lb[1] = isseqaij;
2071   lb[2] = isseqbaij;
2072   lb[3] = isseqsbaij;
2073   ierr = MPIU_Allreduce(lb,bb,4,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr);
2074   if (!bb[0] && !bb[1] && !bb[2] && !bb[3]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Local matrices must have the same type");
2075 #endif
2076 
2077   if (reuse != MAT_REUSE_MATRIX) {
2078     ierr = MatCreate(PetscObjectComm((PetscObject)mat),&MT);CHKERRQ(ierr);
2079     ierr = MatSetSizes(MT,lrows,lcols,rows,cols);CHKERRQ(ierr);
2080     ierr = MatSetType(MT,mtype);CHKERRQ(ierr);
2081     ierr = MatSetBlockSizes(MT,rbs,cbs);CHKERRQ(ierr);
2082     ierr = MatISSetMPIXAIJPreallocation_Private(mat,MT,PETSC_FALSE);CHKERRQ(ierr);
2083   } else {
2084     PetscInt mrbs,mcbs,mrows,mcols,mlrows,mlcols;
2085 
2086     /* some checks */
2087     MT   = *M;
2088     ierr = MatGetBlockSizes(MT,&mrbs,&mcbs);CHKERRQ(ierr);
2089     ierr = MatGetSize(MT,&mrows,&mcols);CHKERRQ(ierr);
2090     ierr = MatGetLocalSize(MT,&mlrows,&mlcols);CHKERRQ(ierr);
2091     if (mrows != rows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows);
2092     if (mcols != cols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols);
2093     if (mlrows != lrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows);
2094     if (mlcols != lcols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols);
2095     if (mrbs != rbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong row block size (%d != %d)",rbs,mrbs);
2096     if (mcbs != cbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong col block size (%d != %d)",cbs,mcbs);
2097     ierr = MatZeroEntries(MT);CHKERRQ(ierr);
2098   }
2099 
2100   if (isseqsbaij) {
2101     ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&local_mat);CHKERRQ(ierr);
2102   } else {
2103     ierr = PetscObjectReference((PetscObject)matis->A);CHKERRQ(ierr);
2104     local_mat = matis->A;
2105   }
2106 
2107   /* Set values */
2108   ierr = MatSetLocalToGlobalMapping(MT,mat->rmap->mapping,mat->cmap->mapping);CHKERRQ(ierr);
2109   if (isseqdense) { /* special case for dense local matrices */
2110     PetscInt i,*dummy;
2111 
2112     ierr = PetscMalloc1(PetscMax(local_rows,local_cols),&dummy);CHKERRQ(ierr);
2113     for (i=0;i<PetscMax(local_rows,local_cols);i++) dummy[i] = i;
2114     ierr = MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
2115     ierr = MatDenseGetArray(local_mat,&array);CHKERRQ(ierr);
2116     ierr = MatSetValuesLocal(MT,local_rows,dummy,local_cols,dummy,array,ADD_VALUES);CHKERRQ(ierr);
2117     ierr = MatDenseRestoreArray(local_mat,&array);CHKERRQ(ierr);
2118     ierr = PetscFree(dummy);CHKERRQ(ierr);
2119   } else if (isseqaij) {
2120     PetscInt  i,nvtxs,*xadj,*adjncy;
2121     PetscBool done;
2122 
2123     ierr = MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
2124     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
2125     ierr = MatSeqAIJGetArray(local_mat,&array);CHKERRQ(ierr);
2126     for (i=0;i<nvtxs;i++) {
2127       ierr = MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],array+xadj[i],ADD_VALUES);CHKERRQ(ierr);
2128     }
2129     ierr = MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
2130     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
2131     ierr = MatSeqAIJRestoreArray(local_mat,&array);CHKERRQ(ierr);
2132   } else { /* very basic values insertion for all other matrix types */
2133     PetscInt i;
2134 
2135     for (i=0;i<local_rows;i++) {
2136       PetscInt       j;
2137       const PetscInt *local_indices_cols;
2138 
2139       ierr = MatGetRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr);
2140       ierr = MatSetValuesLocal(MT,1,&i,j,local_indices_cols,array,ADD_VALUES);CHKERRQ(ierr);
2141       ierr = MatRestoreRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr);
2142     }
2143   }
2144   ierr = MatAssemblyBegin(MT,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2145   ierr = MatDestroy(&local_mat);CHKERRQ(ierr);
2146   ierr = MatAssemblyEnd(MT,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2147   if (isseqdense) {
2148     ierr = MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_TRUE);CHKERRQ(ierr);
2149   }
2150   if (reuse == MAT_INPLACE_MATRIX) {
2151     ierr = MatHeaderReplace(mat,&MT);CHKERRQ(ierr);
2152   } else if (reuse == MAT_INITIAL_MATRIX) {
2153     *M = MT;
2154   }
2155   PetscFunctionReturn(0);
2156 }
2157 
2158 /*@
2159     MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format
2160 
2161   Input Parameter:
2162 .  mat - the matrix (should be of type MATIS)
2163 .  reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
2164 
2165   Output Parameter:
2166 .  newmat - the matrix in AIJ format
2167 
2168   Level: developer
2169 
2170   Notes:
2171     This function has been deprecated and it will be removed in future releases. Update your code to use the MatConvert() interface.
2172 
2173 .seealso: MATIS, MatConvert()
2174 @*/
2175 PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
2176 {
2177   PetscErrorCode ierr;
2178 
2179   PetscFunctionBegin;
2180   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2181   PetscValidLogicalCollectiveEnum(mat,reuse,2);
2182   PetscValidPointer(newmat,3);
2183   if (reuse == MAT_REUSE_MATRIX) {
2184     PetscValidHeaderSpecific(*newmat,MAT_CLASSID,3);
2185     PetscCheckSameComm(mat,1,*newmat,3);
2186     if (mat == *newmat) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix");
2187   }
2188   ierr = PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatType,MatReuse,Mat*),(mat,MATAIJ,reuse,newmat));CHKERRQ(ierr);
2189   PetscFunctionReturn(0);
2190 }
2191 
2192 PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat)
2193 {
2194   PetscErrorCode ierr;
2195   Mat_IS         *matis = (Mat_IS*)(mat->data);
2196   PetscInt       rbs,cbs,m,n,M,N;
2197   Mat            B,localmat;
2198 
2199   PetscFunctionBegin;
2200   ierr = ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);CHKERRQ(ierr);
2201   ierr = ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);CHKERRQ(ierr);
2202   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
2203   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
2204   ierr = MatCreateIS(PetscObjectComm((PetscObject)mat),rbs == cbs ? rbs : 1,m,n,M,N,mat->rmap->mapping,mat->cmap->mapping,&B);CHKERRQ(ierr);
2205   ierr = MatDuplicate(matis->A,op,&localmat);CHKERRQ(ierr);
2206   ierr = MatISSetLocalMat(B,localmat);CHKERRQ(ierr);
2207   ierr = MatDestroy(&localmat);CHKERRQ(ierr);
2208   if (matis->sf) {
2209     Mat_IS *bmatis = (Mat_IS*)(B->data);
2210 
2211     ierr       = PetscObjectReference((PetscObject)matis->sf);CHKERRQ(ierr);
2212     bmatis->sf = matis->sf;
2213     ierr       = PetscMalloc2(matis->sf->nroots,&bmatis->sf_rootdata,matis->sf->nleaves,&bmatis->sf_leafdata);CHKERRQ(ierr);
2214     if (matis->sf != matis->csf) {
2215       ierr        = PetscObjectReference((PetscObject)matis->csf);CHKERRQ(ierr);
2216       bmatis->csf = matis->csf;
2217       ierr        = PetscMalloc2(matis->csf->nroots,&bmatis->csf_rootdata,matis->csf->nleaves,&bmatis->csf_leafdata);CHKERRQ(ierr);
2218     } else {
2219       bmatis->csf          = bmatis->sf;
2220       bmatis->csf_leafdata = bmatis->sf_leafdata;
2221       bmatis->csf_rootdata = bmatis->sf_rootdata;
2222     }
2223   }
2224   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2225   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2226   *newmat = B;
2227   PetscFunctionReturn(0);
2228 }
2229 
2230 static PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool  *flg)
2231 {
2232   PetscErrorCode ierr;
2233   Mat_IS         *matis = (Mat_IS*)A->data;
2234   PetscBool      local_sym;
2235 
2236   PetscFunctionBegin;
2237   ierr = MatIsHermitian(matis->A,tol,&local_sym);CHKERRQ(ierr);
2238   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2239   PetscFunctionReturn(0);
2240 }
2241 
2242 static PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool  *flg)
2243 {
2244   PetscErrorCode ierr;
2245   Mat_IS         *matis = (Mat_IS*)A->data;
2246   PetscBool      local_sym;
2247 
2248   PetscFunctionBegin;
2249   ierr = MatIsSymmetric(matis->A,tol,&local_sym);CHKERRQ(ierr);
2250   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2251   PetscFunctionReturn(0);
2252 }
2253 
2254 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A,PetscBool  *flg)
2255 {
2256   PetscErrorCode ierr;
2257   Mat_IS         *matis = (Mat_IS*)A->data;
2258   PetscBool      local_sym;
2259 
2260   PetscFunctionBegin;
2261   if (A->rmap->mapping != A->cmap->mapping) {
2262     *flg = PETSC_FALSE;
2263     PetscFunctionReturn(0);
2264   }
2265   ierr = MatIsStructurallySymmetric(matis->A,&local_sym);CHKERRQ(ierr);
2266   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2267   PetscFunctionReturn(0);
2268 }
2269 
2270 static PetscErrorCode MatDestroy_IS(Mat A)
2271 {
2272   PetscErrorCode ierr;
2273   Mat_IS         *b = (Mat_IS*)A->data;
2274 
2275   PetscFunctionBegin;
2276   ierr = MatDestroy(&b->A);CHKERRQ(ierr);
2277   ierr = VecScatterDestroy(&b->cctx);CHKERRQ(ierr);
2278   ierr = VecScatterDestroy(&b->rctx);CHKERRQ(ierr);
2279   ierr = VecDestroy(&b->x);CHKERRQ(ierr);
2280   ierr = VecDestroy(&b->y);CHKERRQ(ierr);
2281   ierr = VecDestroy(&b->counter);CHKERRQ(ierr);
2282   ierr = ISDestroy(&b->getsub_ris);CHKERRQ(ierr);
2283   ierr = ISDestroy(&b->getsub_cis);CHKERRQ(ierr);
2284   if (b->sf != b->csf) {
2285     ierr = PetscSFDestroy(&b->csf);CHKERRQ(ierr);
2286     ierr = PetscFree2(b->csf_rootdata,b->csf_leafdata);CHKERRQ(ierr);
2287   } else b->csf = NULL;
2288   ierr = PetscSFDestroy(&b->sf);CHKERRQ(ierr);
2289   ierr = PetscFree2(b->sf_rootdata,b->sf_leafdata);CHKERRQ(ierr);
2290   ierr = PetscFree(A->data);CHKERRQ(ierr);
2291   ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr);
2292   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);CHKERRQ(ierr);
2293   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);CHKERRQ(ierr);
2294   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);CHKERRQ(ierr);
2295   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);CHKERRQ(ierr);
2296   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetUpSF_C",NULL);CHKERRQ(ierr);
2297   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",NULL);CHKERRQ(ierr);
2298   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",NULL);CHKERRQ(ierr);
2299   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",NULL);CHKERRQ(ierr);
2300   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",NULL);CHKERRQ(ierr);
2301   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",NULL);CHKERRQ(ierr);
2302   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",NULL);CHKERRQ(ierr);
2303   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",NULL);CHKERRQ(ierr);
2304   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",NULL);CHKERRQ(ierr);
2305   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",NULL);CHKERRQ(ierr);
2306   PetscFunctionReturn(0);
2307 }
2308 
2309 static PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
2310 {
2311   PetscErrorCode ierr;
2312   Mat_IS         *is  = (Mat_IS*)A->data;
2313   PetscScalar    zero = 0.0;
2314 
2315   PetscFunctionBegin;
2316   /*  scatter the global vector x into the local work vector */
2317   ierr = VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2318   ierr = VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2319 
2320   /* multiply the local matrix */
2321   ierr = MatMult(is->A,is->x,is->y);CHKERRQ(ierr);
2322 
2323   /* scatter product back into global memory */
2324   ierr = VecSet(y,zero);CHKERRQ(ierr);
2325   ierr = VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2326   ierr = VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2327   PetscFunctionReturn(0);
2328 }
2329 
2330 static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2331 {
2332   Vec            temp_vec;
2333   PetscErrorCode ierr;
2334 
2335   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2336   if (v3 != v2) {
2337     ierr = MatMult(A,v1,v3);CHKERRQ(ierr);
2338     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
2339   } else {
2340     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
2341     ierr = MatMult(A,v1,temp_vec);CHKERRQ(ierr);
2342     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
2343     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
2344     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
2345   }
2346   PetscFunctionReturn(0);
2347 }
2348 
2349 static PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x)
2350 {
2351   Mat_IS         *is = (Mat_IS*)A->data;
2352   PetscErrorCode ierr;
2353 
2354   PetscFunctionBegin;
2355   /*  scatter the global vector x into the local work vector */
2356   ierr = VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2357   ierr = VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2358 
2359   /* multiply the local matrix */
2360   ierr = MatMultTranspose(is->A,is->y,is->x);CHKERRQ(ierr);
2361 
2362   /* scatter product back into global vector */
2363   ierr = VecSet(x,0);CHKERRQ(ierr);
2364   ierr = VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2365   ierr = VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2366   PetscFunctionReturn(0);
2367 }
2368 
2369 static PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2370 {
2371   Vec            temp_vec;
2372   PetscErrorCode ierr;
2373 
2374   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2375   if (v3 != v2) {
2376     ierr = MatMultTranspose(A,v1,v3);CHKERRQ(ierr);
2377     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
2378   } else {
2379     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
2380     ierr = MatMultTranspose(A,v1,temp_vec);CHKERRQ(ierr);
2381     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
2382     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
2383     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
2384   }
2385   PetscFunctionReturn(0);
2386 }
2387 
2388 static PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
2389 {
2390   Mat_IS         *a = (Mat_IS*)A->data;
2391   PetscErrorCode ierr;
2392   PetscViewer    sviewer;
2393   PetscBool      isascii,view = PETSC_TRUE;
2394 
2395   PetscFunctionBegin;
2396   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
2397   if (isascii)  {
2398     PetscViewerFormat format;
2399 
2400     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
2401     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2402   }
2403   if (!view) PetscFunctionReturn(0);
2404   ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
2405   ierr = MatView(a->A,sviewer);CHKERRQ(ierr);
2406   ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
2407   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
2408   PetscFunctionReturn(0);
2409 }
2410 
2411 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
2412 {
2413   PetscErrorCode ierr;
2414   PetscInt       nr,rbs,nc,cbs;
2415   Mat_IS         *is = (Mat_IS*)A->data;
2416   Vec            cglobal,rglobal;
2417 
2418   PetscFunctionBegin;
2419   PetscCheckSameComm(A,1,rmapping,2);
2420   PetscCheckSameComm(A,1,cmapping,3);
2421   /* Destroy any previous data */
2422   ierr = VecDestroy(&is->x);CHKERRQ(ierr);
2423   ierr = VecDestroy(&is->y);CHKERRQ(ierr);
2424   ierr = VecDestroy(&is->counter);CHKERRQ(ierr);
2425   ierr = VecScatterDestroy(&is->rctx);CHKERRQ(ierr);
2426   ierr = VecScatterDestroy(&is->cctx);CHKERRQ(ierr);
2427   ierr = MatDestroy(&is->A);CHKERRQ(ierr);
2428   if (is->csf != is->sf) {
2429     ierr = PetscSFDestroy(&is->csf);CHKERRQ(ierr);
2430     ierr = PetscFree2(is->csf_rootdata,is->csf_leafdata);CHKERRQ(ierr);
2431   } else is->csf = NULL;
2432   ierr = PetscSFDestroy(&is->sf);CHKERRQ(ierr);
2433   ierr = PetscFree2(is->sf_rootdata,is->sf_leafdata);CHKERRQ(ierr);
2434 
2435   /* Setup Layout and set local to global maps */
2436   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
2437   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
2438   ierr = ISLocalToGlobalMappingGetSize(rmapping,&nr);CHKERRQ(ierr);
2439   ierr = ISLocalToGlobalMappingGetBlockSize(rmapping,&rbs);CHKERRQ(ierr);
2440   ierr = ISLocalToGlobalMappingGetSize(cmapping,&nc);CHKERRQ(ierr);
2441   ierr = ISLocalToGlobalMappingGetBlockSize(cmapping,&cbs);CHKERRQ(ierr);
2442   /* check if the two mappings are actually the same for square matrices (DOLFIN passes 2 different objects) */
2443   if (rmapping != cmapping && A->rmap->N == A->cmap->N) {
2444     PetscBool same,gsame;
2445 
2446     same = PETSC_FALSE;
2447     if (nr == nc && cbs == rbs) {
2448       const PetscInt *idxs1,*idxs2;
2449 
2450       ierr = ISLocalToGlobalMappingGetBlockIndices(rmapping,&idxs1);CHKERRQ(ierr);
2451       ierr = ISLocalToGlobalMappingGetBlockIndices(cmapping,&idxs2);CHKERRQ(ierr);
2452       ierr = PetscMemcmp(idxs1,idxs2,(nr/rbs)*sizeof(PetscInt),&same);CHKERRQ(ierr);
2453       ierr = ISLocalToGlobalMappingRestoreBlockIndices(rmapping,&idxs1);CHKERRQ(ierr);
2454       ierr = ISLocalToGlobalMappingRestoreBlockIndices(cmapping,&idxs2);CHKERRQ(ierr);
2455     }
2456     ierr = MPIU_Allreduce(&same,&gsame,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2457     if (gsame) cmapping = rmapping;
2458   }
2459   ierr = PetscLayoutSetBlockSize(A->rmap,rbs);CHKERRQ(ierr);
2460   ierr = PetscLayoutSetBlockSize(A->cmap,cbs);CHKERRQ(ierr);
2461   ierr = PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);CHKERRQ(ierr);
2462   ierr = PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);CHKERRQ(ierr);
2463 
2464   /* Create the local matrix A */
2465   ierr = MatCreate(PETSC_COMM_SELF,&is->A);CHKERRQ(ierr);
2466   ierr = MatSetType(is->A,MATAIJ);CHKERRQ(ierr);
2467   ierr = MatSetSizes(is->A,nr,nc,nr,nc);CHKERRQ(ierr);
2468   ierr = MatSetBlockSizes(is->A,rbs,cbs);CHKERRQ(ierr);
2469   ierr = MatSetOptionsPrefix(is->A,((PetscObject)A)->prefix);CHKERRQ(ierr);
2470   ierr = MatAppendOptionsPrefix(is->A,"is_");CHKERRQ(ierr);
2471   ierr = MatSetFromOptions(is->A);CHKERRQ(ierr);
2472   ierr = PetscLayoutSetUp(is->A->rmap);CHKERRQ(ierr);
2473   ierr = PetscLayoutSetUp(is->A->cmap);CHKERRQ(ierr);
2474 
2475   if (!is->islocalref) { /* setup scatters and local vectors for MatMult */
2476     IS             from;
2477     const PetscInt *garray;
2478 
2479     /* Create the local work vectors */
2480     ierr = MatCreateVecs(is->A,&is->x,&is->y);CHKERRQ(ierr);
2481 
2482     /* setup the global to local scatters */
2483     ierr = MatCreateVecs(A,&cglobal,&rglobal);CHKERRQ(ierr);
2484     ierr = ISLocalToGlobalMappingGetBlockIndices(rmapping,&garray);CHKERRQ(ierr);
2485     ierr = ISCreateBlock(PetscObjectComm((PetscObject)A),rbs,nr/rbs,garray,PETSC_USE_POINTER,&from);CHKERRQ(ierr);
2486     ierr = VecScatterCreate(rglobal,from,is->y,NULL,&is->rctx);CHKERRQ(ierr);
2487     ierr = ISLocalToGlobalMappingRestoreBlockIndices(rmapping,&garray);CHKERRQ(ierr);
2488     ierr = ISDestroy(&from);CHKERRQ(ierr);
2489     if (rmapping != cmapping) {
2490       ierr = ISLocalToGlobalMappingGetBlockIndices(cmapping,&garray);CHKERRQ(ierr);
2491       ierr = ISCreateBlock(PetscObjectComm((PetscObject)A),cbs,nc/cbs,garray,PETSC_USE_POINTER,&from);CHKERRQ(ierr);
2492       ierr = VecScatterCreate(cglobal,from,is->x,NULL,&is->cctx);CHKERRQ(ierr);
2493       ierr = ISLocalToGlobalMappingRestoreBlockIndices(cmapping,&garray);CHKERRQ(ierr);
2494       ierr = ISDestroy(&from);CHKERRQ(ierr);
2495     } else {
2496       ierr = PetscObjectReference((PetscObject)is->rctx);CHKERRQ(ierr);
2497       is->cctx = is->rctx;
2498     }
2499 
2500     /* interface counter vector (local) */
2501     ierr = VecDuplicate(is->y,&is->counter);CHKERRQ(ierr);
2502     ierr = VecSet(is->y,1.);CHKERRQ(ierr);
2503     ierr = VecScatterBegin(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2504     ierr = VecScatterEnd(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2505     ierr = VecScatterBegin(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2506     ierr = VecScatterEnd(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2507 
2508     /* free workspace */
2509     ierr = VecDestroy(&rglobal);CHKERRQ(ierr);
2510     ierr = VecDestroy(&cglobal);CHKERRQ(ierr);
2511     ierr = ISDestroy(&from);CHKERRQ(ierr);
2512   }
2513   ierr = MatSetUp(A);CHKERRQ(ierr);
2514   PetscFunctionReturn(0);
2515 }
2516 
2517 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2518 {
2519   Mat_IS         *is = (Mat_IS*)mat->data;
2520   PetscErrorCode ierr;
2521 #if defined(PETSC_USE_DEBUG)
2522   PetscInt       i,zm,zn;
2523 #endif
2524   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
2525 
2526   PetscFunctionBegin;
2527 #if defined(PETSC_USE_DEBUG)
2528   if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
2529   /* count negative indices */
2530   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2531   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2532 #endif
2533   ierr = ISGlobalToLocalMappingApply(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);CHKERRQ(ierr);
2534   ierr = ISGlobalToLocalMappingApply(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);CHKERRQ(ierr);
2535 #if defined(PETSC_USE_DEBUG)
2536   /* count negative indices (should be the same as before) */
2537   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2538   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2539   if (!is->A->rmap->mapping && zm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the row indices can not be mapped! Maybe you should not use MATIS");
2540   if (!is->A->cmap->mapping && zn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the column indices can not be mapped! Maybe you should not use MATIS");
2541 #endif
2542   ierr = MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
2543   PetscFunctionReturn(0);
2544 }
2545 
2546 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2547 {
2548   Mat_IS         *is = (Mat_IS*)mat->data;
2549   PetscErrorCode ierr;
2550 #if defined(PETSC_USE_DEBUG)
2551   PetscInt       i,zm,zn;
2552 #endif
2553   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
2554 
2555   PetscFunctionBegin;
2556 #if defined(PETSC_USE_DEBUG)
2557   if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column block indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
2558   /* count negative indices */
2559   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2560   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2561 #endif
2562   ierr = ISGlobalToLocalMappingApplyBlock(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);CHKERRQ(ierr);
2563   ierr = ISGlobalToLocalMappingApplyBlock(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);CHKERRQ(ierr);
2564 #if defined(PETSC_USE_DEBUG)
2565   /* count negative indices (should be the same as before) */
2566   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2567   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2568   if (!is->A->rmap->mapping && zm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the row indices can not be mapped! Maybe you should not use MATIS");
2569   if (!is->A->cmap->mapping && zn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the column indices can not be mapped! Maybe you should not use MATIS");
2570 #endif
2571   ierr = MatSetValuesBlocked(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
2572   PetscFunctionReturn(0);
2573 }
2574 
2575 static PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2576 {
2577   PetscErrorCode ierr;
2578   Mat_IS         *is = (Mat_IS*)A->data;
2579 
2580   PetscFunctionBegin;
2581   if (is->A->rmap->mapping) {
2582     ierr = MatSetValuesLocal(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
2583   } else {
2584     ierr = MatSetValues(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
2585   }
2586   PetscFunctionReturn(0);
2587 }
2588 
2589 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2590 {
2591   PetscErrorCode ierr;
2592   Mat_IS         *is = (Mat_IS*)A->data;
2593 
2594   PetscFunctionBegin;
2595   if (is->A->rmap->mapping) {
2596 #if defined(PETSC_USE_DEBUG)
2597     PetscInt ibs,bs;
2598 
2599     ierr = ISLocalToGlobalMappingGetBlockSize(is->A->rmap->mapping,&ibs);CHKERRQ(ierr);
2600     ierr = MatGetBlockSize(is->A,&bs);CHKERRQ(ierr);
2601     if (ibs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Different block sizes! local mat %D, local l2g map %D",bs,ibs);
2602 #endif
2603     ierr = MatSetValuesBlockedLocal(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
2604   } else {
2605     ierr = MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
2606   }
2607   PetscFunctionReturn(0);
2608 }
2609 
2610 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,PetscBool columns)
2611 {
2612   Mat_IS         *is = (Mat_IS*)A->data;
2613   PetscErrorCode ierr;
2614 
2615   PetscFunctionBegin;
2616   if (!n) {
2617     is->pure_neumann = PETSC_TRUE;
2618   } else {
2619     PetscInt i;
2620     is->pure_neumann = PETSC_FALSE;
2621 
2622     if (columns) {
2623       ierr = MatZeroRowsColumns(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
2624     } else {
2625       ierr = MatZeroRows(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
2626     }
2627     if (diag != 0.) {
2628       const PetscScalar *array;
2629       ierr = VecGetArrayRead(is->counter,&array);CHKERRQ(ierr);
2630       for (i=0; i<n; i++) {
2631         ierr = MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);CHKERRQ(ierr);
2632       }
2633       ierr = VecRestoreArrayRead(is->counter,&array);CHKERRQ(ierr);
2634     }
2635     ierr = MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2636     ierr = MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2637   }
2638   PetscFunctionReturn(0);
2639 }
2640 
2641 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b,PetscBool columns)
2642 {
2643   Mat_IS         *matis = (Mat_IS*)A->data;
2644   PetscInt       nr,nl,len,i;
2645   PetscInt       *lrows;
2646   PetscErrorCode ierr;
2647 
2648   PetscFunctionBegin;
2649 #if defined(PETSC_USE_DEBUG)
2650   if (columns || diag != 0. || (x && b)) {
2651     PetscBool cong;
2652 
2653     ierr = PetscLayoutCompare(A->rmap,A->cmap,&cong);CHKERRQ(ierr);
2654     cong = (PetscBool)(cong && matis->sf == matis->csf);
2655     if (!cong && columns) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Columns can be zeroed if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2656     if (!cong && diag != 0.) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Nonzero diagonal value supported if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2657     if (!cong && x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"A->rmap and A->cmap need to be congruent, and the l2g maps be the same");
2658   }
2659 #endif
2660   /* get locally owned rows */
2661   ierr = PetscLayoutMapLocal_Private(A->rmap,n,rows,&len,&lrows,NULL);CHKERRQ(ierr);
2662   /* fix right hand side if needed */
2663   if (x && b) {
2664     const PetscScalar *xx;
2665     PetscScalar       *bb;
2666 
2667     ierr = VecGetArrayRead(x, &xx);CHKERRQ(ierr);
2668     ierr = VecGetArray(b, &bb);CHKERRQ(ierr);
2669     for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]];
2670     ierr = VecRestoreArrayRead(x, &xx);CHKERRQ(ierr);
2671     ierr = VecRestoreArray(b, &bb);CHKERRQ(ierr);
2672   }
2673   /* get rows associated to the local matrices */
2674   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
2675   ierr = MatGetSize(matis->A,&nl,NULL);CHKERRQ(ierr);
2676   ierr = PetscMemzero(matis->sf_leafdata,nl*sizeof(PetscInt));CHKERRQ(ierr);
2677   ierr = PetscMemzero(matis->sf_rootdata,A->rmap->n*sizeof(PetscInt));CHKERRQ(ierr);
2678   for (i=0;i<len;i++) matis->sf_rootdata[lrows[i]] = 1;
2679   ierr = PetscFree(lrows);CHKERRQ(ierr);
2680   ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
2681   ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
2682   ierr = PetscMalloc1(nl,&lrows);CHKERRQ(ierr);
2683   for (i=0,nr=0;i<nl;i++) if (matis->sf_leafdata[i]) lrows[nr++] = i;
2684   ierr = MatISZeroRowsColumnsLocal_Private(A,nr,lrows,diag,columns);CHKERRQ(ierr);
2685   ierr = PetscFree(lrows);CHKERRQ(ierr);
2686   PetscFunctionReturn(0);
2687 }
2688 
2689 static PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2690 {
2691   PetscErrorCode ierr;
2692 
2693   PetscFunctionBegin;
2694   ierr = MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_FALSE);CHKERRQ(ierr);
2695   PetscFunctionReturn(0);
2696 }
2697 
2698 static PetscErrorCode MatZeroRowsColumns_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2699 {
2700   PetscErrorCode ierr;
2701 
2702   PetscFunctionBegin;
2703   ierr = MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_TRUE);CHKERRQ(ierr);
2704   PetscFunctionReturn(0);
2705 }
2706 
2707 static PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
2708 {
2709   Mat_IS         *is = (Mat_IS*)A->data;
2710   PetscErrorCode ierr;
2711 
2712   PetscFunctionBegin;
2713   ierr = MatAssemblyBegin(is->A,type);CHKERRQ(ierr);
2714   PetscFunctionReturn(0);
2715 }
2716 
2717 static PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
2718 {
2719   Mat_IS         *is = (Mat_IS*)A->data;
2720   PetscErrorCode ierr;
2721 
2722   PetscFunctionBegin;
2723   ierr = MatAssemblyEnd(is->A,type);CHKERRQ(ierr);
2724   /* fix for local empty rows/cols */
2725   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2726     Mat                    newlA;
2727     ISLocalToGlobalMapping rl2g,cl2g;
2728     IS                     nzr,nzc;
2729     PetscInt               nr,nc,nnzr,nnzc;
2730     PetscBool              lnewl2g,newl2g;
2731 
2732     ierr = MatGetSize(is->A,&nr,&nc);CHKERRQ(ierr);
2733     ierr = MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_FALSE,PETSC_SMALL,&nzr);CHKERRQ(ierr);
2734     if (!nzr) {
2735       ierr = ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&nzr);CHKERRQ(ierr);
2736     }
2737     ierr = MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_TRUE,PETSC_SMALL,&nzc);CHKERRQ(ierr);
2738     if (!nzc) {
2739       ierr = ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&nzc);CHKERRQ(ierr);
2740     }
2741     ierr = ISGetSize(nzr,&nnzr);CHKERRQ(ierr);
2742     ierr = ISGetSize(nzc,&nnzc);CHKERRQ(ierr);
2743     if (nnzr != nr || nnzc != nc) {
2744       ISLocalToGlobalMapping l2g;
2745       IS                     is1,is2;
2746 
2747       /* need new global l2g map */
2748       lnewl2g = PETSC_TRUE;
2749       ierr    = MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2750 
2751       /* extract valid submatrix */
2752       ierr = MatCreateSubMatrix(is->A,nzr,nzc,MAT_INITIAL_MATRIX,&newlA);CHKERRQ(ierr);
2753 
2754       /* attach local l2g maps for successive calls of MatSetValues on the local matrix */
2755       ierr = ISLocalToGlobalMappingCreateIS(nzr,&l2g);CHKERRQ(ierr);
2756       ierr = ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&is1);CHKERRQ(ierr);
2757       ierr = ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);CHKERRQ(ierr);
2758       ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
2759       if (is->A->rmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2760         const PetscInt *idxs1,*idxs2;
2761         PetscInt       j,i,nl,*tidxs;
2762 
2763         ierr = ISLocalToGlobalMappingGetSize(is->A->rmap->mapping,&nl);CHKERRQ(ierr);
2764         ierr = ISLocalToGlobalMappingGetIndices(is->A->rmap->mapping,&idxs1);CHKERRQ(ierr);
2765         ierr = PetscMalloc1(nl,&tidxs);CHKERRQ(ierr);
2766         ierr = ISGetIndices(is2,&idxs2);CHKERRQ(ierr);
2767         for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2768         if (j != nr) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nr);
2769         ierr = ISLocalToGlobalMappingRestoreIndices(is->A->rmap->mapping,&idxs1);CHKERRQ(ierr);
2770         ierr = ISRestoreIndices(is2,&idxs2);CHKERRQ(ierr);
2771         ierr = ISDestroy(&is2);CHKERRQ(ierr);
2772         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is->A->rmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);CHKERRQ(ierr);
2773       }
2774       ierr = ISLocalToGlobalMappingCreateIS(is2,&rl2g);CHKERRQ(ierr);
2775       ierr = ISDestroy(&is1);CHKERRQ(ierr);
2776       ierr = ISDestroy(&is2);CHKERRQ(ierr);
2777 
2778       ierr = ISLocalToGlobalMappingCreateIS(nzc,&l2g);CHKERRQ(ierr);
2779       ierr = ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&is1);CHKERRQ(ierr);
2780       ierr = ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);CHKERRQ(ierr);
2781       ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
2782       if (is->A->cmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2783         const PetscInt *idxs1,*idxs2;
2784         PetscInt       j,i,nl,*tidxs;
2785 
2786         ierr = ISLocalToGlobalMappingGetSize(is->A->cmap->mapping,&nl);CHKERRQ(ierr);
2787         ierr = ISLocalToGlobalMappingGetIndices(is->A->cmap->mapping,&idxs1);CHKERRQ(ierr);
2788         ierr = PetscMalloc1(nl,&tidxs);CHKERRQ(ierr);
2789         ierr = ISGetIndices(is2,&idxs2);CHKERRQ(ierr);
2790         for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2791         if (j != nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nc);
2792         ierr = ISLocalToGlobalMappingRestoreIndices(is->A->cmap->mapping,&idxs1);CHKERRQ(ierr);
2793         ierr = ISRestoreIndices(is2,&idxs2);CHKERRQ(ierr);
2794         ierr = ISDestroy(&is2);CHKERRQ(ierr);
2795         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is->A->cmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);CHKERRQ(ierr);
2796       }
2797       ierr = ISLocalToGlobalMappingCreateIS(is2,&cl2g);CHKERRQ(ierr);
2798       ierr = ISDestroy(&is1);CHKERRQ(ierr);
2799       ierr = ISDestroy(&is2);CHKERRQ(ierr);
2800 
2801       ierr = MatSetLocalToGlobalMapping(newlA,rl2g,cl2g);CHKERRQ(ierr);
2802 
2803       ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2804       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2805     } else { /* local matrix fully populated */
2806       lnewl2g = PETSC_FALSE;
2807       ierr    = MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2808       ierr    = PetscObjectReference((PetscObject)is->A);CHKERRQ(ierr);
2809       newlA   = is->A;
2810     }
2811     /* attach new global l2g map if needed */
2812     if (newl2g) {
2813       IS             gnzr,gnzc;
2814       const PetscInt *grid,*gcid;
2815 
2816       ierr = ISLocalToGlobalMappingApplyIS(A->rmap->mapping,nzr,&gnzr);CHKERRQ(ierr);
2817       ierr = ISLocalToGlobalMappingApplyIS(A->cmap->mapping,nzc,&gnzc);CHKERRQ(ierr);
2818       ierr = ISGetIndices(gnzr,&grid);CHKERRQ(ierr);
2819       ierr = ISGetIndices(gnzc,&gcid);CHKERRQ(ierr);
2820       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzr,grid,PETSC_COPY_VALUES,&rl2g);CHKERRQ(ierr);
2821       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzc,gcid,PETSC_COPY_VALUES,&cl2g);CHKERRQ(ierr);
2822       ierr = ISRestoreIndices(gnzr,&grid);CHKERRQ(ierr);
2823       ierr = ISRestoreIndices(gnzc,&gcid);CHKERRQ(ierr);
2824       ierr = ISDestroy(&gnzr);CHKERRQ(ierr);
2825       ierr = ISDestroy(&gnzc);CHKERRQ(ierr);
2826       ierr = MatSetLocalToGlobalMapping(A,rl2g,cl2g);CHKERRQ(ierr);
2827       ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2828       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2829     }
2830     ierr = MatISSetLocalMat(A,newlA);CHKERRQ(ierr);
2831     ierr = MatDestroy(&newlA);CHKERRQ(ierr);
2832     ierr = ISDestroy(&nzr);CHKERRQ(ierr);
2833     ierr = ISDestroy(&nzc);CHKERRQ(ierr);
2834     is->locempty = PETSC_FALSE;
2835   }
2836   PetscFunctionReturn(0);
2837 }
2838 
2839 static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
2840 {
2841   Mat_IS *is = (Mat_IS*)mat->data;
2842 
2843   PetscFunctionBegin;
2844   *local = is->A;
2845   PetscFunctionReturn(0);
2846 }
2847 
2848 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local)
2849 {
2850   PetscFunctionBegin;
2851   *local = NULL;
2852   PetscFunctionReturn(0);
2853 }
2854 
2855 /*@
2856     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
2857 
2858   Input Parameter:
2859 .  mat - the matrix
2860 
2861   Output Parameter:
2862 .  local - the local matrix
2863 
2864   Level: advanced
2865 
2866   Notes:
2867     This can be called if you have precomputed the nonzero structure of the
2868   matrix and want to provide it to the inner matrix object to improve the performance
2869   of the MatSetValues() operation.
2870 
2871   Call MatISRestoreLocalMat() when finished with the local matrix.
2872 
2873 .seealso: MATIS
2874 @*/
2875 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
2876 {
2877   PetscErrorCode ierr;
2878 
2879   PetscFunctionBegin;
2880   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2881   PetscValidPointer(local,2);
2882   ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
2883   PetscFunctionReturn(0);
2884 }
2885 
2886 /*@
2887     MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()
2888 
2889   Input Parameter:
2890 .  mat - the matrix
2891 
2892   Output Parameter:
2893 .  local - the local matrix
2894 
2895   Level: advanced
2896 
2897 .seealso: MATIS
2898 @*/
2899 PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local)
2900 {
2901   PetscErrorCode ierr;
2902 
2903   PetscFunctionBegin;
2904   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2905   PetscValidPointer(local,2);
2906   ierr = PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
2907   PetscFunctionReturn(0);
2908 }
2909 
2910 static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
2911 {
2912   Mat_IS         *is = (Mat_IS*)mat->data;
2913   PetscInt       nrows,ncols,orows,ocols;
2914   PetscErrorCode ierr;
2915 
2916   PetscFunctionBegin;
2917   if (is->A) {
2918     ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr);
2919     ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr);
2920     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)",orows,ocols,nrows,ncols);
2921   }
2922   ierr  = PetscObjectReference((PetscObject)local);CHKERRQ(ierr);
2923   ierr  = MatDestroy(&is->A);CHKERRQ(ierr);
2924   is->A = local;
2925   PetscFunctionReturn(0);
2926 }
2927 
2928 /*@
2929     MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.
2930 
2931   Input Parameter:
2932 .  mat - the matrix
2933 .  local - the local matrix
2934 
2935   Output Parameter:
2936 
2937   Level: advanced
2938 
2939   Notes:
2940     This can be called if you have precomputed the local matrix and
2941   want to provide it to the matrix object MATIS.
2942 
2943 .seealso: MATIS
2944 @*/
2945 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
2946 {
2947   PetscErrorCode ierr;
2948 
2949   PetscFunctionBegin;
2950   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2951   PetscValidHeaderSpecific(local,MAT_CLASSID,2);
2952   ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr);
2953   PetscFunctionReturn(0);
2954 }
2955 
2956 static PetscErrorCode MatZeroEntries_IS(Mat A)
2957 {
2958   Mat_IS         *a = (Mat_IS*)A->data;
2959   PetscErrorCode ierr;
2960 
2961   PetscFunctionBegin;
2962   ierr = MatZeroEntries(a->A);CHKERRQ(ierr);
2963   PetscFunctionReturn(0);
2964 }
2965 
2966 static PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
2967 {
2968   Mat_IS         *is = (Mat_IS*)A->data;
2969   PetscErrorCode ierr;
2970 
2971   PetscFunctionBegin;
2972   ierr = MatScale(is->A,a);CHKERRQ(ierr);
2973   PetscFunctionReturn(0);
2974 }
2975 
2976 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
2977 {
2978   Mat_IS         *is = (Mat_IS*)A->data;
2979   PetscErrorCode ierr;
2980 
2981   PetscFunctionBegin;
2982   /* get diagonal of the local matrix */
2983   ierr = MatGetDiagonal(is->A,is->y);CHKERRQ(ierr);
2984 
2985   /* scatter diagonal back into global vector */
2986   ierr = VecSet(v,0);CHKERRQ(ierr);
2987   ierr = VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2988   ierr = VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2989   PetscFunctionReturn(0);
2990 }
2991 
2992 static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
2993 {
2994   Mat_IS         *a = (Mat_IS*)A->data;
2995   PetscErrorCode ierr;
2996 
2997   PetscFunctionBegin;
2998   ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr);
2999   PetscFunctionReturn(0);
3000 }
3001 
3002 static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str)
3003 {
3004   Mat_IS         *y = (Mat_IS*)Y->data;
3005   Mat_IS         *x;
3006 #if defined(PETSC_USE_DEBUG)
3007   PetscBool      ismatis;
3008 #endif
3009   PetscErrorCode ierr;
3010 
3011   PetscFunctionBegin;
3012 #if defined(PETSC_USE_DEBUG)
3013   ierr = PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis);CHKERRQ(ierr);
3014   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
3015 #endif
3016   x = (Mat_IS*)X->data;
3017   ierr = MatAXPY(y->A,a,x->A,str);CHKERRQ(ierr);
3018   PetscFunctionReturn(0);
3019 }
3020 
3021 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat)
3022 {
3023   Mat                    lA;
3024   Mat_IS                 *matis;
3025   ISLocalToGlobalMapping rl2g,cl2g;
3026   IS                     is;
3027   const PetscInt         *rg,*rl;
3028   PetscInt               nrg;
3029   PetscInt               N,M,nrl,i,*idxs;
3030   PetscErrorCode         ierr;
3031 
3032   PetscFunctionBegin;
3033   ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
3034   ierr = ISGetLocalSize(row,&nrl);CHKERRQ(ierr);
3035   ierr = ISGetIndices(row,&rl);CHKERRQ(ierr);
3036   ierr = ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg);CHKERRQ(ierr);
3037 #if defined(PETSC_USE_DEBUG)
3038   for (i=0;i<nrl;i++) if (rl[i]>=nrg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row index %D -> %D greater than maximum possible %D",i,rl[i],nrg);
3039 #endif
3040   ierr = PetscMalloc1(nrg,&idxs);CHKERRQ(ierr);
3041   /* map from [0,nrl) to row */
3042   for (i=0;i<nrl;i++) idxs[i] = rl[i];
3043 #if defined(PETSC_USE_DEBUG)
3044   for (i=nrl;i<nrg;i++) idxs[i] = nrg;
3045 #else
3046   for (i=nrl;i<nrg;i++) idxs[i] = -1;
3047 #endif
3048   ierr = ISRestoreIndices(row,&rl);CHKERRQ(ierr);
3049   ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
3050   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
3051   ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
3052   ierr = ISDestroy(&is);CHKERRQ(ierr);
3053   /* compute new l2g map for columns */
3054   if (col != row || A->rmap->mapping != A->cmap->mapping) {
3055     const PetscInt *cg,*cl;
3056     PetscInt       ncg;
3057     PetscInt       ncl;
3058 
3059     ierr = ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
3060     ierr = ISGetLocalSize(col,&ncl);CHKERRQ(ierr);
3061     ierr = ISGetIndices(col,&cl);CHKERRQ(ierr);
3062     ierr = ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg);CHKERRQ(ierr);
3063 #if defined(PETSC_USE_DEBUG)
3064     for (i=0;i<ncl;i++) if (cl[i]>=ncg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local column index %D -> %D greater than maximum possible %D",i,cl[i],ncg);
3065 #endif
3066     ierr = PetscMalloc1(ncg,&idxs);CHKERRQ(ierr);
3067     /* map from [0,ncl) to col */
3068     for (i=0;i<ncl;i++) idxs[i] = cl[i];
3069 #if defined(PETSC_USE_DEBUG)
3070     for (i=ncl;i<ncg;i++) idxs[i] = ncg;
3071 #else
3072     for (i=ncl;i<ncg;i++) idxs[i] = -1;
3073 #endif
3074     ierr = ISRestoreIndices(col,&cl);CHKERRQ(ierr);
3075     ierr = ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
3076     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
3077     ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
3078     ierr = ISDestroy(&is);CHKERRQ(ierr);
3079   } else {
3080     ierr = PetscObjectReference((PetscObject)rl2g);CHKERRQ(ierr);
3081     cl2g = rl2g;
3082   }
3083   /* create the MATIS submatrix */
3084   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
3085   ierr = MatCreate(PetscObjectComm((PetscObject)A),submat);CHKERRQ(ierr);
3086   ierr = MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
3087   ierr = MatSetType(*submat,MATIS);CHKERRQ(ierr);
3088   matis = (Mat_IS*)((*submat)->data);
3089   matis->islocalref = PETSC_TRUE;
3090   ierr = MatSetLocalToGlobalMapping(*submat,rl2g,cl2g);CHKERRQ(ierr);
3091   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
3092   ierr = MatISSetLocalMat(*submat,lA);CHKERRQ(ierr);
3093   ierr = MatSetUp(*submat);CHKERRQ(ierr);
3094   ierr = MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3095   ierr = MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3096   ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
3097   ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
3098   /* remove unsupported ops */
3099   ierr = PetscMemzero((*submat)->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
3100   (*submat)->ops->destroy               = MatDestroy_IS;
3101   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3102   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3103   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3104   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3105   PetscFunctionReturn(0);
3106 }
3107 
3108 static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A)
3109 {
3110   Mat_IS         *a = (Mat_IS*)A->data;
3111   PetscErrorCode ierr;
3112 
3113   PetscFunctionBegin;
3114   ierr = PetscOptionsHead(PetscOptionsObject,"MATIS options");CHKERRQ(ierr);
3115   ierr = PetscObjectOptionsBegin((PetscObject)A);
3116   ierr = PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns","MatISFixLocalEmpty",a->locempty,&a->locempty,NULL);CHKERRQ(ierr);
3117   ierr = PetscOptionsBool("-matis_storel2l","Store local-to-local matrices generated from PtAP operations","MatISStoreL2L",a->storel2l,&a->storel2l,NULL);CHKERRQ(ierr);
3118   ierr = PetscOptionsEnd();CHKERRQ(ierr);
3119   PetscFunctionReturn(0);
3120 }
3121 
3122 /*@
3123     MatCreateIS - Creates a "process" unassembled matrix, assembled on each
3124        process but not across processes.
3125 
3126    Input Parameters:
3127 +     comm    - MPI communicator that will share the matrix
3128 .     bs      - block size of the matrix
3129 .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3130 .     rmap    - local to global map for rows
3131 -     cmap    - local to global map for cols
3132 
3133    Output Parameter:
3134 .    A - the resulting matrix
3135 
3136    Level: advanced
3137 
3138    Notes:
3139     See MATIS for more details.
3140           m and n are NOT related to the size of the map; they represent the size of the local parts of the vectors
3141           used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
3142           If either rmap or cmap are NULL, then the matrix is assumed to be square.
3143 
3144 .seealso: MATIS, MatSetLocalToGlobalMapping()
3145 @*/
3146 PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A)
3147 {
3148   PetscErrorCode ierr;
3149 
3150   PetscFunctionBegin;
3151   if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mappings");
3152   ierr = MatCreate(comm,A);CHKERRQ(ierr);
3153   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
3154   if (bs > 0) {
3155     ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr);
3156   }
3157   ierr = MatSetType(*A,MATIS);CHKERRQ(ierr);
3158   if (rmap && cmap) {
3159     ierr = MatSetLocalToGlobalMapping(*A,rmap,cmap);CHKERRQ(ierr);
3160   } else if (!rmap) {
3161     ierr = MatSetLocalToGlobalMapping(*A,cmap,cmap);CHKERRQ(ierr);
3162   } else {
3163     ierr = MatSetLocalToGlobalMapping(*A,rmap,rmap);CHKERRQ(ierr);
3164   }
3165   PetscFunctionReturn(0);
3166 }
3167 
3168 /*MC
3169    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
3170    This stores the matrices in globally unassembled form. Each processor
3171    assembles only its local Neumann problem and the parallel matrix vector
3172    product is handled "implicitly".
3173 
3174    Operations Provided:
3175 +  MatMult()
3176 .  MatMultAdd()
3177 .  MatMultTranspose()
3178 .  MatMultTransposeAdd()
3179 .  MatZeroEntries()
3180 .  MatSetOption()
3181 .  MatZeroRows()
3182 .  MatSetValues()
3183 .  MatSetValuesBlocked()
3184 .  MatSetValuesLocal()
3185 .  MatSetValuesBlockedLocal()
3186 .  MatScale()
3187 .  MatGetDiagonal()
3188 .  MatMissingDiagonal()
3189 .  MatDuplicate()
3190 .  MatCopy()
3191 .  MatAXPY()
3192 .  MatCreateSubMatrix()
3193 .  MatGetLocalSubMatrix()
3194 .  MatTranspose()
3195 .  MatPtAP() (with P of AIJ type)
3196 -  MatSetLocalToGlobalMapping()
3197 
3198    Options Database Keys:
3199 + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
3200 . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
3201 - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3202 
3203    Notes:
3204     Options prefix for the inner matrix are given by -is_mat_xxx
3205 
3206           You must call MatSetLocalToGlobalMapping() before using this matrix type.
3207 
3208           You can do matrix preallocation on the local matrix after you obtain it with
3209           MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()
3210 
3211   Level: advanced
3212 
3213 .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), MatCreateIS(), PCBDDC, KSPFETIDP
3214 
3215 M*/
3216 
3217 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3218 {
3219   PetscErrorCode ierr;
3220   Mat_IS         *b;
3221 
3222   PetscFunctionBegin;
3223   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
3224   A->data = (void*)b;
3225 
3226   /* matrix ops */
3227   ierr = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
3228   A->ops->mult                    = MatMult_IS;
3229   A->ops->multadd                 = MatMultAdd_IS;
3230   A->ops->multtranspose           = MatMultTranspose_IS;
3231   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3232   A->ops->destroy                 = MatDestroy_IS;
3233   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3234   A->ops->setvalues               = MatSetValues_IS;
3235   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3236   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3237   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
3238   A->ops->zerorows                = MatZeroRows_IS;
3239   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3240   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3241   A->ops->assemblyend             = MatAssemblyEnd_IS;
3242   A->ops->view                    = MatView_IS;
3243   A->ops->zeroentries             = MatZeroEntries_IS;
3244   A->ops->scale                   = MatScale_IS;
3245   A->ops->getdiagonal             = MatGetDiagonal_IS;
3246   A->ops->setoption               = MatSetOption_IS;
3247   A->ops->ishermitian             = MatIsHermitian_IS;
3248   A->ops->issymmetric             = MatIsSymmetric_IS;
3249   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3250   A->ops->duplicate               = MatDuplicate_IS;
3251   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
3252   A->ops->copy                    = MatCopy_IS;
3253   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
3254   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3255   A->ops->axpy                    = MatAXPY_IS;
3256   A->ops->diagonalset             = MatDiagonalSet_IS;
3257   A->ops->shift                   = MatShift_IS;
3258   A->ops->transpose               = MatTranspose_IS;
3259   A->ops->getinfo                 = MatGetInfo_IS;
3260   A->ops->diagonalscale           = MatDiagonalScale_IS;
3261   A->ops->setfromoptions          = MatSetFromOptions_IS;
3262 
3263   /* special MATIS functions */
3264   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr);
3265   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS);CHKERRQ(ierr);
3266   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr);
3267   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3268   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);CHKERRQ(ierr);
3269   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetUpSF_C",MatISSetUpSF_IS);CHKERRQ(ierr);
3270   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",MatISStoreL2L_IS);CHKERRQ(ierr);
3271   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",MatISFixLocalEmpty_IS);CHKERRQ(ierr);
3272   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3273   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3274   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3275   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3276   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3277   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3278   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3279   ierr = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr);
3280   PetscFunctionReturn(0);
3281 }
3282