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