xref: /petsc/src/mat/impls/is/matis.c (revision 00a402e09c6d62f19dbf72eef0e53394ab690d5c)
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 <../src/mat/impls/aij/mpi/mpiaij.h>
12 #include <petsc/private/sfimpl.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 
18 static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
19 {
20   MatISLocalFields lf = (MatISLocalFields)ptr;
21   PetscInt         i;
22   PetscErrorCode   ierr;
23 
24   PetscFunctionBegin;
25   for (i=0;i<lf->nr;i++) {
26     ierr = ISDestroy(&lf->rf[i]);CHKERRQ(ierr);
27   }
28   for (i=0;i<lf->nc;i++) {
29     ierr = ISDestroy(&lf->cf[i]);CHKERRQ(ierr);
30   }
31   ierr = PetscFree2(lf->rf,lf->cf);CHKERRQ(ierr);
32   ierr = PetscFree(lf);CHKERRQ(ierr);
33   PetscFunctionReturn(0);
34 }
35 
36 static PetscErrorCode MatISContainerDestroyArray_Private(void *ptr)
37 {
38   PetscErrorCode ierr;
39 
40   PetscFunctionBeginUser;
41   ierr = PetscFree(ptr);CHKERRQ(ierr);
42   PetscFunctionReturn(0);
43 }
44 
45 PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
46 {
47   Mat_MPIAIJ             *aij  = (Mat_MPIAIJ*)A->data;
48   Mat_SeqAIJ             *diag = (Mat_SeqAIJ*)(aij->A->data);
49   Mat_SeqAIJ             *offd = (Mat_SeqAIJ*)(aij->B->data);
50   Mat                    lA;
51   ISLocalToGlobalMapping rl2g,cl2g;
52   IS                     is;
53   MPI_Comm               comm;
54   void                   *ptrs[2];
55   const char             *names[2] = {"_convert_csr_aux","_convert_csr_data"};
56   PetscScalar            *dd,*od,*aa,*data;
57   PetscInt               *di,*dj,*oi,*oj;
58   PetscInt               *aux,*ii,*jj;
59   PetscInt               lc,dr,dc,oc,str,stc,nnz,i,jd,jo,cum;
60   PetscErrorCode         ierr;
61 
62   PetscFunctionBegin;
63   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
64   if (!aij->garray) SETERRQ(comm,PETSC_ERR_SUP,"garray not present");
65 
66   /* access relevant information from MPIAIJ */
67   ierr = MatGetOwnershipRange(A,&str,NULL);CHKERRQ(ierr);
68   ierr = MatGetOwnershipRangeColumn(A,&stc,NULL);CHKERRQ(ierr);
69   ierr = MatGetLocalSize(A,&dr,&dc);CHKERRQ(ierr);
70   di   = diag->i;
71   dj   = diag->j;
72   dd   = diag->a;
73   oc   = aij->B->cmap->n;
74   oi   = offd->i;
75   oj   = offd->j;
76   od   = offd->a;
77   nnz  = diag->i[dr] + offd->i[dr];
78 
79   /* generate l2g maps for rows and cols */
80   ierr = ISCreateStride(comm,dr,str,1,&is);CHKERRQ(ierr);
81   ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
82   ierr = ISDestroy(&is);CHKERRQ(ierr);
83   if (dr) {
84     ierr = PetscMalloc1(dc+oc,&aux);CHKERRQ(ierr);
85     for (i=0; i<dc; i++) aux[i]    = i+stc;
86     for (i=0; i<oc; i++) aux[i+dc] = aij->garray[i];
87     ierr = ISCreateGeneral(comm,dc+oc,aux,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
88     lc   = dc+oc;
89   } else {
90     ierr = ISCreateGeneral(comm,0,NULL,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
91     lc   = 0;
92   }
93   ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
94   ierr = ISDestroy(&is);CHKERRQ(ierr);
95 
96   /* create MATIS object */
97   ierr = MatCreate(comm,newmat);CHKERRQ(ierr);
98   ierr = MatSetSizes(*newmat,dr,dc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
99   ierr = MatSetType(*newmat,MATIS);CHKERRQ(ierr);
100   ierr = MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g);CHKERRQ(ierr);
101   ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
102   ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
103 
104   /* merge local matrices */
105   ierr = PetscMalloc1(nnz+dr+1,&aux);CHKERRQ(ierr);
106   ierr = PetscMalloc1(nnz,&data);CHKERRQ(ierr);
107   ii   = aux;
108   jj   = aux+dr+1;
109   aa   = data;
110   *ii  = *(di++) + *(oi++);
111   for (jd=0,jo=0,cum=0;*ii<nnz;cum++)
112   {
113      for (;jd<*di;jd++) { *jj++ = *dj++;      *aa++ = *dd++; }
114      for (;jo<*oi;jo++) { *jj++ = *oj++ + dc; *aa++ = *od++; }
115      *(++ii) = *(di++) + *(oi++);
116   }
117   for (;cum<dr;cum++) *(++ii) = nnz;
118   ii   = aux;
119   jj   = aux+dr+1;
120   aa   = data;
121   ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,lc,ii,jj,aa,&lA);CHKERRQ(ierr);
122 
123   /* create containers to destroy the data */
124   ptrs[0] = aux;
125   ptrs[1] = data;
126   for (i=0; i<2; i++) {
127     PetscContainer c;
128 
129     ierr = PetscContainerCreate(PETSC_COMM_SELF,&c);CHKERRQ(ierr);
130     ierr = PetscContainerSetPointer(c,ptrs[i]);CHKERRQ(ierr);
131     ierr = PetscContainerSetUserDestroy(c,MatISContainerDestroyArray_Private);CHKERRQ(ierr);
132     ierr = PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);CHKERRQ(ierr);
133     ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
134   }
135 
136   /* finalize matrix */
137   ierr = MatISSetLocalMat(*newmat,lA);CHKERRQ(ierr);
138   ierr = MatDestroy(&lA);CHKERRQ(ierr);
139   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
140   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
141   PetscFunctionReturn(0);
142 }
143 
144 /*@
145    MatISSetUpSF - Setup star forest objects used by MatIS.
146 
147    Collective on MPI_Comm
148 
149    Input Parameters:
150 +  A - the matrix
151 
152    Level: advanced
153 
154    Notes: This function does not need to be called by the user.
155 
156 .keywords: matrix
157 
158 .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatISGetLocalMat()
159 @*/
160 PetscErrorCode  MatISSetUpSF(Mat A)
161 {
162   PetscErrorCode ierr;
163 
164   PetscFunctionBegin;
165   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
166   PetscValidType(A,1);
167   ierr = PetscTryMethod(A,"MatISSetUpSF_C",(Mat),(A));CHKERRQ(ierr);
168   PetscFunctionReturn(0);
169 }
170 
171 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
172 {
173   Mat                    **nest,*snest,**rnest,lA,B;
174   IS                     *iscol,*isrow,*islrow,*islcol;
175   ISLocalToGlobalMapping rl2g,cl2g;
176   MPI_Comm               comm;
177   PetscInt               *lr,*lc,*l2gidxs;
178   PetscInt               i,j,nr,nc,rbs,cbs;
179   PetscBool              convert,lreuse,*istrans;
180   PetscErrorCode         ierr;
181 
182   PetscFunctionBegin;
183   ierr   = MatNestGetSubMats(A,&nr,&nc,&nest);CHKERRQ(ierr);
184   lreuse = PETSC_FALSE;
185   rnest  = NULL;
186   if (reuse == MAT_REUSE_MATRIX) {
187     PetscBool ismatis,isnest;
188 
189     ierr = PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);CHKERRQ(ierr);
190     if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_USER,"Cannot reuse matrix of type %s",((PetscObject)(*newmat))->type);
191     ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
192     ierr = PetscObjectTypeCompare((PetscObject)lA,MATNEST,&isnest);CHKERRQ(ierr);
193     if (isnest) {
194       ierr   = MatNestGetSubMats(lA,&i,&j,&rnest);CHKERRQ(ierr);
195       lreuse = (PetscBool)(i == nr && j == nc);
196       if (!lreuse) rnest = NULL;
197     }
198   }
199   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
200   ierr = PetscCalloc2(nr,&lr,nc,&lc);CHKERRQ(ierr);
201   ierr = PetscCalloc6(nr,&isrow,nc,&iscol,
202                       nr,&islrow,nc,&islcol,
203                       nr*nc,&snest,nr*nc,&istrans);CHKERRQ(ierr);
204   ierr = MatNestGetISs(A,isrow,iscol);CHKERRQ(ierr);
205   for (i=0;i<nr;i++) {
206     for (j=0;j<nc;j++) {
207       PetscBool ismatis;
208       PetscInt  l1,l2,lb1,lb2,ij=i*nc+j;
209 
210       /* Null matrix pointers are allowed in MATNEST */
211       if (!nest[i][j]) continue;
212 
213       /* Nested matrices should be of type MATIS */
214       ierr = PetscObjectTypeCompare((PetscObject)nest[i][j],MATTRANSPOSEMAT,&istrans[ij]);CHKERRQ(ierr);
215       if (istrans[ij]) {
216         Mat T,lT;
217         ierr = MatTransposeGetMat(nest[i][j],&T);CHKERRQ(ierr);
218         ierr = PetscObjectTypeCompare((PetscObject)T,MATIS,&ismatis);CHKERRQ(ierr);
219         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);
220         ierr = MatISGetLocalMat(T,&lT);CHKERRQ(ierr);
221         ierr = MatCreateTranspose(lT,&snest[ij]);CHKERRQ(ierr);
222       } else {
223         ierr = PetscObjectTypeCompare((PetscObject)nest[i][j],MATIS,&ismatis);CHKERRQ(ierr);
224         if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) is not of type MATIS",i,j);
225         ierr = MatISGetLocalMat(nest[i][j],&snest[ij]);CHKERRQ(ierr);
226       }
227 
228       /* Check compatibility of local sizes */
229       ierr = MatGetSize(snest[ij],&l1,&l2);CHKERRQ(ierr);
230       ierr = MatGetBlockSizes(snest[ij],&lb1,&lb2);CHKERRQ(ierr);
231       if (!l1 || !l2) continue;
232       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);
233       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);
234       lr[i] = l1;
235       lc[j] = l2;
236 
237       /* check compatibilty for local matrix reusage */
238       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
239     }
240   }
241 
242 #if defined (PETSC_USE_DEBUG)
243   /* Check compatibility of l2g maps for rows */
244   for (i=0;i<nr;i++) {
245     rl2g = NULL;
246     for (j=0;j<nc;j++) {
247       PetscInt n1,n2;
248 
249       if (!nest[i][j]) continue;
250       if (istrans[i*nc+j]) {
251         Mat T;
252 
253         ierr = MatTransposeGetMat(nest[i][j],&T);CHKERRQ(ierr);
254         ierr = MatGetLocalToGlobalMapping(T,NULL,&cl2g);CHKERRQ(ierr);
255       } else {
256         ierr = MatGetLocalToGlobalMapping(nest[i][j],&cl2g,NULL);CHKERRQ(ierr);
257       }
258       ierr = ISLocalToGlobalMappingGetSize(cl2g,&n1);CHKERRQ(ierr);
259       if (!n1) continue;
260       if (!rl2g) {
261         rl2g = cl2g;
262       } else {
263         const PetscInt *idxs1,*idxs2;
264         PetscBool      same;
265 
266         ierr = ISLocalToGlobalMappingGetSize(rl2g,&n2);CHKERRQ(ierr);
267         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);
268         ierr = ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);CHKERRQ(ierr);
269         ierr = ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);CHKERRQ(ierr);
270         ierr = PetscMemcmp(idxs1,idxs2,n1*sizeof(PetscInt),&same);CHKERRQ(ierr);
271         ierr = ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);CHKERRQ(ierr);
272         ierr = ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);CHKERRQ(ierr);
273         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);
274       }
275     }
276   }
277   /* Check compatibility of l2g maps for columns */
278   for (i=0;i<nc;i++) {
279     rl2g = NULL;
280     for (j=0;j<nr;j++) {
281       PetscInt n1,n2;
282 
283       if (!nest[j][i]) continue;
284       if (istrans[j*nc+i]) {
285         Mat T;
286 
287         ierr = MatTransposeGetMat(nest[j][i],&T);CHKERRQ(ierr);
288         ierr = MatGetLocalToGlobalMapping(T,&cl2g,NULL);CHKERRQ(ierr);
289       } else {
290         ierr = MatGetLocalToGlobalMapping(nest[j][i],NULL,&cl2g);CHKERRQ(ierr);
291       }
292       ierr = ISLocalToGlobalMappingGetSize(cl2g,&n1);CHKERRQ(ierr);
293       if (!n1) continue;
294       if (!rl2g) {
295         rl2g = cl2g;
296       } else {
297         const PetscInt *idxs1,*idxs2;
298         PetscBool      same;
299 
300         ierr = ISLocalToGlobalMappingGetSize(rl2g,&n2);CHKERRQ(ierr);
301         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);
302         ierr = ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);CHKERRQ(ierr);
303         ierr = ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);CHKERRQ(ierr);
304         ierr = PetscMemcmp(idxs1,idxs2,n1*sizeof(PetscInt),&same);CHKERRQ(ierr);
305         ierr = ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);CHKERRQ(ierr);
306         ierr = ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);CHKERRQ(ierr);
307         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);
308       }
309     }
310   }
311 #endif
312 
313   B = NULL;
314   if (reuse != MAT_REUSE_MATRIX) {
315     PetscInt stl;
316 
317     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
318     for (i=0,stl=0;i<nr;i++) stl += lr[i];
319     ierr = PetscMalloc1(stl,&l2gidxs);CHKERRQ(ierr);
320     for (i=0,stl=0;i<nr;i++) {
321       Mat            usedmat;
322       Mat_IS         *matis;
323       const PetscInt *idxs;
324 
325       /* local IS for local NEST */
326       ierr  = ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);CHKERRQ(ierr);
327 
328       /* l2gmap */
329       j = 0;
330       usedmat = nest[i][j];
331       while (!usedmat && j < nc-1) usedmat = nest[i][++j];
332       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid row mat");
333 
334       if (istrans[i*nc+j]) {
335         Mat T;
336         ierr    = MatTransposeGetMat(usedmat,&T);CHKERRQ(ierr);
337         usedmat = T;
338       }
339       ierr  = MatISSetUpSF(usedmat);CHKERRQ(ierr);
340       matis = (Mat_IS*)(usedmat->data);
341       ierr  = ISGetIndices(isrow[i],&idxs);CHKERRQ(ierr);
342       if (istrans[i*nc+j]) {
343         ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
344         ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
345       } else {
346         ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
347         ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
348       }
349       ierr = ISRestoreIndices(isrow[i],&idxs);CHKERRQ(ierr);
350       stl += lr[i];
351     }
352     ierr = ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&rl2g);CHKERRQ(ierr);
353 
354     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
355     for (i=0,stl=0;i<nc;i++) stl += lc[i];
356     ierr = PetscMalloc1(stl,&l2gidxs);CHKERRQ(ierr);
357     for (i=0,stl=0;i<nc;i++) {
358       Mat            usedmat;
359       Mat_IS         *matis;
360       const PetscInt *idxs;
361 
362       /* local IS for local NEST */
363       ierr  = ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);CHKERRQ(ierr);
364 
365       /* l2gmap */
366       j = 0;
367       usedmat = nest[j][i];
368       while (!usedmat && j < nr-1) usedmat = nest[++j][i];
369       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid column mat");
370       if (istrans[j*nc+i]) {
371         Mat T;
372         ierr    = MatTransposeGetMat(usedmat,&T);CHKERRQ(ierr);
373         usedmat = T;
374       }
375       ierr  = MatISSetUpSF(usedmat);CHKERRQ(ierr);
376       matis = (Mat_IS*)(usedmat->data);
377       ierr  = ISGetIndices(iscol[i],&idxs);CHKERRQ(ierr);
378       if (istrans[j*nc+i]) {
379         ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
380         ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
381       } else {
382         ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
383         ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);CHKERRQ(ierr);
384       }
385       ierr = ISRestoreIndices(iscol[i],&idxs);CHKERRQ(ierr);
386       stl += lc[i];
387     }
388     ierr = ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&cl2g);CHKERRQ(ierr);
389 
390     /* Create MATIS */
391     ierr = MatCreate(comm,&B);CHKERRQ(ierr);
392     ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);CHKERRQ(ierr);
393     ierr = MatGetBlockSizes(A,&rbs,&cbs);CHKERRQ(ierr);
394     ierr = MatSetBlockSizes(B,rbs,cbs);CHKERRQ(ierr);
395     ierr = MatSetType(B,MATIS);CHKERRQ(ierr);
396     ierr = MatSetLocalToGlobalMapping(B,rl2g,cl2g);CHKERRQ(ierr);
397     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
398     ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
399     ierr = MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);CHKERRQ(ierr);
400     for (i=0;i<nr*nc;i++) {
401       if (istrans[i]) {
402         ierr = MatDestroy(&snest[i]);CHKERRQ(ierr);
403       }
404     }
405     ierr = MatISSetLocalMat(B,lA);CHKERRQ(ierr);
406     ierr = MatDestroy(&lA);CHKERRQ(ierr);
407     ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
408     ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
409     if (reuse == MAT_INPLACE_MATRIX) {
410       ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
411     } else {
412       *newmat = B;
413     }
414   } else {
415     if (lreuse) {
416       ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
417       for (i=0;i<nr;i++) {
418         for (j=0;j<nc;j++) {
419           if (snest[i*nc+j]) {
420             ierr = MatNestSetSubMat(lA,i,j,snest[i*nc+j]);CHKERRQ(ierr);
421             if (istrans[i*nc+j]) {
422               ierr = MatDestroy(&snest[i*nc+j]);CHKERRQ(ierr);
423             }
424           }
425         }
426       }
427     } else {
428       PetscInt stl;
429       for (i=0,stl=0;i<nr;i++) {
430         ierr  = ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);CHKERRQ(ierr);
431         stl  += lr[i];
432       }
433       for (i=0,stl=0;i<nc;i++) {
434         ierr  = ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);CHKERRQ(ierr);
435         stl  += lc[i];
436       }
437       ierr = MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);CHKERRQ(ierr);
438       for (i=0;i<nr*nc;i++) {
439         if (istrans[i]) {
440           ierr = MatDestroy(&snest[i]);CHKERRQ(ierr);
441         }
442       }
443       ierr = MatISSetLocalMat(*newmat,lA);CHKERRQ(ierr);
444       ierr = MatDestroy(&lA);CHKERRQ(ierr);
445     }
446     ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
447     ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
448   }
449 
450   /* Create local matrix in MATNEST format */
451   convert = PETSC_FALSE;
452   ierr = PetscOptionsGetBool(NULL,((PetscObject)A)->prefix,"-matis_convert_local_nest",&convert,NULL);CHKERRQ(ierr);
453   if (convert) {
454     Mat              M;
455     MatISLocalFields lf;
456     PetscContainer   c;
457 
458     ierr = MatISGetLocalMat(*newmat,&lA);CHKERRQ(ierr);
459     ierr = MatConvert(lA,MATAIJ,MAT_INITIAL_MATRIX,&M);CHKERRQ(ierr);
460     ierr = MatISSetLocalMat(*newmat,M);CHKERRQ(ierr);
461     ierr = MatDestroy(&M);CHKERRQ(ierr);
462 
463     /* attach local fields to the matrix */
464     ierr = PetscNew(&lf);CHKERRQ(ierr);
465     ierr = PetscCalloc2(nr,&lf->rf,nc,&lf->cf);CHKERRQ(ierr);
466     for (i=0;i<nr;i++) {
467       PetscInt n,st;
468 
469       ierr = ISGetLocalSize(islrow[i],&n);CHKERRQ(ierr);
470       ierr = ISStrideGetInfo(islrow[i],&st,NULL);CHKERRQ(ierr);
471       ierr = ISCreateStride(comm,n,st,1,&lf->rf[i]);CHKERRQ(ierr);
472     }
473     for (i=0;i<nc;i++) {
474       PetscInt n,st;
475 
476       ierr = ISGetLocalSize(islcol[i],&n);CHKERRQ(ierr);
477       ierr = ISStrideGetInfo(islcol[i],&st,NULL);CHKERRQ(ierr);
478       ierr = ISCreateStride(comm,n,st,1,&lf->cf[i]);CHKERRQ(ierr);
479     }
480     lf->nr = nr;
481     lf->nc = nc;
482     ierr = PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)),&c);CHKERRQ(ierr);
483     ierr = PetscContainerSetPointer(c,lf);CHKERRQ(ierr);
484     ierr = PetscContainerSetUserDestroy(c,MatISContainerDestroyFields_Private);CHKERRQ(ierr);
485     ierr = PetscObjectCompose((PetscObject)(*newmat),"_convert_nest_lfields",(PetscObject)c);CHKERRQ(ierr);
486     ierr = PetscContainerDestroy(&c);CHKERRQ(ierr);
487   }
488 
489   /* Free workspace */
490   for (i=0;i<nr;i++) {
491     ierr = ISDestroy(&islrow[i]);CHKERRQ(ierr);
492   }
493   for (i=0;i<nc;i++) {
494     ierr = ISDestroy(&islcol[i]);CHKERRQ(ierr);
495   }
496   ierr = PetscFree6(isrow,iscol,islrow,islcol,snest,istrans);CHKERRQ(ierr);
497   ierr = PetscFree2(lr,lc);CHKERRQ(ierr);
498   PetscFunctionReturn(0);
499 }
500 
501 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
502 {
503   Mat_IS            *matis = (Mat_IS*)A->data;
504   Vec               ll,rr;
505   const PetscScalar *Y,*X;
506   PetscScalar       *x,*y;
507   PetscErrorCode    ierr;
508 
509   PetscFunctionBegin;
510   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
511   if (l) {
512     ll   = matis->y;
513     ierr = VecGetArrayRead(l,&Y);CHKERRQ(ierr);
514     ierr = VecGetArray(ll,&y);CHKERRQ(ierr);
515     ierr = PetscSFBcastBegin(matis->sf,MPIU_SCALAR,Y,y);CHKERRQ(ierr);
516   } else {
517     ll = NULL;
518   }
519   if (r) {
520     rr   = matis->x;
521     ierr = VecGetArrayRead(r,&X);CHKERRQ(ierr);
522     ierr = VecGetArray(rr,&x);CHKERRQ(ierr);
523     ierr = PetscSFBcastBegin(matis->csf,MPIU_SCALAR,X,x);CHKERRQ(ierr);
524   } else {
525     rr = NULL;
526   }
527   if (ll) {
528     ierr = PetscSFBcastEnd(matis->sf,MPIU_SCALAR,Y,y);CHKERRQ(ierr);
529     ierr = VecRestoreArrayRead(l,&Y);CHKERRQ(ierr);
530     ierr = VecRestoreArray(ll,&y);CHKERRQ(ierr);
531   }
532   if (rr) {
533     ierr = PetscSFBcastEnd(matis->csf,MPIU_SCALAR,X,x);CHKERRQ(ierr);
534     ierr = VecRestoreArrayRead(r,&X);CHKERRQ(ierr);
535     ierr = VecRestoreArray(rr,&x);CHKERRQ(ierr);
536   }
537   ierr = MatDiagonalScale(matis->A,ll,rr);CHKERRQ(ierr);
538   PetscFunctionReturn(0);
539 }
540 
541 static PetscErrorCode MatGetInfo_IS(Mat A,MatInfoType flag,MatInfo *ginfo)
542 {
543   Mat_IS         *matis = (Mat_IS*)A->data;
544   MatInfo        info;
545   PetscReal      isend[6],irecv[6];
546   PetscInt       bs;
547   PetscErrorCode ierr;
548 
549   PetscFunctionBegin;
550   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
551   if (matis->A->ops->getinfo) {
552     ierr     = MatGetInfo(matis->A,MAT_LOCAL,&info);CHKERRQ(ierr);
553     isend[0] = info.nz_used;
554     isend[1] = info.nz_allocated;
555     isend[2] = info.nz_unneeded;
556     isend[3] = info.memory;
557     isend[4] = info.mallocs;
558   } else {
559     isend[0] = 0.;
560     isend[1] = 0.;
561     isend[2] = 0.;
562     isend[3] = 0.;
563     isend[4] = 0.;
564   }
565   isend[5] = matis->A->num_ass;
566   if (flag == MAT_LOCAL) {
567     ginfo->nz_used      = isend[0];
568     ginfo->nz_allocated = isend[1];
569     ginfo->nz_unneeded  = isend[2];
570     ginfo->memory       = isend[3];
571     ginfo->mallocs      = isend[4];
572     ginfo->assemblies   = isend[5];
573   } else if (flag == MAT_GLOBAL_MAX) {
574     ierr = MPIU_Allreduce(isend,irecv,6,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
575 
576     ginfo->nz_used      = irecv[0];
577     ginfo->nz_allocated = irecv[1];
578     ginfo->nz_unneeded  = irecv[2];
579     ginfo->memory       = irecv[3];
580     ginfo->mallocs      = irecv[4];
581     ginfo->assemblies   = irecv[5];
582   } else if (flag == MAT_GLOBAL_SUM) {
583     ierr = MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
584 
585     ginfo->nz_used      = irecv[0];
586     ginfo->nz_allocated = irecv[1];
587     ginfo->nz_unneeded  = irecv[2];
588     ginfo->memory       = irecv[3];
589     ginfo->mallocs      = irecv[4];
590     ginfo->assemblies   = A->num_ass;
591   }
592   ginfo->block_size        = bs;
593   ginfo->fill_ratio_given  = 0;
594   ginfo->fill_ratio_needed = 0;
595   ginfo->factor_mallocs    = 0;
596   PetscFunctionReturn(0);
597 }
598 
599 PetscErrorCode MatTranspose_IS(Mat A,MatReuse reuse,Mat *B)
600 {
601   Mat                    C,lC,lA;
602   PetscErrorCode         ierr;
603 
604   PetscFunctionBegin;
605   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
606     ISLocalToGlobalMapping rl2g,cl2g;
607     ierr = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
608     ierr = MatSetSizes(C,A->cmap->n,A->rmap->n,A->cmap->N,A->rmap->N);CHKERRQ(ierr);
609     ierr = MatSetBlockSizes(C,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs));CHKERRQ(ierr);
610     ierr = MatSetType(C,MATIS);CHKERRQ(ierr);
611     ierr = MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);CHKERRQ(ierr);
612     ierr = MatSetLocalToGlobalMapping(C,cl2g,rl2g);CHKERRQ(ierr);
613   } else {
614     C = *B;
615   }
616 
617   /* perform local transposition */
618   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
619   ierr = MatTranspose(lA,MAT_INITIAL_MATRIX,&lC);CHKERRQ(ierr);
620   ierr = MatISSetLocalMat(C,lC);CHKERRQ(ierr);
621   ierr = MatDestroy(&lC);CHKERRQ(ierr);
622 
623   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
624     *B = C;
625   } else {
626     ierr = MatHeaderMerge(A,&C);CHKERRQ(ierr);
627   }
628   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
629   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
630   PetscFunctionReturn(0);
631 }
632 
633 PetscErrorCode  MatDiagonalSet_IS(Mat A,Vec D,InsertMode insmode)
634 {
635   Mat_IS         *is = (Mat_IS*)A->data;
636   PetscErrorCode ierr;
637 
638   PetscFunctionBegin;
639   if (D) { /* MatShift_IS pass D = NULL */
640     ierr = VecScatterBegin(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
641     ierr = VecScatterEnd(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
642   }
643   ierr = VecPointwiseDivide(is->y,is->y,is->counter);CHKERRQ(ierr);
644   ierr = MatDiagonalSet(is->A,is->y,insmode);CHKERRQ(ierr);
645   PetscFunctionReturn(0);
646 }
647 
648 PetscErrorCode  MatShift_IS(Mat A,PetscScalar a)
649 {
650   Mat_IS         *is = (Mat_IS*)A->data;
651   PetscErrorCode ierr;
652 
653   PetscFunctionBegin;
654   ierr = VecSet(is->y,a);CHKERRQ(ierr);
655   ierr = MatDiagonalSet_IS(A,NULL,ADD_VALUES);CHKERRQ(ierr);
656   PetscFunctionReturn(0);
657 }
658 
659 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
660 {
661   PetscErrorCode ierr;
662   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
663 
664   PetscFunctionBegin;
665 #if defined(PETSC_USE_DEBUG)
666   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);
667 #endif
668   ierr = ISLocalToGlobalMappingApply(A->rmap->mapping,m,rows,rows_l);CHKERRQ(ierr);
669   ierr = ISLocalToGlobalMappingApply(A->cmap->mapping,n,cols,cols_l);CHKERRQ(ierr);
670   ierr = MatSetValuesLocal_IS(A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
671   PetscFunctionReturn(0);
672 }
673 
674 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
675 {
676   PetscErrorCode ierr;
677   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
678 
679   PetscFunctionBegin;
680 #if defined(PETSC_USE_DEBUG)
681   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);
682 #endif
683   ierr = ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,m,rows,rows_l);CHKERRQ(ierr);
684   ierr = ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,n,cols,cols_l);CHKERRQ(ierr);
685   ierr = MatSetValuesBlockedLocal_IS(A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
686   PetscFunctionReturn(0);
687 }
688 
689 static PetscErrorCode PetscLayoutMapLocal_Private(PetscLayout map,PetscInt N,const PetscInt idxs[], PetscInt *on,PetscInt **oidxs,PetscInt **ogidxs)
690 {
691   PetscInt      *owners = map->range;
692   PetscInt       n      = map->n;
693   PetscSF        sf;
694   PetscInt      *lidxs,*work = NULL;
695   PetscSFNode   *ridxs;
696   PetscMPIInt    rank;
697   PetscInt       r, p = 0, len = 0;
698   PetscErrorCode ierr;
699 
700   PetscFunctionBegin;
701   if (on) *on = 0;              /* squelch -Wmaybe-uninitialized */
702   /* Create SF where leaves are input idxs and roots are owned idxs (code adapted from MatZeroRowsMapLocal_Private) */
703   ierr = MPI_Comm_rank(map->comm,&rank);CHKERRQ(ierr);
704   ierr = PetscMalloc1(n,&lidxs);CHKERRQ(ierr);
705   for (r = 0; r < n; ++r) lidxs[r] = -1;
706   ierr = PetscMalloc1(N,&ridxs);CHKERRQ(ierr);
707   for (r = 0; r < N; ++r) {
708     const PetscInt idx = idxs[r];
709     if (idx < 0 || map->N <= idx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D out of range [0,%D)",idx,map->N);
710     if (idx < owners[p] || owners[p+1] <= idx) { /* short-circuit the search if the last p owns this idx too */
711       ierr = PetscLayoutFindOwner(map,idx,&p);CHKERRQ(ierr);
712     }
713     ridxs[r].rank = p;
714     ridxs[r].index = idxs[r] - owners[p];
715   }
716   ierr = PetscSFCreate(map->comm,&sf);CHKERRQ(ierr);
717   ierr = PetscSFSetGraph(sf,n,N,NULL,PETSC_OWN_POINTER,ridxs,PETSC_OWN_POINTER);CHKERRQ(ierr);
718   ierr = PetscSFReduceBegin(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
719   ierr = PetscSFReduceEnd(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
720   if (ogidxs) { /* communicate global idxs */
721     PetscInt cum = 0,start,*work2;
722 
723     ierr = PetscMalloc1(n,&work);CHKERRQ(ierr);
724     ierr = PetscCalloc1(N,&work2);CHKERRQ(ierr);
725     for (r = 0; r < N; ++r) if (idxs[r] >=0) cum++;
726     ierr = MPI_Scan(&cum,&start,1,MPIU_INT,MPI_SUM,map->comm);CHKERRQ(ierr);
727     start -= cum;
728     cum = 0;
729     for (r = 0; r < N; ++r) if (idxs[r] >=0) work2[r] = start+cum++;
730     ierr = PetscSFReduceBegin(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
731     ierr = PetscSFReduceEnd(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
732     ierr = PetscFree(work2);CHKERRQ(ierr);
733   }
734   ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
735   /* Compress and put in indices */
736   for (r = 0; r < n; ++r)
737     if (lidxs[r] >= 0) {
738       if (work) work[len] = work[r];
739       lidxs[len++] = r;
740     }
741   if (on) *on = len;
742   if (oidxs) *oidxs = lidxs;
743   if (ogidxs) *ogidxs = work;
744   PetscFunctionReturn(0);
745 }
746 
747 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat,IS irow,IS icol,MatReuse scall,Mat *newmat)
748 {
749   Mat               locmat,newlocmat;
750   Mat_IS            *newmatis;
751 #if defined(PETSC_USE_DEBUG)
752   Vec               rtest,ltest;
753   const PetscScalar *array;
754 #endif
755   const PetscInt    *idxs;
756   PetscInt          i,m,n;
757   PetscErrorCode    ierr;
758 
759   PetscFunctionBegin;
760   if (scall == MAT_REUSE_MATRIX) {
761     PetscBool ismatis;
762 
763     ierr = PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);CHKERRQ(ierr);
764     if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Not of MATIS type");
765     newmatis = (Mat_IS*)(*newmat)->data;
766     if (!newmatis->getsub_ris) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local row IS");
767     if (!newmatis->getsub_cis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local col IS");
768   }
769   /* irow and icol may not have duplicate entries */
770 #if defined(PETSC_USE_DEBUG)
771   ierr = MatCreateVecs(mat,&ltest,&rtest);CHKERRQ(ierr);
772   ierr = ISGetLocalSize(irow,&n);CHKERRQ(ierr);
773   ierr = ISGetIndices(irow,&idxs);CHKERRQ(ierr);
774   for (i=0;i<n;i++) {
775     ierr = VecSetValue(rtest,idxs[i],1.0,ADD_VALUES);CHKERRQ(ierr);
776   }
777   ierr = VecAssemblyBegin(rtest);CHKERRQ(ierr);
778   ierr = VecAssemblyEnd(rtest);CHKERRQ(ierr);
779   ierr = VecGetLocalSize(rtest,&n);CHKERRQ(ierr);
780   ierr = VecGetOwnershipRange(rtest,&m,NULL);CHKERRQ(ierr);
781   ierr = VecGetArrayRead(rtest,&array);CHKERRQ(ierr);
782   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]));
783   ierr = VecRestoreArrayRead(rtest,&array);CHKERRQ(ierr);
784   ierr = ISRestoreIndices(irow,&idxs);CHKERRQ(ierr);
785   ierr = ISGetLocalSize(icol,&n);CHKERRQ(ierr);
786   ierr = ISGetIndices(icol,&idxs);CHKERRQ(ierr);
787   for (i=0;i<n;i++) {
788     ierr = VecSetValue(ltest,idxs[i],1.0,ADD_VALUES);CHKERRQ(ierr);
789   }
790   ierr = VecAssemblyBegin(ltest);CHKERRQ(ierr);
791   ierr = VecAssemblyEnd(ltest);CHKERRQ(ierr);
792   ierr = VecGetLocalSize(ltest,&n);CHKERRQ(ierr);
793   ierr = VecGetOwnershipRange(ltest,&m,NULL);CHKERRQ(ierr);
794   ierr = VecGetArrayRead(ltest,&array);CHKERRQ(ierr);
795   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]));
796   ierr = VecRestoreArrayRead(ltest,&array);CHKERRQ(ierr);
797   ierr = ISRestoreIndices(icol,&idxs);CHKERRQ(ierr);
798   ierr = VecDestroy(&rtest);CHKERRQ(ierr);
799   ierr = VecDestroy(&ltest);CHKERRQ(ierr);
800 #endif
801   if (scall == MAT_INITIAL_MATRIX) {
802     Mat_IS                 *matis = (Mat_IS*)mat->data;
803     ISLocalToGlobalMapping rl2g;
804     IS                     is;
805     PetscInt               *lidxs,*lgidxs,*newgidxs;
806     PetscInt               ll,newloc,irbs,icbs,arbs,acbs,rbs,cbs;
807     MPI_Comm               comm;
808 
809     ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
810     ierr = MatGetBlockSizes(mat,&arbs,&acbs);CHKERRQ(ierr);
811     ierr = ISGetBlockSize(irow,&irbs);CHKERRQ(ierr);
812     ierr = ISGetBlockSize(icol,&icbs);CHKERRQ(ierr);
813     rbs  = arbs == irbs ? irbs : 1;
814     cbs  = acbs == icbs ? icbs : 1;
815     ierr = ISGetLocalSize(irow,&m);CHKERRQ(ierr);
816     ierr = ISGetLocalSize(icol,&n);CHKERRQ(ierr);
817     ierr = MatCreate(comm,newmat);CHKERRQ(ierr);
818     ierr = MatSetType(*newmat,MATIS);CHKERRQ(ierr);
819     ierr = MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
820     ierr = MatSetBlockSizes(*newmat,rbs,cbs);CHKERRQ(ierr);
821     /* communicate irow to their owners in the layout */
822     ierr = ISGetIndices(irow,&idxs);CHKERRQ(ierr);
823     ierr = PetscLayoutMapLocal_Private(mat->rmap,m,idxs,&ll,&lidxs,&lgidxs);CHKERRQ(ierr);
824     ierr = ISRestoreIndices(irow,&idxs);CHKERRQ(ierr);
825     ierr = MatISSetUpSF(mat);CHKERRQ(ierr);
826     ierr = PetscMemzero(matis->sf_rootdata,matis->sf->nroots*sizeof(PetscInt));CHKERRQ(ierr);
827     for (i=0;i<ll;i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i]+1;
828     ierr = PetscFree(lidxs);CHKERRQ(ierr);
829     ierr = PetscFree(lgidxs);CHKERRQ(ierr);
830     ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
831     ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
832     for (i=0,newloc=0;i<matis->sf->nleaves;i++) if (matis->sf_leafdata[i]) newloc++;
833     ierr = PetscMalloc1(newloc,&newgidxs);CHKERRQ(ierr);
834     ierr = PetscMalloc1(newloc,&lidxs);CHKERRQ(ierr);
835     for (i=0,newloc=0;i<matis->sf->nleaves;i++)
836       if (matis->sf_leafdata[i]) {
837         lidxs[newloc] = i;
838         newgidxs[newloc++] = matis->sf_leafdata[i]-1;
839       }
840     ierr = ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
841     ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
842     ierr = ISLocalToGlobalMappingSetBlockSize(rl2g,rbs);CHKERRQ(ierr);
843     ierr = ISDestroy(&is);CHKERRQ(ierr);
844     /* local is to extract local submatrix */
845     newmatis = (Mat_IS*)(*newmat)->data;
846     ierr = ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_ris);CHKERRQ(ierr);
847     if (mat->congruentlayouts == -1) { /* first time we compare rows and cols layouts */
848       PetscBool cong;
849 
850       ierr = PetscLayoutCompare(mat->rmap,mat->cmap,&cong);CHKERRQ(ierr);
851       if (cong) mat->congruentlayouts = 1;
852       else      mat->congruentlayouts = 0;
853     }
854     if (mat->congruentlayouts && irow == icol && matis->csf == matis->sf) {
855       ierr = MatSetLocalToGlobalMapping(*newmat,rl2g,rl2g);CHKERRQ(ierr);
856       ierr = PetscObjectReference((PetscObject)newmatis->getsub_ris);CHKERRQ(ierr);
857       newmatis->getsub_cis = newmatis->getsub_ris;
858     } else {
859       ISLocalToGlobalMapping cl2g;
860 
861       /* communicate icol to their owners in the layout */
862       ierr = ISGetIndices(icol,&idxs);CHKERRQ(ierr);
863       ierr = PetscLayoutMapLocal_Private(mat->cmap,n,idxs,&ll,&lidxs,&lgidxs);CHKERRQ(ierr);
864       ierr = ISRestoreIndices(icol,&idxs);CHKERRQ(ierr);
865       ierr = PetscMemzero(matis->csf_rootdata,matis->csf->nroots*sizeof(PetscInt));CHKERRQ(ierr);
866       for (i=0;i<ll;i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i]+1;
867       ierr = PetscFree(lidxs);CHKERRQ(ierr);
868       ierr = PetscFree(lgidxs);CHKERRQ(ierr);
869       ierr = PetscSFBcastBegin(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);CHKERRQ(ierr);
870       ierr = PetscSFBcastEnd(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);CHKERRQ(ierr);
871       for (i=0,newloc=0;i<matis->csf->nleaves;i++) if (matis->csf_leafdata[i]) newloc++;
872       ierr = PetscMalloc1(newloc,&newgidxs);CHKERRQ(ierr);
873       ierr = PetscMalloc1(newloc,&lidxs);CHKERRQ(ierr);
874       for (i=0,newloc=0;i<matis->csf->nleaves;i++)
875         if (matis->csf_leafdata[i]) {
876           lidxs[newloc] = i;
877           newgidxs[newloc++] = matis->csf_leafdata[i]-1;
878         }
879       ierr = ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
880       ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
881       ierr = ISLocalToGlobalMappingSetBlockSize(cl2g,cbs);CHKERRQ(ierr);
882       ierr = ISDestroy(&is);CHKERRQ(ierr);
883       /* local is to extract local submatrix */
884       ierr = ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_cis);CHKERRQ(ierr);
885       ierr = MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g);CHKERRQ(ierr);
886       ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
887     }
888     ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
889   } else {
890     ierr = MatISGetLocalMat(*newmat,&newlocmat);CHKERRQ(ierr);
891   }
892   ierr = MatISGetLocalMat(mat,&locmat);CHKERRQ(ierr);
893   newmatis = (Mat_IS*)(*newmat)->data;
894   ierr = MatCreateSubMatrix(locmat,newmatis->getsub_ris,newmatis->getsub_cis,scall,&newlocmat);CHKERRQ(ierr);
895   if (scall == MAT_INITIAL_MATRIX) {
896     ierr = MatISSetLocalMat(*newmat,newlocmat);CHKERRQ(ierr);
897     ierr = MatDestroy(&newlocmat);CHKERRQ(ierr);
898   }
899   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
900   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
901   PetscFunctionReturn(0);
902 }
903 
904 static PetscErrorCode MatCopy_IS(Mat A,Mat B,MatStructure str)
905 {
906   Mat_IS         *a = (Mat_IS*)A->data,*b;
907   PetscBool      ismatis;
908   PetscErrorCode ierr;
909 
910   PetscFunctionBegin;
911   ierr = PetscObjectTypeCompare((PetscObject)B,MATIS,&ismatis);CHKERRQ(ierr);
912   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Need to be implemented");
913   b = (Mat_IS*)B->data;
914   ierr = MatCopy(a->A,b->A,str);CHKERRQ(ierr);
915   ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr);
916   PetscFunctionReturn(0);
917 }
918 
919 static PetscErrorCode MatMissingDiagonal_IS(Mat A,PetscBool  *missing,PetscInt *d)
920 {
921   Vec               v;
922   const PetscScalar *array;
923   PetscInt          i,n;
924   PetscErrorCode    ierr;
925 
926   PetscFunctionBegin;
927   *missing = PETSC_FALSE;
928   ierr = MatCreateVecs(A,NULL,&v);CHKERRQ(ierr);
929   ierr = MatGetDiagonal(A,v);CHKERRQ(ierr);
930   ierr = VecGetLocalSize(v,&n);CHKERRQ(ierr);
931   ierr = VecGetArrayRead(v,&array);CHKERRQ(ierr);
932   for (i=0;i<n;i++) if (array[i] == 0.) break;
933   ierr = VecRestoreArrayRead(v,&array);CHKERRQ(ierr);
934   ierr = VecDestroy(&v);CHKERRQ(ierr);
935   if (i != n) *missing = PETSC_TRUE;
936   if (d) {
937     *d = -1;
938     if (*missing) {
939       PetscInt rstart;
940       ierr = MatGetOwnershipRange(A,&rstart,NULL);CHKERRQ(ierr);
941       *d = i+rstart;
942     }
943   }
944   PetscFunctionReturn(0);
945 }
946 
947 static PetscErrorCode MatISSetUpSF_IS(Mat B)
948 {
949   Mat_IS         *matis = (Mat_IS*)(B->data);
950   const PetscInt *gidxs;
951   PetscInt       nleaves;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955   if (matis->sf) PetscFunctionReturn(0);
956   ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);CHKERRQ(ierr);
957   ierr = ISLocalToGlobalMappingGetIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr);
958   ierr = ISLocalToGlobalMappingGetSize(B->rmap->mapping,&nleaves);CHKERRQ(ierr);
959   ierr = PetscSFSetGraphLayout(matis->sf,B->rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr);
960   ierr = ISLocalToGlobalMappingRestoreIndices(B->rmap->mapping,&gidxs);CHKERRQ(ierr);
961   ierr = PetscMalloc2(matis->sf->nroots,&matis->sf_rootdata,matis->sf->nleaves,&matis->sf_leafdata);CHKERRQ(ierr);
962   if (B->rmap->mapping != B->cmap->mapping) { /* setup SF for columns */
963     ierr = ISLocalToGlobalMappingGetSize(B->cmap->mapping,&nleaves);CHKERRQ(ierr);
964     ierr = PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->csf);CHKERRQ(ierr);
965     ierr = ISLocalToGlobalMappingGetIndices(B->cmap->mapping,&gidxs);CHKERRQ(ierr);
966     ierr = PetscSFSetGraphLayout(matis->csf,B->cmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);CHKERRQ(ierr);
967     ierr = ISLocalToGlobalMappingRestoreIndices(B->cmap->mapping,&gidxs);CHKERRQ(ierr);
968     ierr = PetscMalloc2(matis->csf->nroots,&matis->csf_rootdata,matis->csf->nleaves,&matis->csf_leafdata);CHKERRQ(ierr);
969   } else {
970     matis->csf = matis->sf;
971     matis->csf_leafdata = matis->sf_leafdata;
972     matis->csf_rootdata = matis->sf_rootdata;
973   }
974   PetscFunctionReturn(0);
975 }
976 
977 /*@
978    MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.
979 
980    Collective on MPI_Comm
981 
982    Input Parameters:
983 +  B - the matrix
984 .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
985            (same value is used for all local rows)
986 .  d_nnz - array containing the number of nonzeros in the various rows of the
987            DIAGONAL portion of the local submatrix (possibly different for each row)
988            or NULL, if d_nz is used to specify the nonzero structure.
989            The size of this array is equal to the number of local rows, i.e 'm'.
990            For matrices that will be factored, you must leave room for (and set)
991            the diagonal entry even if it is zero.
992 .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
993            submatrix (same value is used for all local rows).
994 -  o_nnz - array containing the number of nonzeros in the various rows of the
995            OFF-DIAGONAL portion of the local submatrix (possibly different for
996            each row) or NULL, if o_nz is used to specify the nonzero
997            structure. The size of this array is equal to the number
998            of local rows, i.e 'm'.
999 
1000    If the *_nnz parameter is given then the *_nz parameter is ignored
1001 
1002    Level: intermediate
1003 
1004    Notes: This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
1005           from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
1006           matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1007 
1008 .keywords: matrix
1009 
1010 .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat(), MATIS
1011 @*/
1012 PetscErrorCode  MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1013 {
1014   PetscErrorCode ierr;
1015 
1016   PetscFunctionBegin;
1017   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
1018   PetscValidType(B,1);
1019   ierr = PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));CHKERRQ(ierr);
1020   PetscFunctionReturn(0);
1021 }
1022 
1023 static PetscErrorCode  MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1024 {
1025   Mat_IS         *matis = (Mat_IS*)(B->data);
1026   PetscInt       bs,i,nlocalcols;
1027   PetscErrorCode ierr;
1028 
1029   PetscFunctionBegin;
1030   if (!matis->A) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping");
1031   ierr = MatISSetUpSF(B);CHKERRQ(ierr);
1032 
1033   if (!d_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nz;
1034   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nnz[i];
1035 
1036   if (!o_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nz;
1037   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nnz[i];
1038 
1039   ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1040   ierr = MatGetSize(matis->A,NULL,&nlocalcols);CHKERRQ(ierr);
1041   ierr = MatGetBlockSize(matis->A,&bs);CHKERRQ(ierr);
1042   ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1043 
1044   for (i=0;i<matis->sf->nleaves;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols);
1045   ierr = MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);CHKERRQ(ierr);
1046 #if defined(PETSC_HAVE_HYPRE)
1047   ierr = MatHYPRESetPreallocation(matis->A,0,matis->sf_leafdata,0,NULL);CHKERRQ(ierr);
1048 #endif
1049 
1050   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs;
1051   ierr = MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
1052 
1053   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i]-i;
1054   ierr = MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);CHKERRQ(ierr);
1055 
1056   /* for other matrix types */
1057   ierr = MatSetUp(matis->A);CHKERRQ(ierr);
1058   PetscFunctionReturn(0);
1059 }
1060 
1061 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1062 {
1063   Mat_IS          *matis = (Mat_IS*)(A->data);
1064   PetscInt        *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership;
1065   const PetscInt  *global_indices_r,*global_indices_c;
1066   PetscInt        i,j,bs,rows,cols;
1067   PetscInt        lrows,lcols;
1068   PetscInt        local_rows,local_cols;
1069   PetscMPIInt     nsubdomains;
1070   PetscBool       isdense,issbaij;
1071   PetscErrorCode  ierr;
1072 
1073   PetscFunctionBegin;
1074   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&nsubdomains);CHKERRQ(ierr);
1075   ierr = MatGetSize(A,&rows,&cols);CHKERRQ(ierr);
1076   ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr);
1077   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
1078   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);CHKERRQ(ierr);
1079   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
1080   ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr);
1081   if (A->rmap->mapping != A->cmap->mapping) {
1082     ierr = ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&global_indices_c);CHKERRQ(ierr);
1083   } else {
1084     global_indices_c = global_indices_r;
1085   }
1086 
1087   if (issbaij) {
1088     ierr = MatGetRowUpperTriangular(matis->A);CHKERRQ(ierr);
1089   }
1090   /*
1091      An SF reduce is needed to sum up properly on shared rows.
1092      Note that generally preallocation is not exact, since it overestimates nonzeros
1093   */
1094   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
1095   ierr = MatGetLocalSize(A,&lrows,&lcols);CHKERRQ(ierr);
1096   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);CHKERRQ(ierr);
1097   /* All processes need to compute entire row ownership */
1098   ierr = PetscMalloc1(rows,&row_ownership);CHKERRQ(ierr);
1099   ierr = MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr);
1100   for (i=0;i<nsubdomains;i++) {
1101     for (j=mat_ranges[i];j<mat_ranges[i+1];j++) {
1102       row_ownership[j] = i;
1103     }
1104   }
1105   ierr = MatGetOwnershipRangesColumn(A,(const PetscInt**)&mat_ranges);CHKERRQ(ierr);
1106 
1107   /*
1108      my_dnz and my_onz contains exact contribution to preallocation from each local mat
1109      then, they will be summed up properly. This way, preallocation is always sufficient
1110   */
1111   ierr = PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);CHKERRQ(ierr);
1112   /* preallocation as a MATAIJ */
1113   if (isdense) { /* special case for dense local matrices */
1114     for (i=0;i<local_rows;i++) {
1115       PetscInt owner = row_ownership[global_indices_r[i]];
1116       for (j=0;j<local_cols;j++) {
1117         PetscInt index_col = global_indices_c[j];
1118         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1119           my_dnz[i] += 1;
1120         } else { /* offdiag block */
1121           my_onz[i] += 1;
1122         }
1123       }
1124     }
1125   } else if (matis->A->ops->getrowij) {
1126     const PetscInt *ii,*jj,*jptr;
1127     PetscBool      done;
1128     ierr = MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);CHKERRQ(ierr);
1129     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
1130     jptr = jj;
1131     for (i=0;i<local_rows;i++) {
1132       PetscInt index_row = global_indices_r[i];
1133       for (j=0;j<ii[i+1]-ii[i];j++,jptr++) {
1134         PetscInt owner = row_ownership[index_row];
1135         PetscInt index_col = global_indices_c[*jptr];
1136         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1137           my_dnz[i] += 1;
1138         } else { /* offdiag block */
1139           my_onz[i] += 1;
1140         }
1141         /* same as before, interchanging rows and cols */
1142         if (issbaij && index_col != index_row) {
1143           owner = row_ownership[index_col];
1144           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1145             my_dnz[*jptr] += 1;
1146           } else {
1147             my_onz[*jptr] += 1;
1148           }
1149         }
1150       }
1151     }
1152     ierr = MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);CHKERRQ(ierr);
1153     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
1154   } else { /* loop over rows and use MatGetRow */
1155     for (i=0;i<local_rows;i++) {
1156       const PetscInt *cols;
1157       PetscInt       ncols,index_row = global_indices_r[i];
1158       ierr = MatGetRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
1159       for (j=0;j<ncols;j++) {
1160         PetscInt owner = row_ownership[index_row];
1161         PetscInt index_col = global_indices_c[cols[j]];
1162         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1163           my_dnz[i] += 1;
1164         } else { /* offdiag block */
1165           my_onz[i] += 1;
1166         }
1167         /* same as before, interchanging rows and cols */
1168         if (issbaij && index_col != index_row) {
1169           owner = row_ownership[index_col];
1170           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1171             my_dnz[cols[j]] += 1;
1172           } else {
1173             my_onz[cols[j]] += 1;
1174           }
1175         }
1176       }
1177       ierr = MatRestoreRow(matis->A,i,&ncols,&cols,NULL);CHKERRQ(ierr);
1178     }
1179   }
1180   if (global_indices_c != global_indices_r) {
1181     ierr = ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&global_indices_c);CHKERRQ(ierr);
1182   }
1183   ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_r);CHKERRQ(ierr);
1184   ierr = PetscFree(row_ownership);CHKERRQ(ierr);
1185 
1186   /* Reduce my_dnz and my_onz */
1187   if (maxreduce) {
1188     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
1189     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
1190     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);CHKERRQ(ierr);
1191     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);CHKERRQ(ierr);
1192   } else {
1193     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
1194     ierr = PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
1195     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);CHKERRQ(ierr);
1196     ierr = PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);CHKERRQ(ierr);
1197   }
1198   ierr = PetscFree2(my_dnz,my_onz);CHKERRQ(ierr);
1199 
1200   /* Resize preallocation if overestimated */
1201   for (i=0;i<lrows;i++) {
1202     dnz[i] = PetscMin(dnz[i],lcols);
1203     onz[i] = PetscMin(onz[i],cols-lcols);
1204   }
1205 
1206   /* Set preallocation */
1207   ierr = MatSeqAIJSetPreallocation(B,0,dnz);CHKERRQ(ierr);
1208   ierr = MatMPIAIJSetPreallocation(B,0,dnz,0,onz);CHKERRQ(ierr);
1209   for (i=0;i<lrows/bs;i++) {
1210     dnz[i] = dnz[i*bs]/bs;
1211     onz[i] = onz[i*bs]/bs;
1212   }
1213   ierr = MatSeqBAIJSetPreallocation(B,bs,0,dnz);CHKERRQ(ierr);
1214   ierr = MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
1215   ierr = MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);CHKERRQ(ierr);
1216   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
1217   if (issbaij) {
1218     ierr = MatRestoreRowUpperTriangular(matis->A);CHKERRQ(ierr);
1219   }
1220   PetscFunctionReturn(0);
1221 }
1222 
1223 static PetscErrorCode MatISGetMPIXAIJ_IS(Mat mat, MatReuse reuse, Mat *M)
1224 {
1225   Mat_IS         *matis = (Mat_IS*)(mat->data);
1226   Mat            local_mat;
1227   /* info on mat */
1228   PetscInt       bs,rows,cols,lrows,lcols;
1229   PetscInt       local_rows,local_cols;
1230   PetscBool      isseqdense,isseqsbaij,isseqaij,isseqbaij;
1231 #if defined (PETSC_USE_DEBUG)
1232   PetscBool      lb[4],bb[4];
1233 #endif
1234   PetscMPIInt    nsubdomains;
1235   /* values insertion */
1236   PetscScalar    *array;
1237   /* work */
1238   PetscErrorCode ierr;
1239 
1240   PetscFunctionBegin;
1241   /* get info from mat */
1242   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)mat),&nsubdomains);CHKERRQ(ierr);
1243   if (nsubdomains == 1) {
1244     Mat            B;
1245     IS             rows,cols;
1246     IS             irows,icols;
1247     const PetscInt *ridxs,*cidxs;
1248 
1249     ierr = ISLocalToGlobalMappingGetIndices(mat->rmap->mapping,&ridxs);CHKERRQ(ierr);
1250     ierr = ISLocalToGlobalMappingGetIndices(mat->cmap->mapping,&cidxs);CHKERRQ(ierr);
1251     ierr = ISCreateGeneral(PETSC_COMM_SELF,mat->rmap->n,ridxs,PETSC_USE_POINTER,&rows);CHKERRQ(ierr);
1252     ierr = ISCreateGeneral(PETSC_COMM_SELF,mat->cmap->n,cidxs,PETSC_USE_POINTER,&cols);CHKERRQ(ierr);
1253     ierr = ISSetPermutation(rows);CHKERRQ(ierr);
1254     ierr = ISSetPermutation(cols);CHKERRQ(ierr);
1255     ierr = ISInvertPermutation(rows,mat->rmap->n,&irows);CHKERRQ(ierr);
1256     ierr = ISInvertPermutation(cols,mat->cmap->n,&icols);CHKERRQ(ierr);
1257     ierr = ISLocalToGlobalMappingRestoreIndices(mat->rmap->mapping,&ridxs);CHKERRQ(ierr);
1258     ierr = ISLocalToGlobalMappingRestoreIndices(mat->cmap->mapping,&cidxs);CHKERRQ(ierr);
1259     ierr = ISDestroy(&cols);CHKERRQ(ierr);
1260     ierr = ISDestroy(&rows);CHKERRQ(ierr);
1261     ierr = MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
1262     ierr = MatCreateSubMatrix(B,irows,icols,reuse,M);CHKERRQ(ierr);
1263     ierr = MatDestroy(&B);CHKERRQ(ierr);
1264     ierr = ISDestroy(&icols);CHKERRQ(ierr);
1265     ierr = ISDestroy(&irows);CHKERRQ(ierr);
1266     PetscFunctionReturn(0);
1267   }
1268   ierr = MatGetSize(mat,&rows,&cols);CHKERRQ(ierr);
1269   ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr);
1270   ierr = MatGetLocalSize(mat,&lrows,&lcols);CHKERRQ(ierr);
1271   ierr = MatGetSize(matis->A,&local_rows,&local_cols);CHKERRQ(ierr);
1272   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isseqdense);CHKERRQ(ierr);
1273   ierr = PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);CHKERRQ(ierr);
1274   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQBAIJ,&isseqbaij);CHKERRQ(ierr);
1275   ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&isseqsbaij);CHKERRQ(ierr);
1276   if (!isseqdense && !isseqaij && !isseqbaij && !isseqsbaij) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(matis->A))->type_name);
1277 #if defined (PETSC_USE_DEBUG)
1278   lb[0] = isseqdense;
1279   lb[1] = isseqaij;
1280   lb[2] = isseqbaij;
1281   lb[3] = isseqsbaij;
1282   ierr = MPIU_Allreduce(lb,bb,4,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));CHKERRQ(ierr);
1283   if (!bb[0] && !bb[1] && !bb[2] && !bb[3]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Local matrices must have the same type");
1284 #endif
1285 
1286   if (reuse == MAT_INITIAL_MATRIX) {
1287     ierr = MatCreate(PetscObjectComm((PetscObject)mat),M);CHKERRQ(ierr);
1288     ierr = MatSetSizes(*M,lrows,lcols,rows,cols);CHKERRQ(ierr);
1289     if (!isseqsbaij) {
1290       ierr = MatSetType(*M,MATAIJ);CHKERRQ(ierr);
1291     } else {
1292       ierr = MatSetType(*M,MATSBAIJ);CHKERRQ(ierr);
1293     }
1294     ierr = MatSetBlockSize(*M,bs);CHKERRQ(ierr);
1295     ierr = MatISSetMPIXAIJPreallocation_Private(mat,*M,PETSC_FALSE);CHKERRQ(ierr);
1296   } else {
1297     PetscInt mbs,mrows,mcols,mlrows,mlcols;
1298     /* some checks */
1299     ierr = MatGetBlockSize(*M,&mbs);CHKERRQ(ierr);
1300     ierr = MatGetSize(*M,&mrows,&mcols);CHKERRQ(ierr);
1301     ierr = MatGetLocalSize(*M,&mlrows,&mlcols);CHKERRQ(ierr);
1302     if (mrows != rows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows);
1303     if (mcols != cols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols);
1304     if (mlrows != lrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows);
1305     if (mlcols != lcols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols);
1306     if (mbs != bs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong block size (%d != %d)",bs,mbs);
1307     ierr = MatZeroEntries(*M);CHKERRQ(ierr);
1308   }
1309 
1310   if (isseqsbaij) {
1311     ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&local_mat);CHKERRQ(ierr);
1312   } else {
1313     ierr = PetscObjectReference((PetscObject)matis->A);CHKERRQ(ierr);
1314     local_mat = matis->A;
1315   }
1316 
1317   /* Set values */
1318   ierr = MatSetLocalToGlobalMapping(*M,mat->rmap->mapping,mat->cmap->mapping);CHKERRQ(ierr);
1319   if (isseqdense) { /* special case for dense local matrices */
1320     PetscInt i,*dummy;
1321 
1322     ierr = PetscMalloc1(PetscMax(local_rows,local_cols),&dummy);CHKERRQ(ierr);
1323     for (i=0;i<PetscMax(local_rows,local_cols);i++) dummy[i] = i;
1324     ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
1325     ierr = MatDenseGetArray(local_mat,&array);CHKERRQ(ierr);
1326     ierr = MatSetValuesLocal(*M,local_rows,dummy,local_cols,dummy,array,ADD_VALUES);CHKERRQ(ierr);
1327     ierr = MatDenseRestoreArray(local_mat,&array);CHKERRQ(ierr);
1328     ierr = PetscFree(dummy);CHKERRQ(ierr);
1329   } else if (isseqaij) {
1330     PetscInt  i,nvtxs,*xadj,*adjncy;
1331     PetscBool done;
1332 
1333     ierr = MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
1334     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
1335     ierr = MatSeqAIJGetArray(local_mat,&array);CHKERRQ(ierr);
1336     for (i=0;i<nvtxs;i++) {
1337       ierr = MatSetValuesLocal(*M,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],array+xadj[i],ADD_VALUES);CHKERRQ(ierr);
1338     }
1339     ierr = MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);CHKERRQ(ierr);
1340     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
1341     ierr = MatSeqAIJRestoreArray(local_mat,&array);CHKERRQ(ierr);
1342   } else { /* very basic values insertion for all other matrix types */
1343     PetscInt i;
1344 
1345     for (i=0;i<local_rows;i++) {
1346       PetscInt       j;
1347       const PetscInt *local_indices_cols;
1348 
1349       ierr = MatGetRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr);
1350       ierr = MatSetValuesLocal(*M,1,&i,j,local_indices_cols,array,ADD_VALUES);CHKERRQ(ierr);
1351       ierr = MatRestoreRow(local_mat,i,&j,&local_indices_cols,(const PetscScalar**)&array);CHKERRQ(ierr);
1352     }
1353   }
1354   ierr = MatAssemblyBegin(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1355   ierr = MatDestroy(&local_mat);CHKERRQ(ierr);
1356   ierr = MatAssemblyEnd(*M,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1357   if (isseqdense) {
1358     ierr = MatSetOption(*M,MAT_ROW_ORIENTED,PETSC_TRUE);CHKERRQ(ierr);
1359   }
1360   PetscFunctionReturn(0);
1361 }
1362 
1363 /*@
1364     MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format
1365 
1366   Input Parameter:
1367 .  mat - the matrix (should be of type MATIS)
1368 .  reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
1369 
1370   Output Parameter:
1371 .  newmat - the matrix in AIJ format
1372 
1373   Level: developer
1374 
1375   Notes: mat and *newmat cannot be the same object when MAT_REUSE_MATRIX is requested.
1376 
1377 .seealso: MATIS
1378 @*/
1379 PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
1380 {
1381   PetscErrorCode ierr;
1382 
1383   PetscFunctionBegin;
1384   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1385   PetscValidLogicalCollectiveEnum(mat,reuse,2);
1386   PetscValidPointer(newmat,3);
1387   if (reuse != MAT_INITIAL_MATRIX) {
1388     PetscValidHeaderSpecific(*newmat,MAT_CLASSID,3);
1389     PetscCheckSameComm(mat,1,*newmat,3);
1390     if (mat == *newmat) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix");
1391   }
1392   ierr = PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatReuse,Mat*),(mat,reuse,newmat));CHKERRQ(ierr);
1393   PetscFunctionReturn(0);
1394 }
1395 
1396 PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat)
1397 {
1398   PetscErrorCode ierr;
1399   Mat_IS         *matis = (Mat_IS*)(mat->data);
1400   PetscInt       bs,m,n,M,N;
1401   Mat            B,localmat;
1402 
1403   PetscFunctionBegin;
1404   ierr = MatGetBlockSize(mat,&bs);CHKERRQ(ierr);
1405   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
1406   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
1407   ierr = MatCreateIS(PetscObjectComm((PetscObject)mat),bs,m,n,M,N,mat->rmap->mapping,mat->cmap->mapping,&B);CHKERRQ(ierr);
1408   ierr = MatDuplicate(matis->A,op,&localmat);CHKERRQ(ierr);
1409   ierr = MatISSetLocalMat(B,localmat);CHKERRQ(ierr);
1410   ierr = MatDestroy(&localmat);CHKERRQ(ierr);
1411   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1412   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1413   *newmat = B;
1414   PetscFunctionReturn(0);
1415 }
1416 
1417 static PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool  *flg)
1418 {
1419   PetscErrorCode ierr;
1420   Mat_IS         *matis = (Mat_IS*)A->data;
1421   PetscBool      local_sym;
1422 
1423   PetscFunctionBegin;
1424   ierr = MatIsHermitian(matis->A,tol,&local_sym);CHKERRQ(ierr);
1425   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 static PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool  *flg)
1430 {
1431   PetscErrorCode ierr;
1432   Mat_IS         *matis = (Mat_IS*)A->data;
1433   PetscBool      local_sym;
1434 
1435   PetscFunctionBegin;
1436   ierr = MatIsSymmetric(matis->A,tol,&local_sym);CHKERRQ(ierr);
1437   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1438   PetscFunctionReturn(0);
1439 }
1440 
1441 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A,PetscBool  *flg)
1442 {
1443   PetscErrorCode ierr;
1444   Mat_IS         *matis = (Mat_IS*)A->data;
1445   PetscBool      local_sym;
1446 
1447   PetscFunctionBegin;
1448   if (A->rmap->mapping != A->cmap->mapping) {
1449     *flg = PETSC_FALSE;
1450     PetscFunctionReturn(0);
1451   }
1452   ierr = MatIsStructurallySymmetric(matis->A,&local_sym);CHKERRQ(ierr);
1453   ierr = MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1454   PetscFunctionReturn(0);
1455 }
1456 
1457 static PetscErrorCode MatDestroy_IS(Mat A)
1458 {
1459   PetscErrorCode ierr;
1460   Mat_IS         *b = (Mat_IS*)A->data;
1461 
1462   PetscFunctionBegin;
1463   ierr = MatDestroy(&b->A);CHKERRQ(ierr);
1464   ierr = VecScatterDestroy(&b->cctx);CHKERRQ(ierr);
1465   ierr = VecScatterDestroy(&b->rctx);CHKERRQ(ierr);
1466   ierr = VecDestroy(&b->x);CHKERRQ(ierr);
1467   ierr = VecDestroy(&b->y);CHKERRQ(ierr);
1468   ierr = VecDestroy(&b->counter);CHKERRQ(ierr);
1469   ierr = ISDestroy(&b->getsub_ris);CHKERRQ(ierr);
1470   ierr = ISDestroy(&b->getsub_cis);CHKERRQ(ierr);
1471   if (b->sf != b->csf) {
1472     ierr = PetscSFDestroy(&b->csf);CHKERRQ(ierr);
1473     ierr = PetscFree2(b->csf_rootdata,b->csf_leafdata);CHKERRQ(ierr);
1474   }
1475   ierr = PetscSFDestroy(&b->sf);CHKERRQ(ierr);
1476   ierr = PetscFree2(b->sf_rootdata,b->sf_leafdata);CHKERRQ(ierr);
1477   ierr = PetscFree(A->data);CHKERRQ(ierr);
1478   ierr = PetscObjectChangeTypeName((PetscObject)A,0);CHKERRQ(ierr);
1479   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);CHKERRQ(ierr);
1480   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);CHKERRQ(ierr);
1481   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);CHKERRQ(ierr);
1482   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);CHKERRQ(ierr);
1483   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetUpSF_C",NULL);CHKERRQ(ierr);
1484   PetscFunctionReturn(0);
1485 }
1486 
1487 static PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
1488 {
1489   PetscErrorCode ierr;
1490   Mat_IS         *is  = (Mat_IS*)A->data;
1491   PetscScalar    zero = 0.0;
1492 
1493   PetscFunctionBegin;
1494   /*  scatter the global vector x into the local work vector */
1495   ierr = VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1496   ierr = VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1497 
1498   /* multiply the local matrix */
1499   ierr = MatMult(is->A,is->x,is->y);CHKERRQ(ierr);
1500 
1501   /* scatter product back into global memory */
1502   ierr = VecSet(y,zero);CHKERRQ(ierr);
1503   ierr = VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1504   ierr = VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1505   PetscFunctionReturn(0);
1506 }
1507 
1508 static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
1509 {
1510   Vec            temp_vec;
1511   PetscErrorCode ierr;
1512 
1513   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
1514   if (v3 != v2) {
1515     ierr = MatMult(A,v1,v3);CHKERRQ(ierr);
1516     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
1517   } else {
1518     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
1519     ierr = MatMult(A,v1,temp_vec);CHKERRQ(ierr);
1520     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
1521     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
1522     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
1523   }
1524   PetscFunctionReturn(0);
1525 }
1526 
1527 static PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x)
1528 {
1529   Mat_IS         *is = (Mat_IS*)A->data;
1530   PetscErrorCode ierr;
1531 
1532   PetscFunctionBegin;
1533   /*  scatter the global vector x into the local work vector */
1534   ierr = VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1535   ierr = VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1536 
1537   /* multiply the local matrix */
1538   ierr = MatMultTranspose(is->A,is->y,is->x);CHKERRQ(ierr);
1539 
1540   /* scatter product back into global vector */
1541   ierr = VecSet(x,0);CHKERRQ(ierr);
1542   ierr = VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1543   ierr = VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1544   PetscFunctionReturn(0);
1545 }
1546 
1547 static PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
1548 {
1549   Vec            temp_vec;
1550   PetscErrorCode ierr;
1551 
1552   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
1553   if (v3 != v2) {
1554     ierr = MatMultTranspose(A,v1,v3);CHKERRQ(ierr);
1555     ierr = VecAXPY(v3,1.0,v2);CHKERRQ(ierr);
1556   } else {
1557     ierr = VecDuplicate(v2,&temp_vec);CHKERRQ(ierr);
1558     ierr = MatMultTranspose(A,v1,temp_vec);CHKERRQ(ierr);
1559     ierr = VecAXPY(temp_vec,1.0,v2);CHKERRQ(ierr);
1560     ierr = VecCopy(temp_vec,v3);CHKERRQ(ierr);
1561     ierr = VecDestroy(&temp_vec);CHKERRQ(ierr);
1562   }
1563   PetscFunctionReturn(0);
1564 }
1565 
1566 static PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
1567 {
1568   Mat_IS         *a = (Mat_IS*)A->data;
1569   PetscErrorCode ierr;
1570   PetscViewer    sviewer;
1571   PetscBool      isascii,view = PETSC_TRUE;
1572 
1573   PetscFunctionBegin;
1574   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
1575   if (isascii)  {
1576     PetscViewerFormat format;
1577 
1578     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
1579     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
1580   }
1581   if (!view) PetscFunctionReturn(0);
1582   ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
1583   ierr = MatView(a->A,sviewer);CHKERRQ(ierr);
1584   ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
1585   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1586   PetscFunctionReturn(0);
1587 }
1588 
1589 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
1590 {
1591   PetscErrorCode ierr;
1592   PetscInt       nr,rbs,nc,cbs;
1593   Mat_IS         *is = (Mat_IS*)A->data;
1594   IS             from,to;
1595   Vec            cglobal,rglobal;
1596 
1597   PetscFunctionBegin;
1598   PetscCheckSameComm(A,1,rmapping,2);
1599   PetscCheckSameComm(A,1,cmapping,3);
1600   /* Destroy any previous data */
1601   ierr = VecDestroy(&is->x);CHKERRQ(ierr);
1602   ierr = VecDestroy(&is->y);CHKERRQ(ierr);
1603   ierr = VecDestroy(&is->counter);CHKERRQ(ierr);
1604   ierr = VecScatterDestroy(&is->rctx);CHKERRQ(ierr);
1605   ierr = VecScatterDestroy(&is->cctx);CHKERRQ(ierr);
1606   ierr = MatDestroy(&is->A);CHKERRQ(ierr);
1607   if (is->csf != is->sf) {
1608     ierr = PetscSFDestroy(&is->csf);CHKERRQ(ierr);
1609     ierr = PetscFree2(is->csf_rootdata,is->csf_leafdata);CHKERRQ(ierr);
1610   }
1611   ierr = PetscSFDestroy(&is->sf);CHKERRQ(ierr);
1612   ierr = PetscFree2(is->sf_rootdata,is->sf_leafdata);CHKERRQ(ierr);
1613 
1614   /* Setup Layout and set local to global maps */
1615   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1616   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1617   ierr = ISLocalToGlobalMappingGetSize(rmapping,&nr);CHKERRQ(ierr);
1618   ierr = ISLocalToGlobalMappingGetBlockSize(rmapping,&rbs);CHKERRQ(ierr);
1619   ierr = ISLocalToGlobalMappingGetSize(cmapping,&nc);CHKERRQ(ierr);
1620   ierr = ISLocalToGlobalMappingGetBlockSize(cmapping,&cbs);CHKERRQ(ierr);
1621   /* check if the two mappings are actually the same for square matrices (DOLFIN passes 2 different objects) */
1622   if (rmapping != cmapping && A->rmap->N == A->cmap->N) {
1623     PetscBool same,gsame;
1624 
1625     same = PETSC_FALSE;
1626     if (nr == nc && cbs == rbs) {
1627       const PetscInt *idxs1,*idxs2;
1628 
1629       ierr = ISLocalToGlobalMappingGetBlockIndices(rmapping,&idxs1);CHKERRQ(ierr);
1630       ierr = ISLocalToGlobalMappingGetBlockIndices(cmapping,&idxs2);CHKERRQ(ierr);
1631       ierr = PetscMemcmp(idxs1,idxs2,(nr/rbs)*sizeof(PetscInt),&same);CHKERRQ(ierr);
1632       ierr = ISLocalToGlobalMappingRestoreBlockIndices(rmapping,&idxs1);CHKERRQ(ierr);
1633       ierr = ISLocalToGlobalMappingRestoreBlockIndices(cmapping,&idxs2);CHKERRQ(ierr);
1634     }
1635     ierr = MPIU_Allreduce(&same,&gsame,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
1636     if (gsame) cmapping = rmapping;
1637   }
1638   ierr = PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);CHKERRQ(ierr);
1639   ierr = PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);CHKERRQ(ierr);
1640 
1641   /* Create the local matrix A */
1642   ierr = MatCreate(PETSC_COMM_SELF,&is->A);CHKERRQ(ierr);
1643   ierr = MatSetType(is->A,MATAIJ);CHKERRQ(ierr);
1644   ierr = MatSetSizes(is->A,nr,nc,nr,nc);CHKERRQ(ierr);
1645   ierr = MatSetBlockSizes(is->A,rbs,cbs);CHKERRQ(ierr);
1646   ierr = MatSetOptionsPrefix(is->A,((PetscObject)A)->prefix);CHKERRQ(ierr);
1647   ierr = MatAppendOptionsPrefix(is->A,"is_");CHKERRQ(ierr);
1648   ierr = MatSetFromOptions(is->A);CHKERRQ(ierr);
1649   ierr = PetscLayoutSetUp(is->A->rmap);CHKERRQ(ierr);
1650   ierr = PetscLayoutSetUp(is->A->cmap);CHKERRQ(ierr);
1651 
1652   if (!is->islocalref) { /* setup scatters and local vectors for MatMult */
1653     /* Create the local work vectors */
1654     ierr = MatCreateVecs(is->A,&is->x,&is->y);CHKERRQ(ierr);
1655 
1656     /* setup the global to local scatters */
1657     ierr = MatCreateVecs(A,&cglobal,&rglobal);CHKERRQ(ierr);
1658     ierr = ISCreateStride(PETSC_COMM_SELF,nr,0,1,&to);CHKERRQ(ierr);
1659     ierr = ISLocalToGlobalMappingApplyIS(rmapping,to,&from);CHKERRQ(ierr);
1660     ierr = VecScatterCreate(rglobal,from,is->y,to,&is->rctx);CHKERRQ(ierr);
1661     if (rmapping != cmapping) {
1662       ierr = ISDestroy(&to);CHKERRQ(ierr);
1663       ierr = ISDestroy(&from);CHKERRQ(ierr);
1664       ierr = ISCreateStride(PETSC_COMM_SELF,nc,0,1,&to);CHKERRQ(ierr);
1665       ierr = ISLocalToGlobalMappingApplyIS(cmapping,to,&from);CHKERRQ(ierr);
1666       ierr = VecScatterCreate(cglobal,from,is->x,to,&is->cctx);CHKERRQ(ierr);
1667     } else {
1668       ierr = PetscObjectReference((PetscObject)is->rctx);CHKERRQ(ierr);
1669       is->cctx = is->rctx;
1670     }
1671 
1672     /* interface counter vector (local) */
1673     ierr = VecDuplicate(is->y,&is->counter);CHKERRQ(ierr);
1674     ierr = VecSet(is->y,1.);CHKERRQ(ierr);
1675     ierr = VecScatterBegin(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1676     ierr = VecScatterEnd(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
1677     ierr = VecScatterBegin(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1678     ierr = VecScatterEnd(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1679 
1680     /* free workspace */
1681     ierr = VecDestroy(&rglobal);CHKERRQ(ierr);
1682     ierr = VecDestroy(&cglobal);CHKERRQ(ierr);
1683     ierr = ISDestroy(&to);CHKERRQ(ierr);
1684     ierr = ISDestroy(&from);CHKERRQ(ierr);
1685   }
1686   ierr = MatSetUp(A);CHKERRQ(ierr);
1687   PetscFunctionReturn(0);
1688 }
1689 
1690 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1691 {
1692   Mat_IS         *is = (Mat_IS*)mat->data;
1693   PetscErrorCode ierr;
1694 #if defined(PETSC_USE_DEBUG)
1695   PetscInt       i,zm,zn;
1696 #endif
1697   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1698 
1699   PetscFunctionBegin;
1700 #if defined(PETSC_USE_DEBUG)
1701   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);
1702   /* count negative indices */
1703   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
1704   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
1705 #endif
1706   ierr = ISGlobalToLocalMappingApply(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);CHKERRQ(ierr);
1707   ierr = ISGlobalToLocalMappingApply(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);CHKERRQ(ierr);
1708 #if defined(PETSC_USE_DEBUG)
1709   /* count negative indices (should be the same as before) */
1710   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
1711   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
1712   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");
1713   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");
1714 #endif
1715   ierr = MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
1716   PetscFunctionReturn(0);
1717 }
1718 
1719 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1720 {
1721   Mat_IS         *is = (Mat_IS*)mat->data;
1722   PetscErrorCode ierr;
1723 #if defined(PETSC_USE_DEBUG)
1724   PetscInt       i,zm,zn;
1725 #endif
1726   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1727 
1728   PetscFunctionBegin;
1729 #if defined(PETSC_USE_DEBUG)
1730   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);
1731   /* count negative indices */
1732   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
1733   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
1734 #endif
1735   ierr = ISGlobalToLocalMappingApplyBlock(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);CHKERRQ(ierr);
1736   ierr = ISGlobalToLocalMappingApplyBlock(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);CHKERRQ(ierr);
1737 #if defined(PETSC_USE_DEBUG)
1738   /* count negative indices (should be the same as before) */
1739   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
1740   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
1741   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");
1742   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");
1743 #endif
1744   ierr = MatSetValuesBlocked(is->A,m,rows_l,n,cols_l,values,addv);CHKERRQ(ierr);
1745   PetscFunctionReturn(0);
1746 }
1747 
1748 static PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1749 {
1750   PetscErrorCode ierr;
1751   Mat_IS         *is = (Mat_IS*)A->data;
1752 
1753   PetscFunctionBegin;
1754   if (is->A->rmap->mapping) {
1755     ierr = MatSetValuesLocal(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
1756   } else {
1757     ierr = MatSetValues(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
1758   }
1759   PetscFunctionReturn(0);
1760 }
1761 
1762 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1763 {
1764   PetscErrorCode ierr;
1765   Mat_IS         *is = (Mat_IS*)A->data;
1766 
1767   PetscFunctionBegin;
1768   if (is->A->rmap->mapping) {
1769 #if defined(PETSC_USE_DEBUG)
1770     PetscInt ibs,bs;
1771 
1772     ierr = ISLocalToGlobalMappingGetBlockSize(is->A->rmap->mapping,&ibs);CHKERRQ(ierr);
1773     ierr = MatGetBlockSize(is->A,&bs);CHKERRQ(ierr);
1774     if (ibs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Different block sizes! local mat %D, local l2g map %D",bs,ibs);
1775 #endif
1776     ierr = MatSetValuesBlockedLocal(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
1777   } else {
1778     ierr = MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);CHKERRQ(ierr);
1779   }
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,PetscBool columns)
1784 {
1785   Mat_IS         *is = (Mat_IS*)A->data;
1786   PetscErrorCode ierr;
1787 
1788   PetscFunctionBegin;
1789   if (!n) {
1790     is->pure_neumann = PETSC_TRUE;
1791   } else {
1792     PetscInt i;
1793     is->pure_neumann = PETSC_FALSE;
1794 
1795     if (columns) {
1796       ierr = MatZeroRowsColumns(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
1797     } else {
1798       ierr = MatZeroRows(is->A,n,rows,diag,0,0);CHKERRQ(ierr);
1799     }
1800     if (diag != 0.) {
1801       const PetscScalar *array;
1802       ierr = VecGetArrayRead(is->counter,&array);CHKERRQ(ierr);
1803       for (i=0; i<n; i++) {
1804         ierr = MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);CHKERRQ(ierr);
1805       }
1806       ierr = VecRestoreArrayRead(is->counter,&array);CHKERRQ(ierr);
1807     }
1808     ierr = MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1809     ierr = MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1810   }
1811   PetscFunctionReturn(0);
1812 }
1813 
1814 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b,PetscBool columns)
1815 {
1816   Mat_IS         *matis = (Mat_IS*)A->data;
1817   PetscInt       nr,nl,len,i;
1818   PetscInt       *lrows;
1819   PetscErrorCode ierr;
1820 
1821   PetscFunctionBegin;
1822 #if defined(PETSC_USE_DEBUG)
1823   if (columns || diag != 0. || (x && b)) {
1824     PetscBool cong;
1825 
1826     ierr = PetscLayoutCompare(A->rmap,A->cmap,&cong);CHKERRQ(ierr);
1827     cong = (PetscBool)(cong && matis->sf == matis->csf);
1828     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");
1829     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");
1830     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");
1831   }
1832 #endif
1833   /* get locally owned rows */
1834   ierr = PetscLayoutMapLocal_Private(A->rmap,n,rows,&len,&lrows,NULL);CHKERRQ(ierr);
1835   /* fix right hand side if needed */
1836   if (x && b) {
1837     const PetscScalar *xx;
1838     PetscScalar       *bb;
1839 
1840     ierr = VecGetArrayRead(x, &xx);CHKERRQ(ierr);
1841     ierr = VecGetArray(b, &bb);CHKERRQ(ierr);
1842     for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]];
1843     ierr = VecRestoreArrayRead(x, &xx);CHKERRQ(ierr);
1844     ierr = VecRestoreArray(b, &bb);CHKERRQ(ierr);
1845   }
1846   /* get rows associated to the local matrices */
1847   ierr = MatISSetUpSF(A);CHKERRQ(ierr);
1848   ierr = MatGetSize(matis->A,&nl,NULL);CHKERRQ(ierr);
1849   ierr = PetscMemzero(matis->sf_leafdata,nl*sizeof(PetscInt));CHKERRQ(ierr);
1850   ierr = PetscMemzero(matis->sf_rootdata,A->rmap->n*sizeof(PetscInt));CHKERRQ(ierr);
1851   for (i=0;i<len;i++) matis->sf_rootdata[lrows[i]] = 1;
1852   ierr = PetscFree(lrows);CHKERRQ(ierr);
1853   ierr = PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1854   ierr = PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);CHKERRQ(ierr);
1855   ierr = PetscMalloc1(nl,&lrows);CHKERRQ(ierr);
1856   for (i=0,nr=0;i<nl;i++) if (matis->sf_leafdata[i]) lrows[nr++] = i;
1857   ierr = MatISZeroRowsColumnsLocal_Private(A,nr,lrows,diag,columns);CHKERRQ(ierr);
1858   ierr = PetscFree(lrows);CHKERRQ(ierr);
1859   PetscFunctionReturn(0);
1860 }
1861 
1862 static PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
1863 {
1864   PetscErrorCode ierr;
1865 
1866   PetscFunctionBegin;
1867   ierr = MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_FALSE);CHKERRQ(ierr);
1868   PetscFunctionReturn(0);
1869 }
1870 
1871 static PetscErrorCode MatZeroRowsColumns_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
1872 {
1873   PetscErrorCode ierr;
1874 
1875   PetscFunctionBegin;
1876   ierr = MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_TRUE);CHKERRQ(ierr);
1877   PetscFunctionReturn(0);
1878 }
1879 
1880 static PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
1881 {
1882   Mat_IS         *is = (Mat_IS*)A->data;
1883   PetscErrorCode ierr;
1884 
1885   PetscFunctionBegin;
1886   ierr = MatAssemblyBegin(is->A,type);CHKERRQ(ierr);
1887   PetscFunctionReturn(0);
1888 }
1889 
1890 static PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
1891 {
1892   Mat_IS         *is = (Mat_IS*)A->data;
1893   PetscErrorCode ierr;
1894 
1895   PetscFunctionBegin;
1896   ierr = MatAssemblyEnd(is->A,type);CHKERRQ(ierr);
1897   /* fix for local empty rows/cols */
1898   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
1899     Mat                    newlA;
1900     ISLocalToGlobalMapping l2g;
1901     IS                     tis;
1902     const PetscScalar      *v;
1903     PetscInt               i,n,cf,*loce,*locf;
1904     PetscBool              sym;
1905 
1906     ierr = MatGetRowMaxAbs(is->A,is->y,NULL);CHKERRQ(ierr);
1907     ierr = MatIsSymmetric(is->A,PETSC_SMALL,&sym);CHKERRQ(ierr);
1908     if (!sym) SETERRQ(PetscObjectComm((PetscObject)is->A),PETSC_ERR_SUP,"Not yet implemented for unsymmetric case");
1909     ierr = VecGetLocalSize(is->y,&n);CHKERRQ(ierr);
1910     ierr = PetscMalloc1(n,&loce);CHKERRQ(ierr);
1911     ierr = PetscMalloc1(n,&locf);CHKERRQ(ierr);
1912     ierr = VecGetArrayRead(is->y,&v);CHKERRQ(ierr);
1913     for (i=0,cf=0;i<n;i++) {
1914       if (v[i] == 0.0) {
1915         loce[i] = -1;
1916       } else {
1917         loce[i]    = cf;
1918         locf[cf++] = i;
1919       }
1920     }
1921     ierr = VecRestoreArrayRead(is->y,&v);CHKERRQ(ierr);
1922     /* extract valid submatrix */
1923     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is->A),cf,locf,PETSC_USE_POINTER,&tis);CHKERRQ(ierr);
1924     ierr = MatCreateSubMatrix(is->A,tis,tis,MAT_INITIAL_MATRIX,&newlA);CHKERRQ(ierr);
1925     ierr = ISDestroy(&tis);CHKERRQ(ierr);
1926     /* attach local l2g map for successive calls of MatSetValues */
1927     ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is->A),1,n,loce,PETSC_OWN_POINTER,&l2g);CHKERRQ(ierr);
1928     ierr = MatSetLocalToGlobalMapping(newlA,l2g,l2g);CHKERRQ(ierr);
1929     ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
1930     /* attach new global l2g map */
1931     ierr = ISLocalToGlobalMappingApply(A->rmap->mapping,cf,locf,locf);CHKERRQ(ierr);
1932     ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,cf,locf,PETSC_OWN_POINTER,&l2g);CHKERRQ(ierr);
1933     ierr = MatSetLocalToGlobalMapping(A,l2g,l2g);CHKERRQ(ierr);
1934     ierr = MatISSetLocalMat(A,newlA);CHKERRQ(ierr);
1935     ierr = MatDestroy(&newlA);CHKERRQ(ierr);
1936     ierr = ISLocalToGlobalMappingDestroy(&l2g);CHKERRQ(ierr);
1937   }
1938   is->locempty = PETSC_FALSE;
1939   PetscFunctionReturn(0);
1940 }
1941 
1942 static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
1943 {
1944   Mat_IS *is = (Mat_IS*)mat->data;
1945 
1946   PetscFunctionBegin;
1947   *local = is->A;
1948   PetscFunctionReturn(0);
1949 }
1950 
1951 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local)
1952 {
1953   PetscFunctionBegin;
1954   *local = NULL;
1955   PetscFunctionReturn(0);
1956 }
1957 
1958 /*@
1959     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
1960 
1961   Input Parameter:
1962 .  mat - the matrix
1963 
1964   Output Parameter:
1965 .  local - the local matrix
1966 
1967   Level: advanced
1968 
1969   Notes:
1970     This can be called if you have precomputed the nonzero structure of the
1971   matrix and want to provide it to the inner matrix object to improve the performance
1972   of the MatSetValues() operation.
1973 
1974   Call MatISRestoreLocalMat() when finished with the local matrix.
1975 
1976 .seealso: MATIS
1977 @*/
1978 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
1979 {
1980   PetscErrorCode ierr;
1981 
1982   PetscFunctionBegin;
1983   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1984   PetscValidPointer(local,2);
1985   ierr = PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 /*@
1990     MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()
1991 
1992   Input Parameter:
1993 .  mat - the matrix
1994 
1995   Output Parameter:
1996 .  local - the local matrix
1997 
1998   Level: advanced
1999 
2000 .seealso: MATIS
2001 @*/
2002 PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local)
2003 {
2004   PetscErrorCode ierr;
2005 
2006   PetscFunctionBegin;
2007   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2008   PetscValidPointer(local,2);
2009   ierr = PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local));CHKERRQ(ierr);
2010   PetscFunctionReturn(0);
2011 }
2012 
2013 static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
2014 {
2015   Mat_IS         *is = (Mat_IS*)mat->data;
2016   PetscInt       nrows,ncols,orows,ocols;
2017   PetscErrorCode ierr;
2018 
2019   PetscFunctionBegin;
2020   if (is->A) {
2021     ierr = MatGetSize(is->A,&orows,&ocols);CHKERRQ(ierr);
2022     ierr = MatGetSize(local,&nrows,&ncols);CHKERRQ(ierr);
2023     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);
2024   }
2025   ierr  = PetscObjectReference((PetscObject)local);CHKERRQ(ierr);
2026   ierr  = MatDestroy(&is->A);CHKERRQ(ierr);
2027   is->A = local;
2028   PetscFunctionReturn(0);
2029 }
2030 
2031 /*@
2032     MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.
2033 
2034   Input Parameter:
2035 .  mat - the matrix
2036 .  local - the local matrix
2037 
2038   Output Parameter:
2039 
2040   Level: advanced
2041 
2042   Notes:
2043     This can be called if you have precomputed the local matrix and
2044   want to provide it to the matrix object MATIS.
2045 
2046 .seealso: MATIS
2047 @*/
2048 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
2049 {
2050   PetscErrorCode ierr;
2051 
2052   PetscFunctionBegin;
2053   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
2054   PetscValidHeaderSpecific(local,MAT_CLASSID,2);
2055   ierr = PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));CHKERRQ(ierr);
2056   PetscFunctionReturn(0);
2057 }
2058 
2059 static PetscErrorCode MatZeroEntries_IS(Mat A)
2060 {
2061   Mat_IS         *a = (Mat_IS*)A->data;
2062   PetscErrorCode ierr;
2063 
2064   PetscFunctionBegin;
2065   ierr = MatZeroEntries(a->A);CHKERRQ(ierr);
2066   PetscFunctionReturn(0);
2067 }
2068 
2069 static PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
2070 {
2071   Mat_IS         *is = (Mat_IS*)A->data;
2072   PetscErrorCode ierr;
2073 
2074   PetscFunctionBegin;
2075   ierr = MatScale(is->A,a);CHKERRQ(ierr);
2076   PetscFunctionReturn(0);
2077 }
2078 
2079 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
2080 {
2081   Mat_IS         *is = (Mat_IS*)A->data;
2082   PetscErrorCode ierr;
2083 
2084   PetscFunctionBegin;
2085   /* get diagonal of the local matrix */
2086   ierr = MatGetDiagonal(is->A,is->y);CHKERRQ(ierr);
2087 
2088   /* scatter diagonal back into global vector */
2089   ierr = VecSet(v,0);CHKERRQ(ierr);
2090   ierr = VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2091   ierr = VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
2092   PetscFunctionReturn(0);
2093 }
2094 
2095 static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
2096 {
2097   Mat_IS         *a = (Mat_IS*)A->data;
2098   PetscErrorCode ierr;
2099 
2100   PetscFunctionBegin;
2101   ierr = MatSetOption(a->A,op,flg);CHKERRQ(ierr);
2102   PetscFunctionReturn(0);
2103 }
2104 
2105 static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str)
2106 {
2107   Mat_IS         *y = (Mat_IS*)Y->data;
2108   Mat_IS         *x;
2109 #if defined(PETSC_USE_DEBUG)
2110   PetscBool      ismatis;
2111 #endif
2112   PetscErrorCode ierr;
2113 
2114   PetscFunctionBegin;
2115 #if defined(PETSC_USE_DEBUG)
2116   ierr = PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis);CHKERRQ(ierr);
2117   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
2118 #endif
2119   x = (Mat_IS*)X->data;
2120   ierr = MatAXPY(y->A,a,x->A,str);CHKERRQ(ierr);
2121   PetscFunctionReturn(0);
2122 }
2123 
2124 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat)
2125 {
2126   Mat                    lA;
2127   Mat_IS                 *matis;
2128   ISLocalToGlobalMapping rl2g,cl2g;
2129   IS                     is;
2130   const PetscInt         *rg,*rl;
2131   PetscInt               nrg;
2132   PetscInt               N,M,nrl,i,*idxs;
2133   PetscErrorCode         ierr;
2134 
2135   PetscFunctionBegin;
2136   ierr = ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
2137   ierr = ISGetLocalSize(row,&nrl);CHKERRQ(ierr);
2138   ierr = ISGetIndices(row,&rl);CHKERRQ(ierr);
2139   ierr = ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg);CHKERRQ(ierr);
2140 #if defined(PETSC_USE_DEBUG)
2141   for (i=0;i<nrl;i++) if (rl[i]>=nrg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row index %D -> %D greater than maximum possible %D",i,rl[i],nrg);
2142 #endif
2143   ierr = PetscMalloc1(nrg,&idxs);CHKERRQ(ierr);
2144   /* map from [0,nrl) to row */
2145   for (i=0;i<nrl;i++) idxs[i] = rl[i];
2146 #if defined(PETSC_USE_DEBUG)
2147   for (i=nrl;i<nrg;i++) idxs[i] = nrg;
2148 #else
2149   for (i=nrl;i<nrg;i++) idxs[i] = -1;
2150 #endif
2151   ierr = ISRestoreIndices(row,&rl);CHKERRQ(ierr);
2152   ierr = ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg);CHKERRQ(ierr);
2153   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
2154   ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g);CHKERRQ(ierr);
2155   ierr = ISDestroy(&is);CHKERRQ(ierr);
2156   /* compute new l2g map for columns */
2157   if (col != row || A->rmap->mapping != A->cmap->mapping) {
2158     const PetscInt *cg,*cl;
2159     PetscInt       ncg;
2160     PetscInt       ncl;
2161 
2162     ierr = ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
2163     ierr = ISGetLocalSize(col,&ncl);CHKERRQ(ierr);
2164     ierr = ISGetIndices(col,&cl);CHKERRQ(ierr);
2165     ierr = ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg);CHKERRQ(ierr);
2166 #if defined(PETSC_USE_DEBUG)
2167     for (i=0;i<ncl;i++) if (cl[i]>=ncg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local column index %D -> %D greater than maximum possible %D",i,cl[i],ncg);
2168 #endif
2169     ierr = PetscMalloc1(ncg,&idxs);CHKERRQ(ierr);
2170     /* map from [0,ncl) to col */
2171     for (i=0;i<ncl;i++) idxs[i] = cl[i];
2172 #if defined(PETSC_USE_DEBUG)
2173     for (i=ncl;i<ncg;i++) idxs[i] = ncg;
2174 #else
2175     for (i=ncl;i<ncg;i++) idxs[i] = -1;
2176 #endif
2177     ierr = ISRestoreIndices(col,&cl);CHKERRQ(ierr);
2178     ierr = ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg);CHKERRQ(ierr);
2179     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is);CHKERRQ(ierr);
2180     ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g);CHKERRQ(ierr);
2181     ierr = ISDestroy(&is);CHKERRQ(ierr);
2182   } else {
2183     ierr = PetscObjectReference((PetscObject)rl2g);CHKERRQ(ierr);
2184     cl2g = rl2g;
2185   }
2186   /* create the MATIS submatrix */
2187   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
2188   ierr = MatCreate(PetscObjectComm((PetscObject)A),submat);CHKERRQ(ierr);
2189   ierr = MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr);
2190   ierr = MatSetType(*submat,MATIS);CHKERRQ(ierr);
2191   matis = (Mat_IS*)((*submat)->data);
2192   matis->islocalref = PETSC_TRUE;
2193   ierr = MatSetLocalToGlobalMapping(*submat,rl2g,cl2g);CHKERRQ(ierr);
2194   ierr = MatISGetLocalMat(A,&lA);CHKERRQ(ierr);
2195   ierr = MatISSetLocalMat(*submat,lA);CHKERRQ(ierr);
2196   ierr = MatSetUp(*submat);CHKERRQ(ierr);
2197   ierr = MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2198   ierr = MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2199   ierr = ISLocalToGlobalMappingDestroy(&rl2g);CHKERRQ(ierr);
2200   ierr = ISLocalToGlobalMappingDestroy(&cl2g);CHKERRQ(ierr);
2201   /* remove unsupported ops */
2202   ierr = PetscMemzero((*submat)->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
2203   (*submat)->ops->destroy               = MatDestroy_IS;
2204   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
2205   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
2206   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
2207   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
2208   PetscFunctionReturn(0);
2209 }
2210 
2211 static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A)
2212 {
2213   Mat_IS         *a = (Mat_IS*)A->data;
2214   PetscErrorCode ierr;
2215 
2216   PetscFunctionBegin;
2217   ierr = PetscOptionsHead(PetscOptionsObject,"MATIS options");CHKERRQ(ierr);
2218   ierr = PetscObjectOptionsBegin((PetscObject)A);
2219   ierr = PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns",NULL,a->locempty,&a->locempty,NULL);CHKERRQ(ierr);
2220   ierr = PetscOptionsEnd();CHKERRQ(ierr);
2221   PetscFunctionReturn(0);
2222 }
2223 
2224 /*@
2225     MatCreateIS - Creates a "process" unassembled matrix, assembled on each
2226        process but not across processes.
2227 
2228    Input Parameters:
2229 +     comm    - MPI communicator that will share the matrix
2230 .     bs      - block size of the matrix
2231 .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
2232 .     rmap    - local to global map for rows
2233 -     cmap    - local to global map for cols
2234 
2235    Output Parameter:
2236 .    A - the resulting matrix
2237 
2238    Level: advanced
2239 
2240    Notes: See MATIS for more details.
2241           m and n are NOT related to the size of the map; they represent the size of the local parts of the vectors
2242           used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
2243           If either rmap or cmap are NULL, then the matrix is assumed to be square.
2244 
2245 .seealso: MATIS, MatSetLocalToGlobalMapping()
2246 @*/
2247 PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A)
2248 {
2249   PetscErrorCode ierr;
2250 
2251   PetscFunctionBegin;
2252   if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mappings");
2253   ierr = MatCreate(comm,A);CHKERRQ(ierr);
2254   ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr);
2255   if (bs > 0) {
2256     ierr = MatSetBlockSize(*A,bs);CHKERRQ(ierr);
2257   }
2258   ierr = MatSetType(*A,MATIS);CHKERRQ(ierr);
2259   if (rmap && cmap) {
2260     ierr = MatSetLocalToGlobalMapping(*A,rmap,cmap);CHKERRQ(ierr);
2261   } else if (!rmap) {
2262     ierr = MatSetLocalToGlobalMapping(*A,cmap,cmap);CHKERRQ(ierr);
2263   } else {
2264     ierr = MatSetLocalToGlobalMapping(*A,rmap,rmap);CHKERRQ(ierr);
2265   }
2266   PetscFunctionReturn(0);
2267 }
2268 
2269 /*MC
2270    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
2271    This stores the matrices in globally unassembled form. Each processor
2272    assembles only its local Neumann problem and the parallel matrix vector
2273    product is handled "implicitly".
2274 
2275    Operations Provided:
2276 +  MatMult()
2277 .  MatMultAdd()
2278 .  MatMultTranspose()
2279 .  MatMultTransposeAdd()
2280 .  MatZeroEntries()
2281 .  MatSetOption()
2282 .  MatZeroRows()
2283 .  MatSetValues()
2284 .  MatSetValuesBlocked()
2285 .  MatSetValuesLocal()
2286 .  MatSetValuesBlockedLocal()
2287 .  MatScale()
2288 .  MatGetDiagonal()
2289 .  MatMissingDiagonal()
2290 .  MatDuplicate()
2291 .  MatCopy()
2292 .  MatAXPY()
2293 .  MatCreateSubMatrix()
2294 .  MatGetLocalSubMatrix()
2295 .  MatTranspose()
2296 -  MatSetLocalToGlobalMapping()
2297 
2298    Options Database Keys:
2299 . -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
2300 
2301    Notes: Options prefix for the inner matrix are given by -is_mat_xxx
2302 
2303           You must call MatSetLocalToGlobalMapping() before using this matrix type.
2304 
2305           You can do matrix preallocation on the local matrix after you obtain it with
2306           MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()
2307 
2308   Level: advanced
2309 
2310 .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), MatCreateIS(), PCBDDC, KSPFETIDP
2311 
2312 M*/
2313 
2314 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
2315 {
2316   PetscErrorCode ierr;
2317   Mat_IS         *b;
2318 
2319   PetscFunctionBegin;
2320   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
2321   A->data = (void*)b;
2322 
2323   /* matrix ops */
2324   ierr    = PetscMemzero(A->ops,sizeof(struct _MatOps));CHKERRQ(ierr);
2325   A->ops->mult                    = MatMult_IS;
2326   A->ops->multadd                 = MatMultAdd_IS;
2327   A->ops->multtranspose           = MatMultTranspose_IS;
2328   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
2329   A->ops->destroy                 = MatDestroy_IS;
2330   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
2331   A->ops->setvalues               = MatSetValues_IS;
2332   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
2333   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
2334   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
2335   A->ops->zerorows                = MatZeroRows_IS;
2336   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
2337   A->ops->assemblybegin           = MatAssemblyBegin_IS;
2338   A->ops->assemblyend             = MatAssemblyEnd_IS;
2339   A->ops->view                    = MatView_IS;
2340   A->ops->zeroentries             = MatZeroEntries_IS;
2341   A->ops->scale                   = MatScale_IS;
2342   A->ops->getdiagonal             = MatGetDiagonal_IS;
2343   A->ops->setoption               = MatSetOption_IS;
2344   A->ops->ishermitian             = MatIsHermitian_IS;
2345   A->ops->issymmetric             = MatIsSymmetric_IS;
2346   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
2347   A->ops->duplicate               = MatDuplicate_IS;
2348   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
2349   A->ops->copy                    = MatCopy_IS;
2350   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
2351   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
2352   A->ops->axpy                    = MatAXPY_IS;
2353   A->ops->diagonalset             = MatDiagonalSet_IS;
2354   A->ops->shift                   = MatShift_IS;
2355   A->ops->transpose               = MatTranspose_IS;
2356   A->ops->getinfo                 = MatGetInfo_IS;
2357   A->ops->diagonalscale           = MatDiagonalScale_IS;
2358   A->ops->setfromoptions          = MatSetFromOptions_IS;
2359 
2360   /* special MATIS functions */
2361   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);CHKERRQ(ierr);
2362   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS);CHKERRQ(ierr);
2363   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);CHKERRQ(ierr);
2364   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatISGetMPIXAIJ_IS);CHKERRQ(ierr);
2365   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);CHKERRQ(ierr);
2366   ierr = PetscObjectComposeFunction((PetscObject)A,"MatISSetUpSF_C",MatISSetUpSF_IS);CHKERRQ(ierr);
2367   ierr = PetscObjectChangeTypeName((PetscObject)A,MATIS);CHKERRQ(ierr);
2368   PetscFunctionReturn(0);
2369 }
2370