xref: /petsc/src/mat/impls/is/matis.c (revision fabe8965ab9e196b74400c5e9aa2ee31ed4f64c9)
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       ierr = ISLocalToGlobalMappingCreateIS(is2,&rl2g);CHKERRQ(ierr);
2760       ierr = ISDestroy(&is1);CHKERRQ(ierr);
2761       ierr = ISDestroy(&is2);CHKERRQ(ierr);
2762       ierr = ISLocalToGlobalMappingCreateIS(nzc,&l2g);CHKERRQ(ierr);
2763       ierr = ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&is1);CHKERRQ(ierr);
2764       ierr = ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);CHKERRQ(ierr);
2765       ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
2766       ierr = ISLocalToGlobalMappingCreateIS(is2,&cl2g);CHKERRQ(ierr);
2767       ierr = ISDestroy(&is1);CHKERRQ(ierr);
2768       ierr = ISDestroy(&is2);CHKERRQ(ierr);
2769       ierr = MatSetLocalToGlobalMapping(newlA,rl2g,cl2g);CHKERRQ(ierr);
2770       ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2771       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2772     } else { /* local matrix fully populated */
2773       lnewl2g = PETSC_FALSE;
2774       ierr    = MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
2775       ierr    = PetscObjectReference((PetscObject)is->A);CHKERRQ(ierr);
2776       newlA   = is->A;
2777     }
2778     /* attach new global l2g map if needed */
2779     if (newl2g) {
2780       IS             gnzr,gnzc;
2781       const PetscInt *grid,*gcid;
2782 
2783       ierr = ISLocalToGlobalMappingApplyIS(A->rmap->mapping,nzr,&gnzr);CHKERRQ(ierr);
2784       ierr = ISLocalToGlobalMappingApplyIS(A->cmap->mapping,nzc,&gnzc);CHKERRQ(ierr);
2785       ierr = ISGetIndices(gnzr,&grid);CHKERRQ(ierr);
2786       ierr = ISGetIndices(gnzc,&gcid);CHKERRQ(ierr);
2787       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzr,grid,PETSC_COPY_VALUES,&rl2g);CHKERRQ(ierr);
2788       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzc,gcid,PETSC_COPY_VALUES,&cl2g);CHKERRQ(ierr);
2789       ierr = ISRestoreIndices(gnzr,&grid);CHKERRQ(ierr);
2790       ierr = ISRestoreIndices(gnzc,&gcid);CHKERRQ(ierr);
2791       ierr = ISDestroy(&gnzr);CHKERRQ(ierr);
2792       ierr = ISDestroy(&gnzc);CHKERRQ(ierr);
2793       ierr = MatSetLocalToGlobalMapping(A,rl2g,cl2g);CHKERRQ(ierr);
2794       ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2795       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2796     }
2797     ierr = MatISSetLocalMat(A,newlA);CHKERRQ(ierr);
2798     ierr = MatDestroy(&newlA);CHKERRQ(ierr);
2799     ierr = ISDestroy(&nzr);CHKERRQ(ierr);
2800     ierr = ISDestroy(&nzc);CHKERRQ(ierr);
2801     is->locempty = PETSC_FALSE;
2802   }
2803   PetscFunctionReturn(0);
2804 }
2805 
2806 static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
2807 {
2808   Mat_IS *is = (Mat_IS*)mat->data;
2809 
2810   PetscFunctionBegin;
2811   *local = is->A;
2812   PetscFunctionReturn(0);
2813 }
2814 
2815 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local)
2816 {
2817   PetscFunctionBegin;
2818   *local = NULL;
2819   PetscFunctionReturn(0);
2820 }
2821 
2822 /*@
2823     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
2824 
2825   Input Parameter:
2826 .  mat - the matrix
2827 
2828   Output Parameter:
2829 .  local - the local matrix
2830 
2831   Level: advanced
2832 
2833   Notes:
2834     This can be called if you have precomputed the nonzero structure of the
2835   matrix and want to provide it to the inner matrix object to improve the performance
2836   of the MatSetValues() operation.
2837 
2838   Call MatISRestoreLocalMat() when finished with the local matrix.
2839 
2840 .seealso: MATIS
2841 @*/
2842 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
2843 {
2844   PetscErrorCode ierr;
2845 
2846   PetscFunctionBegin;
2847   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2848   PetscValidPointer(local,2);
2849   ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
2850   PetscFunctionReturn(0);
2851 }
2852 
2853 /*@
2854     MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()
2855 
2856   Input Parameter:
2857 .  mat - the matrix
2858 
2859   Output Parameter:
2860 .  local - the local matrix
2861 
2862   Level: advanced
2863 
2864 .seealso: MATIS
2865 @*/
2866 PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local)
2867 {
2868   PetscErrorCode ierr;
2869 
2870   PetscFunctionBegin;
2871   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2872   PetscValidPointer(local,2);
2873   ierr = PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
2874   PetscFunctionReturn(0);
2875 }
2876 
2877 static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
2878 {
2879   Mat_IS         *is = (Mat_IS*)mat->data;
2880   PetscInt       nrows,ncols,orows,ocols;
2881   PetscErrorCode ierr;
2882 
2883   PetscFunctionBegin;
2884   if (is->A) {
2885     ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr);
2886     ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr);
2887     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);
2888   }
2889   ierr  = PetscObjectReference((PetscObject)local);CHKERRQ(ierr);
2890   ierr  = MatDestroy(&is->A);CHKERRQ(ierr);
2891   is->A = local;
2892   PetscFunctionReturn(0);
2893 }
2894 
2895 /*@
2896     MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.
2897 
2898   Input Parameter:
2899 .  mat - the matrix
2900 .  local - the local matrix
2901 
2902   Output Parameter:
2903 
2904   Level: advanced
2905 
2906   Notes:
2907     This can be called if you have precomputed the local matrix and
2908   want to provide it to the matrix object MATIS.
2909 
2910 .seealso: MATIS
2911 @*/
2912 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
2913 {
2914   PetscErrorCode ierr;
2915 
2916   PetscFunctionBegin;
2917   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2918   PetscValidHeaderSpecific(local,MAT_CLASSID,2);
2919   ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr);
2920   PetscFunctionReturn(0);
2921 }
2922 
2923 static PetscErrorCode MatZeroEntries_IS(Mat A)
2924 {
2925   Mat_IS         *a = (Mat_IS*)A->data;
2926   PetscErrorCode ierr;
2927 
2928   PetscFunctionBegin;
2929   ierr = MatZeroEntries(a->A);CHKERRQ(ierr);
2930   PetscFunctionReturn(0);
2931 }
2932 
2933 static PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
2934 {
2935   Mat_IS         *is = (Mat_IS*)A->data;
2936   PetscErrorCode ierr;
2937 
2938   PetscFunctionBegin;
2939   ierr = MatScale(is->A,a);CHKERRQ(ierr);
2940   PetscFunctionReturn(0);
2941 }
2942 
2943 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
2944 {
2945   Mat_IS         *is = (Mat_IS*)A->data;
2946   PetscErrorCode ierr;
2947 
2948   PetscFunctionBegin;
2949   /* get diagonal of the local matrix */
2950   ierr = MatGetDiagonal(is->A,is->y);CHKERRQ(ierr);
2951 
2952   /* scatter diagonal back into global vector */
2953   ierr = VecSet(v,0);CHKERRQ(ierr);
2954   ierr = VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2955   ierr = VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2956   PetscFunctionReturn(0);
2957 }
2958 
2959 static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
2960 {
2961   Mat_IS         *a = (Mat_IS*)A->data;
2962   PetscErrorCode ierr;
2963 
2964   PetscFunctionBegin;
2965   ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr);
2966   PetscFunctionReturn(0);
2967 }
2968 
2969 static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str)
2970 {
2971   Mat_IS         *y = (Mat_IS*)Y->data;
2972   Mat_IS         *x;
2973 #if defined(PETSC_USE_DEBUG)
2974   PetscBool      ismatis;
2975 #endif
2976   PetscErrorCode ierr;
2977 
2978   PetscFunctionBegin;
2979 #if defined(PETSC_USE_DEBUG)
2980   ierr = PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis);CHKERRQ(ierr);
2981   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
2982 #endif
2983   x = (Mat_IS*)X->data;
2984   ierr = MatAXPY(y->A,a,x->A,str);CHKERRQ(ierr);
2985   PetscFunctionReturn(0);
2986 }
2987 
2988 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat)
2989 {
2990   Mat                    lA;
2991   Mat_IS                 *matis;
2992   ISLocalToGlobalMapping rl2g,cl2g;
2993   IS                     is;
2994   const PetscInt         *rg,*rl;
2995   PetscInt               nrg;
2996   PetscInt               N,M,nrl,i,*idxs;
2997   PetscErrorCode         ierr;
2998 
2999   PetscFunctionBegin;
3000   ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
3001   ierr = ISGetLocalSize(row,&nrl);CHKERRQ(ierr);
3002   ierr = ISGetIndices(row,&rl);CHKERRQ(ierr);
3003   ierr = ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg);CHKERRQ(ierr);
3004 #if defined(PETSC_USE_DEBUG)
3005   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);
3006 #endif
3007   ierr = PetscMalloc1(nrg,&idxs);CHKERRQ(ierr);
3008   /* map from [0,nrl) to row */
3009   for (i=0;i<nrl;i++) idxs[i] = rl[i];
3010 #if defined(PETSC_USE_DEBUG)
3011   for (i=nrl;i<nrg;i++) idxs[i] = nrg;
3012 #else
3013   for (i=nrl;i<nrg;i++) idxs[i] = -1;
3014 #endif
3015   ierr = ISRestoreIndices(row,&rl);CHKERRQ(ierr);
3016   ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
3017   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
3018   ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
3019   ierr = ISDestroy(&is);CHKERRQ(ierr);
3020   /* compute new l2g map for columns */
3021   if (col != row || A->rmap->mapping != A->cmap->mapping) {
3022     const PetscInt *cg,*cl;
3023     PetscInt       ncg;
3024     PetscInt       ncl;
3025 
3026     ierr = ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
3027     ierr = ISGetLocalSize(col,&ncl);CHKERRQ(ierr);
3028     ierr = ISGetIndices(col,&cl);CHKERRQ(ierr);
3029     ierr = ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg);CHKERRQ(ierr);
3030 #if defined(PETSC_USE_DEBUG)
3031     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);
3032 #endif
3033     ierr = PetscMalloc1(ncg,&idxs);CHKERRQ(ierr);
3034     /* map from [0,ncl) to col */
3035     for (i=0;i<ncl;i++) idxs[i] = cl[i];
3036 #if defined(PETSC_USE_DEBUG)
3037     for (i=ncl;i<ncg;i++) idxs[i] = ncg;
3038 #else
3039     for (i=ncl;i<ncg;i++) idxs[i] = -1;
3040 #endif
3041     ierr = ISRestoreIndices(col,&cl);CHKERRQ(ierr);
3042     ierr = ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
3043     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
3044     ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
3045     ierr = ISDestroy(&is);CHKERRQ(ierr);
3046   } else {
3047     ierr = PetscObjectReference((PetscObject)rl2g);CHKERRQ(ierr);
3048     cl2g = rl2g;
3049   }
3050   /* create the MATIS submatrix */
3051   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
3052   ierr = MatCreate(PetscObjectComm((PetscObject)A),submat);CHKERRQ(ierr);
3053   ierr = MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
3054   ierr = MatSetType(*submat,MATIS);CHKERRQ(ierr);
3055   matis = (Mat_IS*)((*submat)->data);
3056   matis->islocalref = PETSC_TRUE;
3057   ierr = MatSetLocalToGlobalMapping(*submat,rl2g,cl2g);CHKERRQ(ierr);
3058   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
3059   ierr = MatISSetLocalMat(*submat,lA);CHKERRQ(ierr);
3060   ierr = MatSetUp(*submat);CHKERRQ(ierr);
3061   ierr = MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3062   ierr = MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
3063   ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
3064   ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
3065   /* remove unsupported ops */
3066   ierr = PetscMemzero((*submat)->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
3067   (*submat)->ops->destroy               = MatDestroy_IS;
3068   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3069   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3070   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3071   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3072   PetscFunctionReturn(0);
3073 }
3074 
3075 static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A)
3076 {
3077   Mat_IS         *a = (Mat_IS*)A->data;
3078   PetscErrorCode ierr;
3079 
3080   PetscFunctionBegin;
3081   ierr = PetscOptionsHead(PetscOptionsObject,"MATIS options");CHKERRQ(ierr);
3082   ierr = PetscObjectOptionsBegin((PetscObject)A);
3083   ierr = PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns","MatISFixLocalEmpty",a->locempty,&a->locempty,NULL);CHKERRQ(ierr);
3084   ierr = PetscOptionsBool("-matis_storel2l","Store local-to-local matrices generated from PtAP operations","MatISStoreL2L",a->storel2l,&a->storel2l,NULL);CHKERRQ(ierr);
3085   ierr = PetscOptionsEnd();CHKERRQ(ierr);
3086   PetscFunctionReturn(0);
3087 }
3088 
3089 /*@
3090     MatCreateIS - Creates a "process" unassembled matrix, assembled on each
3091        process but not across processes.
3092 
3093    Input Parameters:
3094 +     comm    - MPI communicator that will share the matrix
3095 .     bs      - block size of the matrix
3096 .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3097 .     rmap    - local to global map for rows
3098 -     cmap    - local to global map for cols
3099 
3100    Output Parameter:
3101 .    A - the resulting matrix
3102 
3103    Level: advanced
3104 
3105    Notes:
3106     See MATIS for more details.
3107           m and n are NOT related to the size of the map; they represent the size of the local parts of the vectors
3108           used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
3109           If either rmap or cmap are NULL, then the matrix is assumed to be square.
3110 
3111 .seealso: MATIS, MatSetLocalToGlobalMapping()
3112 @*/
3113 PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A)
3114 {
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mappings");
3119   ierr = MatCreate(comm,A);CHKERRQ(ierr);
3120   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
3121   if (bs > 0) {
3122     ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr);
3123   }
3124   ierr = MatSetType(*A,MATIS);CHKERRQ(ierr);
3125   if (rmap && cmap) {
3126     ierr = MatSetLocalToGlobalMapping(*A,rmap,cmap);CHKERRQ(ierr);
3127   } else if (!rmap) {
3128     ierr = MatSetLocalToGlobalMapping(*A,cmap,cmap);CHKERRQ(ierr);
3129   } else {
3130     ierr = MatSetLocalToGlobalMapping(*A,rmap,rmap);CHKERRQ(ierr);
3131   }
3132   PetscFunctionReturn(0);
3133 }
3134 
3135 /*MC
3136    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
3137    This stores the matrices in globally unassembled form. Each processor
3138    assembles only its local Neumann problem and the parallel matrix vector
3139    product is handled "implicitly".
3140 
3141    Operations Provided:
3142 +  MatMult()
3143 .  MatMultAdd()
3144 .  MatMultTranspose()
3145 .  MatMultTransposeAdd()
3146 .  MatZeroEntries()
3147 .  MatSetOption()
3148 .  MatZeroRows()
3149 .  MatSetValues()
3150 .  MatSetValuesBlocked()
3151 .  MatSetValuesLocal()
3152 .  MatSetValuesBlockedLocal()
3153 .  MatScale()
3154 .  MatGetDiagonal()
3155 .  MatMissingDiagonal()
3156 .  MatDuplicate()
3157 .  MatCopy()
3158 .  MatAXPY()
3159 .  MatCreateSubMatrix()
3160 .  MatGetLocalSubMatrix()
3161 .  MatTranspose()
3162 .  MatPtAP() (with P of AIJ type)
3163 -  MatSetLocalToGlobalMapping()
3164 
3165    Options Database Keys:
3166 + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
3167 . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
3168 - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3169 
3170    Notes:
3171     Options prefix for the inner matrix are given by -is_mat_xxx
3172 
3173           You must call MatSetLocalToGlobalMapping() before using this matrix type.
3174 
3175           You can do matrix preallocation on the local matrix after you obtain it with
3176           MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()
3177 
3178   Level: advanced
3179 
3180 .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), MatCreateIS(), PCBDDC, KSPFETIDP
3181 
3182 M*/
3183 
3184 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3185 {
3186   PetscErrorCode ierr;
3187   Mat_IS         *b;
3188 
3189   PetscFunctionBegin;
3190   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
3191   A->data = (void*)b;
3192 
3193   /* matrix ops */
3194   ierr = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
3195   A->ops->mult                    = MatMult_IS;
3196   A->ops->multadd                 = MatMultAdd_IS;
3197   A->ops->multtranspose           = MatMultTranspose_IS;
3198   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3199   A->ops->destroy                 = MatDestroy_IS;
3200   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3201   A->ops->setvalues               = MatSetValues_IS;
3202   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3203   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3204   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
3205   A->ops->zerorows                = MatZeroRows_IS;
3206   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3207   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3208   A->ops->assemblyend             = MatAssemblyEnd_IS;
3209   A->ops->view                    = MatView_IS;
3210   A->ops->zeroentries             = MatZeroEntries_IS;
3211   A->ops->scale                   = MatScale_IS;
3212   A->ops->getdiagonal             = MatGetDiagonal_IS;
3213   A->ops->setoption               = MatSetOption_IS;
3214   A->ops->ishermitian             = MatIsHermitian_IS;
3215   A->ops->issymmetric             = MatIsSymmetric_IS;
3216   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3217   A->ops->duplicate               = MatDuplicate_IS;
3218   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
3219   A->ops->copy                    = MatCopy_IS;
3220   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
3221   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3222   A->ops->axpy                    = MatAXPY_IS;
3223   A->ops->diagonalset             = MatDiagonalSet_IS;
3224   A->ops->shift                   = MatShift_IS;
3225   A->ops->transpose               = MatTranspose_IS;
3226   A->ops->getinfo                 = MatGetInfo_IS;
3227   A->ops->diagonalscale           = MatDiagonalScale_IS;
3228   A->ops->setfromoptions          = MatSetFromOptions_IS;
3229 
3230   /* special MATIS functions */
3231   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr);
3232   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS);CHKERRQ(ierr);
3233   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr);
3234   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3235   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);CHKERRQ(ierr);
3236   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetUpSF_C",MatISSetUpSF_IS);CHKERRQ(ierr);
3237   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",MatISStoreL2L_IS);CHKERRQ(ierr);
3238   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",MatISFixLocalEmpty_IS);CHKERRQ(ierr);
3239   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3240   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3241   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3242   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3243   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3244   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3245   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",MatConvert_IS_XAIJ);CHKERRQ(ierr);
3246   ierr = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr);
3247   PetscFunctionReturn(0);
3248 }
3249