Actual source code: matis.c

petsc-3.13.1 2020-05-02
Report Typos and Errors
  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".

  7:     Currently this allows for only one subdomain per processor.
  8: */

 10:  #include <../src/mat/impls/is/matis.h>
 11:  #include <petsc/private/sfimpl.h>
 12:  #include <petsc/private/vecimpl.h>

 14: #define MATIS_MAX_ENTRIES_INSERTION 2048
 15: static PetscErrorCode MatSetValuesLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
 16: static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
 17: static PetscErrorCode MatISSetUpScatters_Private(Mat);

 19: static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr)
 20: {
 21:   MatISPtAP      ptap = (MatISPtAP)ptr;

 25:   MatDestroySubMatrices(ptap->ris1 ? 2 : 1,&ptap->lP);
 26:   ISDestroy(&ptap->cis0);
 27:   ISDestroy(&ptap->cis1);
 28:   ISDestroy(&ptap->ris0);
 29:   ISDestroy(&ptap->ris1);
 30:   PetscFree(ptap);
 31:   return(0);
 32: }

 34: static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
 35: {
 36:   MatISPtAP      ptap;
 37:   Mat_IS         *matis = (Mat_IS*)A->data;
 38:   Mat            lA,lC;
 39:   MatReuse       reuse;
 40:   IS             ris[2],cis[2];
 41:   PetscContainer c;
 42:   PetscInt       n;

 46:   PetscObjectQuery((PetscObject)C,"_MatIS_PtAP",(PetscObject*)&c);
 47:   if (!c) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing PtAP information");
 48:   PetscContainerGetPointer(c,(void**)&ptap);
 49:   ris[0] = ptap->ris0;
 50:   ris[1] = ptap->ris1;
 51:   cis[0] = ptap->cis0;
 52:   cis[1] = ptap->cis1;
 53:   n      = ptap->ris1 ? 2 : 1;
 54:   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
 55:   MatCreateSubMatrices(P,n,ris,cis,reuse,&ptap->lP);

 57:   MatISGetLocalMat(A,&lA);
 58:   MatISGetLocalMat(C,&lC);
 59:   if (ptap->ris1) { /* unsymmetric A mapping */
 60:     Mat lPt;

 62:     MatTranspose(ptap->lP[1],MAT_INITIAL_MATRIX,&lPt);
 63:     MatMatMatMult(lPt,lA,ptap->lP[0],reuse,ptap->fill,&lC);
 64:     if (matis->storel2l) {
 65:       PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",(PetscObject)lPt);
 66:     }
 67:     MatDestroy(&lPt);
 68:   } else {
 69:     MatPtAP(lA,ptap->lP[0],reuse,ptap->fill,&lC);
 70:     if (matis->storel2l) {
 71:      PetscObjectCompose((PetscObject)C,"_MatIS_PtAP_l2l",(PetscObject)ptap->lP[0]);
 72:     }
 73:   }
 74:   if (reuse == MAT_INITIAL_MATRIX) {
 75:     MatISSetLocalMat(C,lC);
 76:     MatDestroy(&lC);
 77:   }
 78:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
 79:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
 80:   return(0);
 81: }

 83: static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT,IS *cis)
 84: {
 85:   Mat            Po,Pd;
 86:   IS             zd,zo;
 87:   const PetscInt *garray;
 88:   PetscInt       *aux,i,bs;
 89:   PetscInt       dc,stc,oc,ctd,cto;
 90:   PetscBool      ismpiaij,ismpibaij,isseqaij,isseqbaij;
 91:   MPI_Comm       comm;

 97:   PetscObjectGetComm((PetscObject)PT,&comm);
 98:   bs   = 1;
 99:   PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIAIJ,&ismpiaij);
100:   PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIBAIJ,&ismpibaij);
101:   PetscObjectBaseTypeCompare((PetscObject)PT,MATSEQAIJ,&isseqaij);
102:   PetscObjectTypeCompare((PetscObject)PT,MATSEQBAIJ,&isseqbaij);
103:   if (isseqaij || isseqbaij) {
104:     Pd = PT;
105:     Po = NULL;
106:     garray = NULL;
107:   } else if (ismpiaij) {
108:     MatMPIAIJGetSeqAIJ(PT,&Pd,&Po,&garray);
109:   } else if (ismpibaij) {
110:     MatMPIBAIJGetSeqBAIJ(PT,&Pd,&Po,&garray);
111:     MatGetBlockSize(PT,&bs);
112:   } else SETERRQ1(comm,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(PT))->type_name);

114:   /* identify any null columns in Pd or Po */
115:   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
116:      some of the columns are not really zero, but very close to */
117:   zo = zd = NULL;
118:   if (Po) {
119:     MatFindNonzeroRowsOrCols_Basic(Po,PETSC_TRUE,PETSC_SMALL,&zo);
120:   }
121:   MatFindNonzeroRowsOrCols_Basic(Pd,PETSC_TRUE,PETSC_SMALL,&zd);

123:   MatGetLocalSize(PT,NULL,&dc);
124:   MatGetOwnershipRangeColumn(PT,&stc,NULL);
125:   if (Po) { MatGetLocalSize(Po,NULL,&oc); }
126:   else oc = 0;
127:   PetscMalloc1((dc+oc)/bs,&aux);
128:   if (zd) {
129:     const PetscInt *idxs;
130:     PetscInt       nz;

132:     /* this will throw an error if bs is not valid */
133:     ISSetBlockSize(zd,bs);
134:     ISGetLocalSize(zd,&nz);
135:     ISGetIndices(zd,&idxs);
136:     ctd  = nz/bs;
137:     for (i=0; i<ctd; i++) aux[i] = (idxs[bs*i]+stc)/bs;
138:     ISRestoreIndices(zd,&idxs);
139:   } else {
140:     ctd = dc/bs;
141:     for (i=0; i<ctd; i++) aux[i] = i+stc/bs;
142:   }
143:   if (zo) {
144:     const PetscInt *idxs;
145:     PetscInt       nz;

147:     /* this will throw an error if bs is not valid */
148:     ISSetBlockSize(zo,bs);
149:     ISGetLocalSize(zo,&nz);
150:     ISGetIndices(zo,&idxs);
151:     cto  = nz/bs;
152:     for (i=0; i<cto; i++) aux[i+ctd] = garray[idxs[bs*i]/bs];
153:     ISRestoreIndices(zo,&idxs);
154:   } else {
155:     cto = oc/bs;
156:     for (i=0; i<cto; i++) aux[i+ctd] = garray[i];
157:   }
158:   ISCreateBlock(comm,bs,ctd+cto,aux,PETSC_OWN_POINTER,cis);
159:   ISDestroy(&zd);
160:   ISDestroy(&zo);
161:   return(0);
162: }

164: static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A,Mat P,PetscReal fill,Mat C)
165: {
166:   Mat                    PT,lA;
167:   MatISPtAP              ptap;
168:   ISLocalToGlobalMapping Crl2g,Ccl2g,rl2g,cl2g;
169:   PetscContainer         c;
170:   MatType                lmtype;
171:   const PetscInt         *garray;
172:   PetscInt               ibs,N,dc;
173:   MPI_Comm               comm;
174:   PetscErrorCode         ierr;

177:   PetscObjectGetComm((PetscObject)A,&comm);
178:   MatSetType(C,MATIS);
179:   MatISGetLocalMat(A,&lA);
180:   MatGetType(lA,&lmtype);
181:   MatISSetLocalMatType(C,lmtype);
182:   MatGetSize(P,NULL,&N);
183:   MatGetLocalSize(P,NULL,&dc);
184:   MatSetSizes(C,dc,dc,N,N);
185: /* Not sure about this
186:   MatGetBlockSizes(P,NULL,&ibs);
187:   MatSetBlockSize(*C,ibs);
188: */

190:   PetscNew(&ptap);
191:   PetscContainerCreate(PETSC_COMM_SELF,&c);
192:   PetscContainerSetPointer(c,ptap);
193:   PetscContainerSetUserDestroy(c,MatISContainerDestroyPtAP_Private);
194:   PetscObjectCompose((PetscObject)C,"_MatIS_PtAP",(PetscObject)c);
195:   PetscContainerDestroy(&c);
196:   ptap->fill = fill;

198:   MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);

200:   ISLocalToGlobalMappingGetBlockSize(cl2g,&ibs);
201:   ISLocalToGlobalMappingGetSize(cl2g,&N);
202:   ISLocalToGlobalMappingGetBlockIndices(cl2g,&garray);
203:   ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris0);
204:   ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&garray);

206:   MatCreateSubMatrix(P,ptap->ris0,NULL,MAT_INITIAL_MATRIX,&PT);
207:   MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis0);
208:   ISLocalToGlobalMappingCreateIS(ptap->cis0,&Ccl2g);
209:   MatDestroy(&PT);

211:   Crl2g = NULL;
212:   if (rl2g != cl2g) { /* unsymmetric A mapping */
213:     PetscBool same,lsame = PETSC_FALSE;
214:     PetscInt  N1,ibs1;

216:     ISLocalToGlobalMappingGetSize(rl2g,&N1);
217:     ISLocalToGlobalMappingGetBlockSize(rl2g,&ibs1);
218:     ISLocalToGlobalMappingGetBlockIndices(rl2g,&garray);
219:     ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris1);
220:     ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&garray);
221:     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
222:       const PetscInt *i1,*i2;

224:       ISBlockGetIndices(ptap->ris0,&i1);
225:       ISBlockGetIndices(ptap->ris1,&i2);
226:       PetscArraycmp(i1,i2,N,&lsame);
227:     }
228:     MPIU_Allreduce(&lsame,&same,1,MPIU_BOOL,MPI_LAND,comm);
229:     if (same) {
230:       ISDestroy(&ptap->ris1);
231:     } else {
232:       MatCreateSubMatrix(P,ptap->ris1,NULL,MAT_INITIAL_MATRIX,&PT);
233:       MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis1);
234:       ISLocalToGlobalMappingCreateIS(ptap->cis1,&Crl2g);
235:       MatDestroy(&PT);
236:     }
237:   }
238: /* Not sure about this
239:   if (!Crl2g) {
240:     MatGetBlockSize(C,&ibs);
241:     ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs);
242:   }
243: */
244:   MatSetLocalToGlobalMapping(C,Crl2g ? Crl2g : Ccl2g,Ccl2g);
245:   ISLocalToGlobalMappingDestroy(&Crl2g);
246:   ISLocalToGlobalMappingDestroy(&Ccl2g);

248:   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
249:   return(0);
250: }

252: /* ----------------------------------------- */
253: static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
254: {
256:   Mat_Product    *product = C->product;
257:   Mat            A=product->A,P=product->B;
258:   PetscReal      fill=product->fill;

261:   MatPtAPSymbolic_IS_XAIJ(A,P,fill,C);
262:   C->ops->productnumeric = MatProductNumeric_PtAP;
263:   return(0);
264: }

266: static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
267: {
269:   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
270:   return(0);
271: }

273: PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
274: {
276:   Mat_Product    *product = C->product;

279:   MatSetType(C,MATIS);
280:   if (product->type == MATPRODUCT_PtAP) {
281:     MatProductSetFromOptions_IS_XAIJ_PtAP(C);
282:   } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatProduct type %s is not supported for IS and XAIJ matrices",MatProductTypes[product->type]);
283:   return(0);
284: }

286: /* ----------------------------------------- */
287: static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
288: {
289:   MatISLocalFields lf = (MatISLocalFields)ptr;
290:   PetscInt         i;
291:   PetscErrorCode   ierr;

294:   for (i=0;i<lf->nr;i++) {
295:     ISDestroy(&lf->rf[i]);
296:   }
297:   for (i=0;i<lf->nc;i++) {
298:     ISDestroy(&lf->cf[i]);
299:   }
300:   PetscFree2(lf->rf,lf->cf);
301:   PetscFree(lf);
302:   return(0);
303: }

305: static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
306: {
307:   Mat            B,lB;

311:   if (reuse != MAT_REUSE_MATRIX) {
312:     ISLocalToGlobalMapping rl2g,cl2g;
313:     PetscInt               bs;
314:     IS                     is;

316:     MatGetBlockSize(A,&bs);
317:     ISCreateStride(PetscObjectComm((PetscObject)A),A->rmap->n/bs,0,1,&is);
318:     if (bs > 1) {
319:       IS       is2;
320:       PetscInt i,*aux;

322:       ISGetLocalSize(is,&i);
323:       ISGetIndices(is,(const PetscInt**)&aux);
324:       ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);
325:       ISRestoreIndices(is,(const PetscInt**)&aux);
326:       ISDestroy(&is);
327:       is   = is2;
328:     }
329:     ISSetIdentity(is);
330:     ISLocalToGlobalMappingCreateIS(is,&rl2g);
331:     ISDestroy(&is);
332:     ISCreateStride(PetscObjectComm((PetscObject)A),A->cmap->n/bs,0,1,&is);
333:     if (bs > 1) {
334:       IS       is2;
335:       PetscInt i,*aux;

337:       ISGetLocalSize(is,&i);
338:       ISGetIndices(is,(const PetscInt**)&aux);
339:       ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);
340:       ISRestoreIndices(is,(const PetscInt**)&aux);
341:       ISDestroy(&is);
342:       is   = is2;
343:     }
344:     ISSetIdentity(is);
345:     ISLocalToGlobalMappingCreateIS(is,&cl2g);
346:     ISDestroy(&is);
347:     MatCreateIS(PetscObjectComm((PetscObject)A),bs,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N,rl2g,cl2g,&B);
348:     ISLocalToGlobalMappingDestroy(&rl2g);
349:     ISLocalToGlobalMappingDestroy(&cl2g);
350:     MatDuplicate(A,MAT_COPY_VALUES,&lB);
351:     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
352:   } else {
353:     B    = *newmat;
354:     PetscObjectReference((PetscObject)A);
355:     lB   = A;
356:   }
357:   MatISSetLocalMat(B,lB);
358:   MatDestroy(&lB);
359:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
360:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
361:   if (reuse == MAT_INPLACE_MATRIX) {
362:     MatHeaderReplace(A,&B);
363:   }
364:   return(0);
365: }

367: static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
368: {
369:   Mat_IS         *matis = (Mat_IS*)(A->data);
370:   PetscScalar    *aa;
371:   const PetscInt *ii,*jj;
372:   PetscInt       i,n,m;
373:   PetscInt       *ecount,**eneighs;
374:   PetscBool      flg;

378:   MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);
379:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
380:   ISLocalToGlobalMappingGetNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);
381:   if (m != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",m,n);
382:   MatSeqAIJGetArray(matis->A,&aa);
383:   for (i=0;i<n;i++) {
384:     if (ecount[i] > 1) {
385:       PetscInt j;

387:       for (j=ii[i];j<ii[i+1];j++) {
388:         PetscInt    i2 = jj[j],p,p2;
389:         PetscReal   scal = 0.0;

391:         for (p=0;p<ecount[i];p++) {
392:           for (p2=0;p2<ecount[i2];p2++) {
393:             if (eneighs[i][p] == eneighs[i2][p2]) { scal += 1.0; break; }
394:           }
395:         }
396:         if (scal) aa[j] /= scal;
397:       }
398:     }
399:   }
400:   ISLocalToGlobalMappingRestoreNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);
401:   MatSeqAIJRestoreArray(matis->A,&aa);
402:   MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);
403:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
404:   return(0);
405: }

407: typedef enum {MAT_IS_DISASSEMBLE_L2G_NATURAL,MAT_IS_DISASSEMBLE_L2G_MAT, MAT_IS_DISASSEMBLE_L2G_ND} MatISDisassemblel2gType;

409: static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
410: {
411:   Mat                     Ad,Ao;
412:   IS                      is,ndmap,ndsub;
413:   MPI_Comm                comm;
414:   const PetscInt          *garray,*ndmapi;
415:   PetscInt                bs,i,cnt,nl,*ncount,*ndmapc;
416:   PetscBool               ismpiaij,ismpibaij;
417:   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL","MAT","ND","MatISDisassemblel2gType","MAT_IS_DISASSEMBLE_L2G_",0};
418:   MatISDisassemblel2gType mode = MAT_IS_DISASSEMBLE_L2G_NATURAL;
419:   MatPartitioning         part;
420:   PetscSF                 sf;
421:   PetscErrorCode          ierr;

424:   PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"MatIS l2g disassembling options","Mat");
425:   PetscOptionsEnum("-mat_is_disassemble_l2g_type","Type of local-to-global mapping to be used for disassembling","MatISDisassemblel2gType",MatISDisassemblel2gTypes,(PetscEnum)mode,(PetscEnum*)&mode,NULL);
426:   PetscOptionsEnd();
427:   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
428:     MatGetLocalToGlobalMapping(A,l2g,NULL);
429:     return(0);
430:   }
431:   PetscObjectGetComm((PetscObject)A,&comm);
432:   PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);
433:   PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);
434:   MatGetBlockSize(A,&bs);
435:   switch (mode) {
436:   case MAT_IS_DISASSEMBLE_L2G_ND:
437:     MatPartitioningCreate(comm,&part);
438:     MatPartitioningSetAdjacency(part,A);
439:     PetscObjectSetOptionsPrefix((PetscObject)part,((PetscObject)A)->prefix);
440:     MatPartitioningSetFromOptions(part);
441:     MatPartitioningApplyND(part,&ndmap);
442:     MatPartitioningDestroy(&part);
443:     ISBuildTwoSided(ndmap,NULL,&ndsub);
444:     MatMPIAIJSetUseScalableIncreaseOverlap(A,PETSC_TRUE);
445:     MatIncreaseOverlap(A,1,&ndsub,1);
446:     ISLocalToGlobalMappingCreateIS(ndsub,l2g);

448:     /* it may happen that a separator node is not properly shared */
449:     ISLocalToGlobalMappingGetNodeInfo(*l2g,&nl,&ncount,NULL);
450:     PetscSFCreate(comm,&sf);
451:     ISLocalToGlobalMappingGetIndices(*l2g,&garray);
452:     PetscSFSetGraphLayout(sf,A->rmap,nl,NULL,PETSC_OWN_POINTER,garray);
453:     ISLocalToGlobalMappingRestoreIndices(*l2g,&garray);
454:     PetscCalloc1(A->rmap->n,&ndmapc);
455:     PetscSFReduceBegin(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);
456:     PetscSFReduceEnd(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);
457:     ISLocalToGlobalMappingRestoreNodeInfo(*l2g,NULL,&ncount,NULL);
458:     ISGetIndices(ndmap,&ndmapi);
459:     for (i = 0, cnt = 0; i < A->rmap->n; i++)
460:       if (ndmapi[i] < 0 && ndmapc[i] < 2)
461:         cnt++;

463:     MPIU_Allreduce(&cnt,&i,1,MPIU_INT,MPI_MAX,comm);
464:     if (i) { /* we detected isolated separator nodes */
465:       Mat                    A2,A3;
466:       IS                     *workis,is2;
467:       PetscScalar            *vals;
468:       PetscInt               gcnt = i,*dnz,*onz,j,*lndmapi;
469:       ISLocalToGlobalMapping ll2g;
470:       PetscBool              flg;
471:       const PetscInt         *ii,*jj;

473:       /* communicate global id of separators */
474:       MatPreallocateInitialize(comm,A->rmap->n,A->cmap->n,dnz,onz);
475:       for (i = 0, cnt = 0; i < A->rmap->n; i++)
476:         dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;

478:       PetscMalloc1(nl,&lndmapi);
479:       PetscSFBcastBegin(sf,MPIU_INT,dnz,lndmapi);

481:       /* compute adjacency of isolated separators node */
482:       PetscMalloc1(gcnt,&workis);
483:       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
484:         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
485:           ISCreateStride(comm,1,i+A->rmap->rstart,1,&workis[cnt++]);
486:         }
487:       }
488:       for (i = cnt; i < gcnt; i++) {
489:         ISCreateStride(comm,0,0,1,&workis[i]);
490:       }
491:       for (i = 0; i < gcnt; i++) {
492:         PetscObjectSetName((PetscObject)workis[i],"ISOLATED");
493:         ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");
494:       }

496:       /* no communications since all the ISes correspond to locally owned rows */
497:       MatIncreaseOverlap(A,gcnt,workis,1);

499:       /* end communicate global id of separators */
500:       PetscSFBcastEnd(sf,MPIU_INT,dnz,lndmapi);

502:       /* communicate new layers : create a matrix and transpose it */
503:       PetscArrayzero(dnz,A->rmap->n);
504:       PetscArrayzero(onz,A->rmap->n);
505:       for (i = 0, j = 0; i < A->rmap->n; i++) {
506:         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
507:           const PetscInt* idxs;
508:           PetscInt        s;

510:           ISGetLocalSize(workis[j],&s);
511:           ISGetIndices(workis[j],&idxs);
512:           MatPreallocateSet(i+A->rmap->rstart,s,idxs,dnz,onz);
513:           j++;
514:         }
515:       }
516:       if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);

518:       for (i = 0; i < gcnt; i++) {
519:         PetscObjectSetName((PetscObject)workis[i],"EXTENDED");
520:         ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");
521:       }

523:       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j,dnz[i]+onz[i]);
524:       PetscMalloc1(j,&vals);
525:       for (i = 0; i < j; i++) vals[i] = 1.0;

527:       MatCreate(comm,&A2);
528:       MatSetType(A2,MATMPIAIJ);
529:       MatSetSizes(A2,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
530:       MatMPIAIJSetPreallocation(A2,0,dnz,0,onz);
531:       MatSetOption(A2,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
532:       for (i = 0, j = 0; i < A2->rmap->n; i++) {
533:         PetscInt        row = i+A2->rmap->rstart,s = dnz[i] + onz[i];
534:         const PetscInt* idxs;

536:         if (s) {
537:           ISGetIndices(workis[j],&idxs);
538:           MatSetValues(A2,1,&row,s,idxs,vals,INSERT_VALUES);
539:           ISRestoreIndices(workis[j],&idxs);
540:           j++;
541:         }
542:       }
543:       if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);
544:       PetscFree(vals);
545:       MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY);
546:       MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY);
547:       MatTranspose(A2,MAT_INPLACE_MATRIX,&A2);

549:       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
550:       for (i = 0, j = 0; i < nl; i++)
551:         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
552:       ISCreateGeneral(comm,j,lndmapi,PETSC_USE_POINTER,&is);
553:       MatMPIAIJGetLocalMatCondensed(A2,MAT_INITIAL_MATRIX,&is,NULL,&A3);
554:       ISDestroy(&is);
555:       MatDestroy(&A2);

557:       /* extend local to global map to include connected isolated separators */
558:       PetscObjectQuery((PetscObject)A3,"_petsc_GetLocalMatCondensed_iscol",(PetscObject*)&is);
559:       if (!is) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing column map");
560:       ISLocalToGlobalMappingCreateIS(is,&ll2g);
561:       MatGetRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);
562:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
563:       ISCreateGeneral(PETSC_COMM_SELF,ii[i],jj,PETSC_COPY_VALUES,&is);
564:       MatRestoreRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);
565:       if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
566:       ISLocalToGlobalMappingApplyIS(ll2g,is,&is2);
567:       ISDestroy(&is);
568:       ISLocalToGlobalMappingDestroy(&ll2g);

570:       /* add new nodes to the local-to-global map */
571:       ISLocalToGlobalMappingDestroy(l2g);
572:       ISExpand(ndsub,is2,&is);
573:       ISDestroy(&is2);
574:       ISLocalToGlobalMappingCreateIS(is,l2g);
575:       ISDestroy(&is);

577:       MatDestroy(&A3);
578:       PetscFree(lndmapi);
579:       MatPreallocateFinalize(dnz,onz);
580:       for (i = 0; i < gcnt; i++) {
581:         ISDestroy(&workis[i]);
582:       }
583:       PetscFree(workis);
584:     }
585:     ISRestoreIndices(ndmap,&ndmapi);
586:     PetscSFDestroy(&sf);
587:     PetscFree(ndmapc);
588:     ISDestroy(&ndmap);
589:     ISDestroy(&ndsub);
590:     ISLocalToGlobalMappingSetBlockSize(*l2g,bs);
591:     ISLocalToGlobalMappingViewFromOptions(*l2g,NULL,"-matis_nd_l2g_view");
592:     break;
593:   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
594:     if (ismpiaij) {
595:       MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);
596:     } else if (ismpibaij) {
597:       MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);
598:     } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
599:     if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");
600:     if (A->rmap->n) {
601:       PetscInt dc,oc,stc,*aux;

603:       MatGetLocalSize(A,NULL,&dc);
604:       MatGetLocalSize(Ao,NULL,&oc);
605:       MatGetOwnershipRangeColumn(A,&stc,NULL);
606:       PetscMalloc1((dc+oc)/bs,&aux);
607:       for (i=0; i<dc/bs; i++) aux[i]       = i+stc/bs;
608:       for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
609:       ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);
610:     } else {
611:       ISCreateBlock(comm,1,0,NULL,PETSC_OWN_POINTER,&is);
612:     }
613:     ISLocalToGlobalMappingCreateIS(is,l2g);
614:     ISDestroy(&is);
615:     break;
616:   default:
617:     SETERRQ1(comm,PETSC_ERR_ARG_WRONG,"Unsupported l2g disassembling type %D",mode);
618:   }
619:   return(0);
620: }

622: PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
623: {
624:   Mat                    lA,Ad,Ao,B = NULL;
625:   ISLocalToGlobalMapping rl2g,cl2g;
626:   IS                     is;
627:   MPI_Comm               comm;
628:   void                   *ptrs[2];
629:   const char             *names[2] = {"_convert_csr_aux","_convert_csr_data"};
630:   const PetscInt         *garray;
631:   PetscScalar            *dd,*od,*aa,*data;
632:   const PetscInt         *di,*dj,*oi,*oj;
633:   const PetscInt         *odi,*odj,*ooi,*ooj;
634:   PetscInt               *aux,*ii,*jj;
635:   PetscInt               bs,lc,dr,dc,oc,str,stc,nnz,i,jd,jo,cum;
636:   PetscBool              flg,ismpiaij,ismpibaij,was_inplace = PETSC_FALSE;
637:   PetscMPIInt            size;
638:   PetscErrorCode         ierr;

641:   PetscObjectGetComm((PetscObject)A,&comm);
642:   MPI_Comm_size(comm,&size);
643:   if (size == 1) {
644:     MatConvert_SeqXAIJ_IS(A,type,reuse,newmat);
645:     return(0);
646:   }
647:   if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
648:     MatMPIXAIJComputeLocalToGlobalMapping_Private(A,&rl2g);
649:     MatCreate(comm,&B);
650:     MatSetType(B,MATIS);
651:     MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
652:     MatSetLocalToGlobalMapping(B,rl2g,rl2g);
653:     MatGetBlockSize(A,&bs);
654:     MatSetBlockSize(B,bs);
655:     ISLocalToGlobalMappingDestroy(&rl2g);
656:     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
657:     reuse = MAT_REUSE_MATRIX;
658:   }
659:   if (reuse == MAT_REUSE_MATRIX) {
660:     Mat            *newlA, lA;
661:     IS             rows, cols;
662:     const PetscInt *ridx, *cidx;
663:     PetscInt       rbs, cbs, nr, nc;

665:     if (!B) B = *newmat;
666:     MatGetLocalToGlobalMapping(B,&rl2g,&cl2g);
667:     ISLocalToGlobalMappingGetBlockIndices(rl2g,&ridx);
668:     ISLocalToGlobalMappingGetBlockIndices(cl2g,&cidx);
669:     ISLocalToGlobalMappingGetSize(rl2g,&nr);
670:     ISLocalToGlobalMappingGetSize(cl2g,&nc);
671:     ISLocalToGlobalMappingGetBlockSize(rl2g,&rbs);
672:     ISLocalToGlobalMappingGetBlockSize(cl2g,&cbs);
673:     ISCreateBlock(comm,rbs,nr/rbs,ridx,PETSC_USE_POINTER,&rows);
674:     if (rl2g != cl2g) {
675:       ISCreateBlock(comm,cbs,nc/cbs,cidx,PETSC_USE_POINTER,&cols);
676:     } else {
677:       PetscObjectReference((PetscObject)rows);
678:       cols = rows;
679:     }
680:     MatISGetLocalMat(B,&lA);
681:     MatCreateSubMatrices(A,1,&rows,&cols,MAT_INITIAL_MATRIX,&newlA);
682:     MatConvert(newlA[0],MATSEQAIJ,MAT_INPLACE_MATRIX,&newlA[0]);
683:     ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&ridx);
684:     ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&cidx);
685:     ISDestroy(&rows);
686:     ISDestroy(&cols);
687:     if (!lA->preallocated) { /* first time */
688:       MatDuplicate(newlA[0],MAT_COPY_VALUES,&lA);
689:       MatISSetLocalMat(B,lA);
690:       PetscObjectDereference((PetscObject)lA);
691:     }
692:     MatCopy(newlA[0],lA,SAME_NONZERO_PATTERN);
693:     MatDestroySubMatrices(1,&newlA);
694:     MatISScaleDisassembling_Private(B);
695:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
696:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
697:     if (was_inplace) { MatHeaderReplace(A,&B); }
698:     else *newmat = B;
699:     return(0);
700:   }
701:   /* rectangular case, just compress out the column space */
702:   PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);
703:   PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);
704:   if (ismpiaij) {
705:     bs   = 1;
706:     MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);
707:   } else if (ismpibaij) {
708:     MatGetBlockSize(A,&bs);
709:     MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);
710:     MatConvert(Ad,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ad);
711:     MatConvert(Ao,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ao);
712:   } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
713:   MatSeqAIJGetArray(Ad,&dd);
714:   MatSeqAIJGetArray(Ao,&od);
715:   if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");

717:   /* access relevant information from MPIAIJ */
718:   MatGetOwnershipRange(A,&str,NULL);
719:   MatGetOwnershipRangeColumn(A,&stc,NULL);
720:   MatGetLocalSize(A,&dr,&dc);
721:   MatGetLocalSize(Ao,NULL,&oc);
722:   MatGetRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&di,&dj,&flg);
723:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
724:   MatGetRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&oi,&oj,&flg);
725:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
726:   nnz = di[dr] + oi[dr];
727:   /* store original pointers to be restored later */
728:   odi = di; odj = dj; ooi = oi; ooj = oj;

730:   /* generate l2g maps for rows and cols */
731:   ISCreateStride(comm,dr/bs,str/bs,1,&is);
732:   if (bs > 1) {
733:     IS is2;

735:     ISGetLocalSize(is,&i);
736:     ISGetIndices(is,(const PetscInt**)&aux);
737:     ISCreateBlock(comm,bs,i,aux,PETSC_COPY_VALUES,&is2);
738:     ISRestoreIndices(is,(const PetscInt**)&aux);
739:     ISDestroy(&is);
740:     is   = is2;
741:   }
742:   ISLocalToGlobalMappingCreateIS(is,&rl2g);
743:   ISDestroy(&is);
744:   if (dr) {
745:     PetscMalloc1((dc+oc)/bs,&aux);
746:     for (i=0; i<dc/bs; i++) aux[i]       = i+stc/bs;
747:     for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
748:     ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);
749:     lc   = dc+oc;
750:   } else {
751:     ISCreateBlock(comm,bs,0,NULL,PETSC_OWN_POINTER,&is);
752:     lc   = 0;
753:   }
754:   ISLocalToGlobalMappingCreateIS(is,&cl2g);
755:   ISDestroy(&is);

757:   /* create MATIS object */
758:   MatCreate(comm,&B);
759:   MatSetSizes(B,dr,dc,PETSC_DECIDE,PETSC_DECIDE);
760:   MatSetType(B,MATIS);
761:   MatSetBlockSize(B,bs);
762:   MatSetLocalToGlobalMapping(B,rl2g,cl2g);
763:   ISLocalToGlobalMappingDestroy(&rl2g);
764:   ISLocalToGlobalMappingDestroy(&cl2g);

766:   /* merge local matrices */
767:   PetscMalloc1(nnz+dr+1,&aux);
768:   PetscMalloc1(nnz,&data);
769:   ii   = aux;
770:   jj   = aux+dr+1;
771:   aa   = data;
772:   *ii  = *(di++) + *(oi++);
773:   for (jd=0,jo=0,cum=0;*ii<nnz;cum++)
774:   {
775:      for (;jd<*di;jd++) { *jj++ = *dj++;      *aa++ = *dd++; }
776:      for (;jo<*oi;jo++) { *jj++ = *oj++ + dc; *aa++ = *od++; }
777:      *(++ii) = *(di++) + *(oi++);
778:   }
779:   for (;cum<dr;cum++) *(++ii) = nnz;

781:   MatRestoreRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&odi,&odj,&flg);
782:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
783:   MatRestoreRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&ooi,&ooj,&flg);
784:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
785:   MatSeqAIJRestoreArray(Ad,&dd);
786:   MatSeqAIJRestoreArray(Ao,&od);

788:   ii   = aux;
789:   jj   = aux+dr+1;
790:   aa   = data;
791:   MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,lc,ii,jj,aa,&lA);

793:   /* create containers to destroy the data */
794:   ptrs[0] = aux;
795:   ptrs[1] = data;
796:   for (i=0; i<2; i++) {
797:     PetscContainer c;

799:     PetscContainerCreate(PETSC_COMM_SELF,&c);
800:     PetscContainerSetPointer(c,ptrs[i]);
801:     PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault);
802:     PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);
803:     PetscContainerDestroy(&c);
804:   }
805:   if (ismpibaij) { /* destroy converted local matrices */
806:     MatDestroy(&Ad);
807:     MatDestroy(&Ao);
808:   }

810:   /* finalize matrix */
811:   MatISSetLocalMat(B,lA);
812:   MatDestroy(&lA);
813:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
814:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
815:   if (reuse == MAT_INPLACE_MATRIX) {
816:     MatHeaderReplace(A,&B);
817:   } else *newmat = B;
818:   return(0);
819: }

821: PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
822: {
823:   Mat                    **nest,*snest,**rnest,lA,B;
824:   IS                     *iscol,*isrow,*islrow,*islcol;
825:   ISLocalToGlobalMapping rl2g,cl2g;
826:   MPI_Comm               comm;
827:   PetscInt               *lr,*lc,*l2gidxs;
828:   PetscInt               i,j,nr,nc,rbs,cbs;
829:   PetscBool              convert,lreuse,*istrans;
830:   PetscErrorCode         ierr;

833:   MatNestGetSubMats(A,&nr,&nc,&nest);
834:   lreuse = PETSC_FALSE;
835:   rnest  = NULL;
836:   if (reuse == MAT_REUSE_MATRIX) {
837:     PetscBool ismatis,isnest;

839:     PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);
840:     if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_USER,"Cannot reuse matrix of type %s",((PetscObject)(*newmat))->type_name);
841:     MatISGetLocalMat(*newmat,&lA);
842:     PetscObjectTypeCompare((PetscObject)lA,MATNEST,&isnest);
843:     if (isnest) {
844:       MatNestGetSubMats(lA,&i,&j,&rnest);
845:       lreuse = (PetscBool)(i == nr && j == nc);
846:       if (!lreuse) rnest = NULL;
847:     }
848:   }
849:   PetscObjectGetComm((PetscObject)A,&comm);
850:   PetscCalloc2(nr,&lr,nc,&lc);
851:   PetscCalloc6(nr,&isrow,nc,&iscol,nr,&islrow,nc,&islcol,nr*nc,&snest,nr*nc,&istrans);
852:   MatNestGetISs(A,isrow,iscol);
853:   for (i=0;i<nr;i++) {
854:     for (j=0;j<nc;j++) {
855:       PetscBool ismatis;
856:       PetscInt  l1,l2,lb1,lb2,ij=i*nc+j;

858:       /* Null matrix pointers are allowed in MATNEST */
859:       if (!nest[i][j]) continue;

861:       /* Nested matrices should be of type MATIS */
862:       PetscObjectTypeCompare((PetscObject)nest[i][j],MATTRANSPOSEMAT,&istrans[ij]);
863:       if (istrans[ij]) {
864:         Mat T,lT;
865:         MatTransposeGetMat(nest[i][j],&T);
866:         PetscObjectTypeCompare((PetscObject)T,MATIS,&ismatis);
867:         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);
868:         MatISGetLocalMat(T,&lT);
869:         MatCreateTranspose(lT,&snest[ij]);
870:       } else {
871:         PetscObjectTypeCompare((PetscObject)nest[i][j],MATIS,&ismatis);
872:         if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) is not of type MATIS",i,j);
873:         MatISGetLocalMat(nest[i][j],&snest[ij]);
874:       }

876:       /* Check compatibility of local sizes */
877:       MatGetSize(snest[ij],&l1,&l2);
878:       MatGetBlockSizes(snest[ij],&lb1,&lb2);
879:       if (!l1 || !l2) continue;
880:       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);
881:       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);
882:       lr[i] = l1;
883:       lc[j] = l2;

885:       /* check compatibilty for local matrix reusage */
886:       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
887:     }
888:   }

890: #if defined (PETSC_USE_DEBUG)
891:   /* Check compatibility of l2g maps for rows */
892:   for (i=0;i<nr;i++) {
893:     rl2g = NULL;
894:     for (j=0;j<nc;j++) {
895:       PetscInt n1,n2;

897:       if (!nest[i][j]) continue;
898:       if (istrans[i*nc+j]) {
899:         Mat T;

901:         MatTransposeGetMat(nest[i][j],&T);
902:         MatGetLocalToGlobalMapping(T,NULL,&cl2g);
903:       } else {
904:         MatGetLocalToGlobalMapping(nest[i][j],&cl2g,NULL);
905:       }
906:       ISLocalToGlobalMappingGetSize(cl2g,&n1);
907:       if (!n1) continue;
908:       if (!rl2g) {
909:         rl2g = cl2g;
910:       } else {
911:         const PetscInt *idxs1,*idxs2;
912:         PetscBool      same;

914:         ISLocalToGlobalMappingGetSize(rl2g,&n2);
915:         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);
916:         ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);
917:         ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);
918:         PetscArraycmp(idxs1,idxs2,n1,&same);
919:         ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);
920:         ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);
921:         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);
922:       }
923:     }
924:   }
925:   /* Check compatibility of l2g maps for columns */
926:   for (i=0;i<nc;i++) {
927:     rl2g = NULL;
928:     for (j=0;j<nr;j++) {
929:       PetscInt n1,n2;

931:       if (!nest[j][i]) continue;
932:       if (istrans[j*nc+i]) {
933:         Mat T;

935:         MatTransposeGetMat(nest[j][i],&T);
936:         MatGetLocalToGlobalMapping(T,&cl2g,NULL);
937:       } else {
938:         MatGetLocalToGlobalMapping(nest[j][i],NULL,&cl2g);
939:       }
940:       ISLocalToGlobalMappingGetSize(cl2g,&n1);
941:       if (!n1) continue;
942:       if (!rl2g) {
943:         rl2g = cl2g;
944:       } else {
945:         const PetscInt *idxs1,*idxs2;
946:         PetscBool      same;

948:         ISLocalToGlobalMappingGetSize(rl2g,&n2);
949:         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);
950:         ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);
951:         ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);
952:         PetscArraycmp(idxs1,idxs2,n1,&same);
953:         ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);
954:         ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);
955:         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);
956:       }
957:     }
958:   }
959: #endif

961:   B = NULL;
962:   if (reuse != MAT_REUSE_MATRIX) {
963:     PetscInt stl;

965:     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
966:     for (i=0,stl=0;i<nr;i++) stl += lr[i];
967:     PetscMalloc1(stl,&l2gidxs);
968:     for (i=0,stl=0;i<nr;i++) {
969:       Mat            usedmat;
970:       Mat_IS         *matis;
971:       const PetscInt *idxs;

973:       /* local IS for local NEST */
974:       ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);

976:       /* l2gmap */
977:       j = 0;
978:       usedmat = nest[i][j];
979:       while (!usedmat && j < nc-1) usedmat = nest[i][++j];
980:       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid row mat");

982:       if (istrans[i*nc+j]) {
983:         Mat T;
984:         MatTransposeGetMat(usedmat,&T);
985:         usedmat = T;
986:       }
987:       matis = (Mat_IS*)(usedmat->data);
988:       ISGetIndices(isrow[i],&idxs);
989:       if (istrans[i*nc+j]) {
990:         PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
991:         PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
992:       } else {
993:         PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
994:         PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
995:       }
996:       ISRestoreIndices(isrow[i],&idxs);
997:       stl += lr[i];
998:     }
999:     ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&rl2g);

1001:     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
1002:     for (i=0,stl=0;i<nc;i++) stl += lc[i];
1003:     PetscMalloc1(stl,&l2gidxs);
1004:     for (i=0,stl=0;i<nc;i++) {
1005:       Mat            usedmat;
1006:       Mat_IS         *matis;
1007:       const PetscInt *idxs;

1009:       /* local IS for local NEST */
1010:       ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);

1012:       /* l2gmap */
1013:       j = 0;
1014:       usedmat = nest[j][i];
1015:       while (!usedmat && j < nr-1) usedmat = nest[++j][i];
1016:       if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid column mat");
1017:       if (istrans[j*nc+i]) {
1018:         Mat T;
1019:         MatTransposeGetMat(usedmat,&T);
1020:         usedmat = T;
1021:       }
1022:       matis = (Mat_IS*)(usedmat->data);
1023:       ISGetIndices(iscol[i],&idxs);
1024:       if (istrans[j*nc+i]) {
1025:         PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
1026:         PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
1027:       } else {
1028:         PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
1029:         PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
1030:       }
1031:       ISRestoreIndices(iscol[i],&idxs);
1032:       stl += lc[i];
1033:     }
1034:     ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&cl2g);

1036:     /* Create MATIS */
1037:     MatCreate(comm,&B);
1038:     MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
1039:     MatGetBlockSizes(A,&rbs,&cbs);
1040:     MatSetBlockSizes(B,rbs,cbs);
1041:     MatSetType(B,MATIS);
1042:     MatISSetLocalMatType(B,MATNEST);
1043:     { /* hack : avoid setup of scatters */
1044:       Mat_IS *matis = (Mat_IS*)(B->data);
1045:       matis->islocalref = PETSC_TRUE;
1046:     }
1047:     MatSetLocalToGlobalMapping(B,rl2g,cl2g);
1048:     ISLocalToGlobalMappingDestroy(&rl2g);
1049:     ISLocalToGlobalMappingDestroy(&cl2g);
1050:     MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);
1051:     MatNestSetVecType(lA,VECNEST);
1052:     for (i=0;i<nr*nc;i++) {
1053:       if (istrans[i]) {
1054:         MatDestroy(&snest[i]);
1055:       }
1056:     }
1057:     MatISSetLocalMat(B,lA);
1058:     MatDestroy(&lA);
1059:     { /* hack : setup of scatters done here */
1060:       Mat_IS *matis = (Mat_IS*)(B->data);

1062:       matis->islocalref = PETSC_FALSE;
1063:       MatISSetUpScatters_Private(B);
1064:     }
1065:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
1066:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
1067:     if (reuse == MAT_INPLACE_MATRIX) {
1068:       MatHeaderReplace(A,&B);
1069:     } else {
1070:       *newmat = B;
1071:     }
1072:   } else {
1073:     if (lreuse) {
1074:       MatISGetLocalMat(*newmat,&lA);
1075:       for (i=0;i<nr;i++) {
1076:         for (j=0;j<nc;j++) {
1077:           if (snest[i*nc+j]) {
1078:             MatNestSetSubMat(lA,i,j,snest[i*nc+j]);
1079:             if (istrans[i*nc+j]) {
1080:               MatDestroy(&snest[i*nc+j]);
1081:             }
1082:           }
1083:         }
1084:       }
1085:     } else {
1086:       PetscInt stl;
1087:       for (i=0,stl=0;i<nr;i++) {
1088:         ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);
1089:         stl  += lr[i];
1090:       }
1091:       for (i=0,stl=0;i<nc;i++) {
1092:         ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);
1093:         stl  += lc[i];
1094:       }
1095:       MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);
1096:       for (i=0;i<nr*nc;i++) {
1097:         if (istrans[i]) {
1098:           MatDestroy(&snest[i]);
1099:         }
1100:       }
1101:       MatISSetLocalMat(*newmat,lA);
1102:       MatDestroy(&lA);
1103:     }
1104:     MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);
1105:     MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);
1106:   }

1108:   /* Create local matrix in MATNEST format */
1109:   convert = PETSC_FALSE;
1110:   PetscOptionsGetBool(NULL,((PetscObject)A)->prefix,"-matis_convert_local_nest",&convert,NULL);
1111:   if (convert) {
1112:     Mat              M;
1113:     MatISLocalFields lf;
1114:     PetscContainer   c;

1116:     MatISGetLocalMat(*newmat,&lA);
1117:     MatConvert(lA,MATAIJ,MAT_INITIAL_MATRIX,&M);
1118:     MatISSetLocalMat(*newmat,M);
1119:     MatDestroy(&M);

1121:     /* attach local fields to the matrix */
1122:     PetscNew(&lf);
1123:     PetscMalloc2(nr,&lf->rf,nc,&lf->cf);
1124:     for (i=0;i<nr;i++) {
1125:       PetscInt n,st;

1127:       ISGetLocalSize(islrow[i],&n);
1128:       ISStrideGetInfo(islrow[i],&st,NULL);
1129:       ISCreateStride(comm,n,st,1,&lf->rf[i]);
1130:     }
1131:     for (i=0;i<nc;i++) {
1132:       PetscInt n,st;

1134:       ISGetLocalSize(islcol[i],&n);
1135:       ISStrideGetInfo(islcol[i],&st,NULL);
1136:       ISCreateStride(comm,n,st,1,&lf->cf[i]);
1137:     }
1138:     lf->nr = nr;
1139:     lf->nc = nc;
1140:     PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)),&c);
1141:     PetscContainerSetPointer(c,lf);
1142:     PetscContainerSetUserDestroy(c,MatISContainerDestroyFields_Private);
1143:     PetscObjectCompose((PetscObject)(*newmat),"_convert_nest_lfields",(PetscObject)c);
1144:     PetscContainerDestroy(&c);
1145:   }

1147:   /* Free workspace */
1148:   for (i=0;i<nr;i++) {
1149:     ISDestroy(&islrow[i]);
1150:   }
1151:   for (i=0;i<nc;i++) {
1152:     ISDestroy(&islcol[i]);
1153:   }
1154:   PetscFree6(isrow,iscol,islrow,islcol,snest,istrans);
1155:   PetscFree2(lr,lc);
1156:   return(0);
1157: }

1159: static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1160: {
1161:   Mat_IS            *matis = (Mat_IS*)A->data;
1162:   Vec               ll,rr;
1163:   const PetscScalar *Y,*X;
1164:   PetscScalar       *x,*y;
1165:   PetscErrorCode    ierr;

1168:   if (l) {
1169:     ll   = matis->y;
1170:     VecGetArrayRead(l,&Y);
1171:     VecGetArray(ll,&y);
1172:     PetscSFBcastBegin(matis->sf,MPIU_SCALAR,Y,y);
1173:   } else {
1174:     ll = NULL;
1175:   }
1176:   if (r) {
1177:     rr   = matis->x;
1178:     VecGetArrayRead(r,&X);
1179:     VecGetArray(rr,&x);
1180:     PetscSFBcastBegin(matis->csf,MPIU_SCALAR,X,x);
1181:   } else {
1182:     rr = NULL;
1183:   }
1184:   if (ll) {
1185:     PetscSFBcastEnd(matis->sf,MPIU_SCALAR,Y,y);
1186:     VecRestoreArrayRead(l,&Y);
1187:     VecRestoreArray(ll,&y);
1188:   }
1189:   if (rr) {
1190:     PetscSFBcastEnd(matis->csf,MPIU_SCALAR,X,x);
1191:     VecRestoreArrayRead(r,&X);
1192:     VecRestoreArray(rr,&x);
1193:   }
1194:   MatDiagonalScale(matis->A,ll,rr);
1195:   return(0);
1196: }

1198: static PetscErrorCode MatGetInfo_IS(Mat A,MatInfoType flag,MatInfo *ginfo)
1199: {
1200:   Mat_IS         *matis = (Mat_IS*)A->data;
1201:   MatInfo        info;
1202:   PetscLogDouble isend[6],irecv[6];
1203:   PetscInt       bs;

1207:   MatGetBlockSize(A,&bs);
1208:   if (matis->A->ops->getinfo) {
1209:     MatGetInfo(matis->A,MAT_LOCAL,&info);
1210:     isend[0] = info.nz_used;
1211:     isend[1] = info.nz_allocated;
1212:     isend[2] = info.nz_unneeded;
1213:     isend[3] = info.memory;
1214:     isend[4] = info.mallocs;
1215:   } else {
1216:     isend[0] = 0.;
1217:     isend[1] = 0.;
1218:     isend[2] = 0.;
1219:     isend[3] = 0.;
1220:     isend[4] = 0.;
1221:   }
1222:   isend[5] = matis->A->num_ass;
1223:   if (flag == MAT_LOCAL) {
1224:     ginfo->nz_used      = isend[0];
1225:     ginfo->nz_allocated = isend[1];
1226:     ginfo->nz_unneeded  = isend[2];
1227:     ginfo->memory       = isend[3];
1228:     ginfo->mallocs      = isend[4];
1229:     ginfo->assemblies   = isend[5];
1230:   } else if (flag == MAT_GLOBAL_MAX) {
1231:     MPIU_Allreduce(isend,irecv,6,MPIU_PETSCLOGDOUBLE,MPI_MAX,PetscObjectComm((PetscObject)A));

1233:     ginfo->nz_used      = irecv[0];
1234:     ginfo->nz_allocated = irecv[1];
1235:     ginfo->nz_unneeded  = irecv[2];
1236:     ginfo->memory       = irecv[3];
1237:     ginfo->mallocs      = irecv[4];
1238:     ginfo->assemblies   = irecv[5];
1239:   } else if (flag == MAT_GLOBAL_SUM) {
1240:     MPIU_Allreduce(isend,irecv,5,MPIU_PETSCLOGDOUBLE,MPI_SUM,PetscObjectComm((PetscObject)A));

1242:     ginfo->nz_used      = irecv[0];
1243:     ginfo->nz_allocated = irecv[1];
1244:     ginfo->nz_unneeded  = irecv[2];
1245:     ginfo->memory       = irecv[3];
1246:     ginfo->mallocs      = irecv[4];
1247:     ginfo->assemblies   = A->num_ass;
1248:   }
1249:   ginfo->block_size        = bs;
1250:   ginfo->fill_ratio_given  = 0;
1251:   ginfo->fill_ratio_needed = 0;
1252:   ginfo->factor_mallocs    = 0;
1253:   return(0);
1254: }

1256: PetscErrorCode MatTranspose_IS(Mat A,MatReuse reuse,Mat *B)
1257: {
1258:   Mat                    C,lC,lA;
1259:   PetscErrorCode         ierr;

1262:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1263:     ISLocalToGlobalMapping rl2g,cl2g;
1264:     MatCreate(PetscObjectComm((PetscObject)A),&C);
1265:     MatSetSizes(C,A->cmap->n,A->rmap->n,A->cmap->N,A->rmap->N);
1266:     MatSetBlockSizes(C,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs));
1267:     MatSetType(C,MATIS);
1268:     MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);
1269:     MatSetLocalToGlobalMapping(C,cl2g,rl2g);
1270:   } else {
1271:     C = *B;
1272:   }

1274:   /* perform local transposition */
1275:   MatISGetLocalMat(A,&lA);
1276:   MatTranspose(lA,MAT_INITIAL_MATRIX,&lC);
1277:   MatISSetLocalMat(C,lC);
1278:   MatDestroy(&lC);

1280:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1281:     *B = C;
1282:   } else {
1283:     MatHeaderMerge(A,&C);
1284:   }
1285:   MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
1286:   MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
1287:   return(0);
1288: }

1290: PetscErrorCode  MatDiagonalSet_IS(Mat A,Vec D,InsertMode insmode)
1291: {
1292:   Mat_IS         *is = (Mat_IS*)A->data;

1296:   if (D) { /* MatShift_IS pass D = NULL */
1297:     VecScatterBegin(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);
1298:     VecScatterEnd(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);
1299:   }
1300:   VecPointwiseDivide(is->y,is->y,is->counter);
1301:   MatDiagonalSet(is->A,is->y,insmode);
1302:   return(0);
1303: }

1305: PetscErrorCode  MatShift_IS(Mat A,PetscScalar a)
1306: {
1307:   Mat_IS         *is = (Mat_IS*)A->data;

1311:   VecSet(is->y,a);
1312:   MatDiagonalSet_IS(A,NULL,ADD_VALUES);
1313:   return(0);
1314: }

1316: static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1317: {
1319:   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];

1322: #if defined(PETSC_USE_DEBUG)
1323:   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);
1324: #endif
1325:   ISLocalToGlobalMappingApply(A->rmap->mapping,m,rows,rows_l);
1326:   ISLocalToGlobalMappingApply(A->cmap->mapping,n,cols,cols_l);
1327:   MatSetValuesLocal_IS(A,m,rows_l,n,cols_l,values,addv);
1328:   return(0);
1329: }

1331: static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1332: {
1334:   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];

1337: #if defined(PETSC_USE_DEBUG)
1338:   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);
1339: #endif
1340:   ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,m,rows,rows_l);
1341:   ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,n,cols,cols_l);
1342:   MatSetValuesBlockedLocal_IS(A,m,rows_l,n,cols_l,values,addv);
1343:   return(0);
1344: }

1346: static PetscErrorCode MatCreateSubMatrix_IS(Mat mat,IS irow,IS icol,MatReuse scall,Mat *newmat)
1347: {
1348:   Mat               locmat,newlocmat;
1349:   Mat_IS            *newmatis;
1350: #if defined(PETSC_USE_DEBUG)
1351:   Vec               rtest,ltest;
1352:   const PetscScalar *array;
1353: #endif
1354:   const PetscInt    *idxs;
1355:   PetscInt          i,m,n;
1356:   PetscErrorCode    ierr;

1359:   if (scall == MAT_REUSE_MATRIX) {
1360:     PetscBool ismatis;

1362:     PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);
1363:     if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Not of MATIS type");
1364:     newmatis = (Mat_IS*)(*newmat)->data;
1365:     if (!newmatis->getsub_ris) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local row IS");
1366:     if (!newmatis->getsub_cis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local col IS");
1367:   }
1368:   /* irow and icol may not have duplicate entries */
1369: #if defined(PETSC_USE_DEBUG)
1370:   MatCreateVecs(mat,&ltest,&rtest);
1371:   ISGetLocalSize(irow,&n);
1372:   ISGetIndices(irow,&idxs);
1373:   for (i=0;i<n;i++) {
1374:     VecSetValue(rtest,idxs[i],1.0,ADD_VALUES);
1375:   }
1376:   VecAssemblyBegin(rtest);
1377:   VecAssemblyEnd(rtest);
1378:   VecGetLocalSize(rtest,&n);
1379:   VecGetOwnershipRange(rtest,&m,NULL);
1380:   VecGetArrayRead(rtest,&array);
1381:   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]));
1382:   VecRestoreArrayRead(rtest,&array);
1383:   ISRestoreIndices(irow,&idxs);
1384:   ISGetLocalSize(icol,&n);
1385:   ISGetIndices(icol,&idxs);
1386:   for (i=0;i<n;i++) {
1387:     VecSetValue(ltest,idxs[i],1.0,ADD_VALUES);
1388:   }
1389:   VecAssemblyBegin(ltest);
1390:   VecAssemblyEnd(ltest);
1391:   VecGetLocalSize(ltest,&n);
1392:   VecGetOwnershipRange(ltest,&m,NULL);
1393:   VecGetArrayRead(ltest,&array);
1394:   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]));
1395:   VecRestoreArrayRead(ltest,&array);
1396:   ISRestoreIndices(icol,&idxs);
1397:   VecDestroy(&rtest);
1398:   VecDestroy(&ltest);
1399: #endif
1400:   if (scall == MAT_INITIAL_MATRIX) {
1401:     Mat_IS                 *matis = (Mat_IS*)mat->data;
1402:     ISLocalToGlobalMapping rl2g;
1403:     IS                     is;
1404:     PetscInt               *lidxs,*lgidxs,*newgidxs;
1405:     PetscInt               ll,newloc,irbs,icbs,arbs,acbs,rbs,cbs;
1406:     PetscBool              cong;
1407:     MPI_Comm               comm;

1409:     PetscObjectGetComm((PetscObject)mat,&comm);
1410:     MatGetBlockSizes(mat,&arbs,&acbs);
1411:     ISGetBlockSize(irow,&irbs);
1412:     ISGetBlockSize(icol,&icbs);
1413:     rbs  = arbs == irbs ? irbs : 1;
1414:     cbs  = acbs == icbs ? icbs : 1;
1415:     ISGetLocalSize(irow,&m);
1416:     ISGetLocalSize(icol,&n);
1417:     MatCreate(comm,newmat);
1418:     MatSetType(*newmat,MATIS);
1419:     MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE);
1420:     MatSetBlockSizes(*newmat,rbs,cbs);
1421:     /* communicate irow to their owners in the layout */
1422:     ISGetIndices(irow,&idxs);
1423:     PetscLayoutMapLocal(mat->rmap,m,idxs,&ll,&lidxs,&lgidxs);
1424:     ISRestoreIndices(irow,&idxs);
1425:     PetscArrayzero(matis->sf_rootdata,matis->sf->nroots);
1426:     for (i=0;i<ll;i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i]+1;
1427:     PetscFree(lidxs);
1428:     PetscFree(lgidxs);
1429:     PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1430:     PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1431:     for (i=0,newloc=0;i<matis->sf->nleaves;i++) if (matis->sf_leafdata[i]) newloc++;
1432:     PetscMalloc1(newloc,&newgidxs);
1433:     PetscMalloc1(newloc,&lidxs);
1434:     for (i=0,newloc=0;i<matis->sf->nleaves;i++)
1435:       if (matis->sf_leafdata[i]) {
1436:         lidxs[newloc] = i;
1437:         newgidxs[newloc++] = matis->sf_leafdata[i]-1;
1438:       }
1439:     ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);
1440:     ISLocalToGlobalMappingCreateIS(is,&rl2g);
1441:     ISLocalToGlobalMappingSetBlockSize(rl2g,rbs);
1442:     ISDestroy(&is);
1443:     /* local is to extract local submatrix */
1444:     newmatis = (Mat_IS*)(*newmat)->data;
1445:     ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_ris);
1446:     MatHasCongruentLayouts(mat,&cong);
1447:     if (cong && irow == icol && matis->csf == matis->sf) {
1448:       MatSetLocalToGlobalMapping(*newmat,rl2g,rl2g);
1449:       PetscObjectReference((PetscObject)newmatis->getsub_ris);
1450:       newmatis->getsub_cis = newmatis->getsub_ris;
1451:     } else {
1452:       ISLocalToGlobalMapping cl2g;

1454:       /* communicate icol to their owners in the layout */
1455:       ISGetIndices(icol,&idxs);
1456:       PetscLayoutMapLocal(mat->cmap,n,idxs,&ll,&lidxs,&lgidxs);
1457:       ISRestoreIndices(icol,&idxs);
1458:       PetscArrayzero(matis->csf_rootdata,matis->csf->nroots);
1459:       for (i=0;i<ll;i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i]+1;
1460:       PetscFree(lidxs);
1461:       PetscFree(lgidxs);
1462:       PetscSFBcastBegin(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);
1463:       PetscSFBcastEnd(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);
1464:       for (i=0,newloc=0;i<matis->csf->nleaves;i++) if (matis->csf_leafdata[i]) newloc++;
1465:       PetscMalloc1(newloc,&newgidxs);
1466:       PetscMalloc1(newloc,&lidxs);
1467:       for (i=0,newloc=0;i<matis->csf->nleaves;i++)
1468:         if (matis->csf_leafdata[i]) {
1469:           lidxs[newloc] = i;
1470:           newgidxs[newloc++] = matis->csf_leafdata[i]-1;
1471:         }
1472:       ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);
1473:       ISLocalToGlobalMappingCreateIS(is,&cl2g);
1474:       ISLocalToGlobalMappingSetBlockSize(cl2g,cbs);
1475:       ISDestroy(&is);
1476:       /* local is to extract local submatrix */
1477:       ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_cis);
1478:       MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g);
1479:       ISLocalToGlobalMappingDestroy(&cl2g);
1480:     }
1481:     ISLocalToGlobalMappingDestroy(&rl2g);
1482:   } else {
1483:     MatISGetLocalMat(*newmat,&newlocmat);
1484:   }
1485:   MatISGetLocalMat(mat,&locmat);
1486:   newmatis = (Mat_IS*)(*newmat)->data;
1487:   MatCreateSubMatrix(locmat,newmatis->getsub_ris,newmatis->getsub_cis,scall,&newlocmat);
1488:   if (scall == MAT_INITIAL_MATRIX) {
1489:     MatISSetLocalMat(*newmat,newlocmat);
1490:     MatDestroy(&newlocmat);
1491:   }
1492:   MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);
1493:   MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);
1494:   return(0);
1495: }

1497: static PetscErrorCode MatCopy_IS(Mat A,Mat B,MatStructure str)
1498: {
1499:   Mat_IS         *a = (Mat_IS*)A->data,*b;
1500:   PetscBool      ismatis;

1504:   PetscObjectTypeCompare((PetscObject)B,MATIS,&ismatis);
1505:   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Need to be implemented");
1506:   b = (Mat_IS*)B->data;
1507:   MatCopy(a->A,b->A,str);
1508:   PetscObjectStateIncrease((PetscObject)B);
1509:   return(0);
1510: }

1512: static PetscErrorCode MatMissingDiagonal_IS(Mat A,PetscBool  *missing,PetscInt *d)
1513: {
1514:   Vec               v;
1515:   const PetscScalar *array;
1516:   PetscInt          i,n;
1517:   PetscErrorCode    ierr;

1520:   *missing = PETSC_FALSE;
1521:   MatCreateVecs(A,NULL,&v);
1522:   MatGetDiagonal(A,v);
1523:   VecGetLocalSize(v,&n);
1524:   VecGetArrayRead(v,&array);
1525:   for (i=0;i<n;i++) if (array[i] == 0.) break;
1526:   VecRestoreArrayRead(v,&array);
1527:   VecDestroy(&v);
1528:   if (i != n) *missing = PETSC_TRUE;
1529:   if (d) {
1530:     *d = -1;
1531:     if (*missing) {
1532:       PetscInt rstart;
1533:       MatGetOwnershipRange(A,&rstart,NULL);
1534:       *d = i+rstart;
1535:     }
1536:   }
1537:   return(0);
1538: }

1540: static PetscErrorCode MatISSetUpSF_IS(Mat B)
1541: {
1542:   Mat_IS         *matis = (Mat_IS*)(B->data);
1543:   const PetscInt *gidxs;
1544:   PetscInt       nleaves;

1548:   if (matis->sf) return(0);
1549:   PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);
1550:   ISLocalToGlobalMappingGetIndices(B->rmap->mapping,&gidxs);
1551:   ISLocalToGlobalMappingGetSize(B->rmap->mapping,&nleaves);
1552:   PetscSFSetGraphLayout(matis->sf,B->rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);
1553:   ISLocalToGlobalMappingRestoreIndices(B->rmap->mapping,&gidxs);
1554:   PetscMalloc2(matis->sf->nroots,&matis->sf_rootdata,matis->sf->nleaves,&matis->sf_leafdata);
1555:   if (B->rmap->mapping != B->cmap->mapping) { /* setup SF for columns */
1556:     ISLocalToGlobalMappingGetSize(B->cmap->mapping,&nleaves);
1557:     PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->csf);
1558:     ISLocalToGlobalMappingGetIndices(B->cmap->mapping,&gidxs);
1559:     PetscSFSetGraphLayout(matis->csf,B->cmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);
1560:     ISLocalToGlobalMappingRestoreIndices(B->cmap->mapping,&gidxs);
1561:     PetscMalloc2(matis->csf->nroots,&matis->csf_rootdata,matis->csf->nleaves,&matis->csf_leafdata);
1562:   } else {
1563:     matis->csf = matis->sf;
1564:     matis->csf_leafdata = matis->sf_leafdata;
1565:     matis->csf_rootdata = matis->sf_rootdata;
1566:   }
1567:   return(0);
1568: }

1570: /*@
1571:    MatISStoreL2L - Store local-to-local operators during the Galerkin process of MatPtAP.

1573:    Collective

1575:    Input Parameters:
1576: +  A - the matrix
1577: -  store - the boolean flag

1579:    Level: advanced

1581:    Notes:

1583: .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatPtAP()
1584: @*/
1585: PetscErrorCode  MatISStoreL2L(Mat A, PetscBool store)
1586: {

1593:   PetscTryMethod(A,"MatISStoreL2L_C",(Mat,PetscBool),(A,store));
1594:   return(0);
1595: }

1597: static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1598: {
1599:   Mat_IS         *matis = (Mat_IS*)(A->data);

1603:   matis->storel2l = store;
1604:   if (!store) {
1605:     PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",NULL);
1606:   }
1607:   return(0);
1608: }

1610: /*@
1611:    MatISFixLocalEmpty - Compress out zero local rows from the local matrices

1613:    Collective

1615:    Input Parameters:
1616: +  A - the matrix
1617: -  fix - the boolean flag

1619:    Level: advanced

1621:    Notes: When fix is true, new local matrices and l2g maps are generated during the final assembly process.

1623: .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatAssemblyEnd(), MAT_FINAL_ASSEMBLY
1624: @*/
1625: PetscErrorCode  MatISFixLocalEmpty(Mat A, PetscBool fix)
1626: {

1633:   PetscTryMethod(A,"MatISFixLocalEmpty_C",(Mat,PetscBool),(A,fix));
1634:   return(0);
1635: }

1637: static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1638: {
1639:   Mat_IS *matis = (Mat_IS*)(A->data);

1642:   matis->locempty = fix;
1643:   return(0);
1644: }

1646: /*@
1647:    MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.

1649:    Collective

1651:    Input Parameters:
1652: +  B - the matrix
1653: .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1654:            (same value is used for all local rows)
1655: .  d_nnz - array containing the number of nonzeros in the various rows of the
1656:            DIAGONAL portion of the local submatrix (possibly different for each row)
1657:            or NULL, if d_nz is used to specify the nonzero structure.
1658:            The size of this array is equal to the number of local rows, i.e 'm'.
1659:            For matrices that will be factored, you must leave room for (and set)
1660:            the diagonal entry even if it is zero.
1661: .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1662:            submatrix (same value is used for all local rows).
1663: -  o_nnz - array containing the number of nonzeros in the various rows of the
1664:            OFF-DIAGONAL portion of the local submatrix (possibly different for
1665:            each row) or NULL, if o_nz is used to specify the nonzero
1666:            structure. The size of this array is equal to the number
1667:            of local rows, i.e 'm'.

1669:    If the *_nnz parameter is given then the *_nz parameter is ignored

1671:    Level: intermediate

1673:    Notes:
1674:     This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
1675:           from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
1676:           matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.

1678: .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat(), MATIS
1679: @*/
1680: PetscErrorCode  MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1681: {

1687:   PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));
1688:   return(0);
1689: }

1691: /* this is used by DMDA */
1692: PETSC_EXTERN PetscErrorCode  MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1693: {
1694:   Mat_IS         *matis = (Mat_IS*)(B->data);
1695:   PetscInt       bs,i,nlocalcols;

1699:   if (!matis->A) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping");

1701:   if (!d_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nz;
1702:   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nnz[i];

1704:   if (!o_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nz;
1705:   else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nnz[i];

1707:   PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1708:   MatGetSize(matis->A,NULL,&nlocalcols);
1709:   MatGetBlockSize(matis->A,&bs);
1710:   PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);

1712:   for (i=0;i<matis->sf->nleaves;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols);
1713:   MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);
1714: #if defined(PETSC_HAVE_HYPRE)
1715:   MatHYPRESetPreallocation(matis->A,0,matis->sf_leafdata,0,NULL);
1716: #endif

1718:   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs;
1719:   MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);

1721:   nlocalcols /= bs;
1722:   for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols - i);
1723:   MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);

1725:   /* for other matrix types */
1726:   MatSetUp(matis->A);
1727:   return(0);
1728: }

1730: PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1731: {
1732:   Mat_IS          *matis = (Mat_IS*)(A->data);
1733:   PetscInt        *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership;
1734:   const PetscInt  *global_indices_r,*global_indices_c;
1735:   PetscInt        i,j,bs,rows,cols;
1736:   PetscInt        lrows,lcols;
1737:   PetscInt        local_rows,local_cols;
1738:   PetscMPIInt     size;
1739:   PetscBool       isdense,issbaij;
1740:   PetscErrorCode  ierr;

1743:   MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
1744:   MatGetSize(A,&rows,&cols);
1745:   MatGetBlockSize(A,&bs);
1746:   MatGetSize(matis->A,&local_rows,&local_cols);
1747:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);
1748:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);
1749:   ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_r);
1750:   if (A->rmap->mapping != A->cmap->mapping) {
1751:     ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&global_indices_c);
1752:   } else {
1753:     global_indices_c = global_indices_r;
1754:   }

1756:   if (issbaij) {
1757:     MatGetRowUpperTriangular(matis->A);
1758:   }
1759:   /*
1760:      An SF reduce is needed to sum up properly on shared rows.
1761:      Note that generally preallocation is not exact, since it overestimates nonzeros
1762:   */
1763:   MatGetLocalSize(A,&lrows,&lcols);
1764:   MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);
1765:   /* All processes need to compute entire row ownership */
1766:   PetscMalloc1(rows,&row_ownership);
1767:   MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);
1768:   for (i=0;i<size;i++) {
1769:     for (j=mat_ranges[i];j<mat_ranges[i+1];j++) {
1770:       row_ownership[j] = i;
1771:     }
1772:   }
1773:   MatGetOwnershipRangesColumn(A,(const PetscInt**)&mat_ranges);

1775:   /*
1776:      my_dnz and my_onz contains exact contribution to preallocation from each local mat
1777:      then, they will be summed up properly. This way, preallocation is always sufficient
1778:   */
1779:   PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);
1780:   /* preallocation as a MATAIJ */
1781:   if (isdense) { /* special case for dense local matrices */
1782:     for (i=0;i<local_rows;i++) {
1783:       PetscInt owner = row_ownership[global_indices_r[i]];
1784:       for (j=0;j<local_cols;j++) {
1785:         PetscInt index_col = global_indices_c[j];
1786:         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1]) { /* diag block */
1787:           my_dnz[i] += 1;
1788:         } else { /* offdiag block */
1789:           my_onz[i] += 1;
1790:         }
1791:       }
1792:     }
1793:   } else if (matis->A->ops->getrowij) {
1794:     const PetscInt *ii,*jj,*jptr;
1795:     PetscBool      done;
1796:     MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);
1797:     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
1798:     jptr = jj;
1799:     for (i=0;i<local_rows;i++) {
1800:       PetscInt index_row = global_indices_r[i];
1801:       for (j=0;j<ii[i+1]-ii[i];j++,jptr++) {
1802:         PetscInt owner = row_ownership[index_row];
1803:         PetscInt index_col = global_indices_c[*jptr];
1804:         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1805:           my_dnz[i] += 1;
1806:         } else { /* offdiag block */
1807:           my_onz[i] += 1;
1808:         }
1809:         /* same as before, interchanging rows and cols */
1810:         if (issbaij && index_col != index_row) {
1811:           owner = row_ownership[index_col];
1812:           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1813:             my_dnz[*jptr] += 1;
1814:           } else {
1815:             my_onz[*jptr] += 1;
1816:           }
1817:         }
1818:       }
1819:     }
1820:     MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);
1821:     if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
1822:   } else { /* loop over rows and use MatGetRow */
1823:     for (i=0;i<local_rows;i++) {
1824:       const PetscInt *cols;
1825:       PetscInt       ncols,index_row = global_indices_r[i];
1826:       MatGetRow(matis->A,i,&ncols,&cols,NULL);
1827:       for (j=0;j<ncols;j++) {
1828:         PetscInt owner = row_ownership[index_row];
1829:         PetscInt index_col = global_indices_c[cols[j]];
1830:         if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1831:           my_dnz[i] += 1;
1832:         } else { /* offdiag block */
1833:           my_onz[i] += 1;
1834:         }
1835:         /* same as before, interchanging rows and cols */
1836:         if (issbaij && index_col != index_row) {
1837:           owner = row_ownership[index_col];
1838:           if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1839:             my_dnz[cols[j]] += 1;
1840:           } else {
1841:             my_onz[cols[j]] += 1;
1842:           }
1843:         }
1844:       }
1845:       MatRestoreRow(matis->A,i,&ncols,&cols,NULL);
1846:     }
1847:   }
1848:   if (global_indices_c != global_indices_r) {
1849:     ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&global_indices_c);
1850:   }
1851:   ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_r);
1852:   PetscFree(row_ownership);

1854:   /* Reduce my_dnz and my_onz */
1855:   if (maxreduce) {
1856:     PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);
1857:     PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);
1858:     PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);
1859:     PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);
1860:   } else {
1861:     PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);
1862:     PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);
1863:     PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);
1864:     PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);
1865:   }
1866:   PetscFree2(my_dnz,my_onz);

1868:   /* Resize preallocation if overestimated */
1869:   for (i=0;i<lrows;i++) {
1870:     dnz[i] = PetscMin(dnz[i],lcols);
1871:     onz[i] = PetscMin(onz[i],cols-lcols);
1872:   }

1874:   /* Set preallocation */
1875:   MatSeqAIJSetPreallocation(B,0,dnz);
1876:   MatMPIAIJSetPreallocation(B,0,dnz,0,onz);
1877:   for (i=0;i<lrows;i+=bs) {
1878:     PetscInt b, d = dnz[i],o = onz[i];

1880:     for (b=1;b<bs;b++) {
1881:       d = PetscMax(d,dnz[i+b]);
1882:       o = PetscMax(o,onz[i+b]);
1883:     }
1884:     dnz[i/bs] = PetscMin(d/bs + d%bs,lcols/bs);
1885:     onz[i/bs] = PetscMin(o/bs + o%bs,(cols-lcols)/bs);
1886:   }
1887:   MatSeqBAIJSetPreallocation(B,bs,0,dnz);
1888:   MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);
1889:   MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);
1890:   MatPreallocateFinalize(dnz,onz);
1891:   if (issbaij) {
1892:     MatRestoreRowUpperTriangular(matis->A);
1893:   }
1894:   MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
1895:   return(0);
1896: }

1898: PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1899: {
1900:   Mat_IS            *matis = (Mat_IS*)(mat->data);
1901:   Mat               local_mat,MT;
1902:   PetscInt          rbs,cbs,rows,cols,lrows,lcols;
1903:   PetscInt          local_rows,local_cols;
1904:   PetscBool         isseqdense,isseqsbaij,isseqaij,isseqbaij;
1905: #if defined (PETSC_USE_DEBUG)
1906:   PetscBool         lb[4],bb[4];
1907: #endif
1908:   PetscMPIInt       size;
1909:   const PetscScalar *array;
1910:   PetscErrorCode    ierr;

1913:   MPI_Comm_size(PetscObjectComm((PetscObject)mat),&size);
1914:   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
1915:     Mat      B;
1916:     IS       irows = NULL,icols = NULL;
1917:     PetscInt rbs,cbs;

1919:     ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
1920:     ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
1921:     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
1922:       IS             rows,cols;
1923:       const PetscInt *ridxs,*cidxs;
1924:       PetscInt       i,nw,*work;

1926:       ISLocalToGlobalMappingGetBlockIndices(mat->rmap->mapping,&ridxs);
1927:       ISLocalToGlobalMappingGetSize(mat->rmap->mapping,&nw);
1928:       nw   = nw/rbs;
1929:       PetscCalloc1(nw,&work);
1930:       for (i=0;i<nw;i++) work[ridxs[i]] += 1;
1931:       for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
1932:       if (i == nw) {
1933:         ISCreateBlock(PETSC_COMM_SELF,rbs,nw,ridxs,PETSC_USE_POINTER,&rows);
1934:         ISSetPermutation(rows);
1935:         ISInvertPermutation(rows,PETSC_DECIDE,&irows);
1936:         ISDestroy(&rows);
1937:       }
1938:       ISLocalToGlobalMappingRestoreBlockIndices(mat->rmap->mapping,&ridxs);
1939:       PetscFree(work);
1940:       if (irows && mat->rmap->mapping != mat->cmap->mapping) {
1941:         ISLocalToGlobalMappingGetBlockIndices(mat->cmap->mapping,&cidxs);
1942:         ISLocalToGlobalMappingGetSize(mat->cmap->mapping,&nw);
1943:         nw   = nw/cbs;
1944:         PetscCalloc1(nw,&work);
1945:         for (i=0;i<nw;i++) work[cidxs[i]] += 1;
1946:         for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
1947:         if (i == nw) {
1948:           ISCreateBlock(PETSC_COMM_SELF,cbs,nw,cidxs,PETSC_USE_POINTER,&cols);
1949:           ISSetPermutation(cols);
1950:           ISInvertPermutation(cols,PETSC_DECIDE,&icols);
1951:           ISDestroy(&cols);
1952:         }
1953:         ISLocalToGlobalMappingRestoreBlockIndices(mat->cmap->mapping,&cidxs);
1954:         PetscFree(work);
1955:       } else if (irows) {
1956:         PetscObjectReference((PetscObject)irows);
1957:         icols = irows;
1958:       }
1959:     } else {
1960:       PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject*)&irows);
1961:       PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject*)&icols);
1962:       if (irows) { PetscObjectReference((PetscObject)irows); }
1963:       if (icols) { PetscObjectReference((PetscObject)icols); }
1964:     }
1965:     if (!irows || !icols) {
1966:       ISDestroy(&icols);
1967:       ISDestroy(&irows);
1968:       goto general_assembly;
1969:     }
1970:     MatConvert(matis->A,mtype,MAT_INITIAL_MATRIX,&B);
1971:     if (reuse != MAT_INPLACE_MATRIX) {
1972:       MatCreateSubMatrix(B,irows,icols,reuse,M);
1973:       PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject)irows);
1974:       PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject)icols);
1975:     } else {
1976:       Mat C;

1978:       MatCreateSubMatrix(B,irows,icols,MAT_INITIAL_MATRIX,&C);
1979:       MatHeaderReplace(mat,&C);
1980:     }
1981:     MatDestroy(&B);
1982:     ISDestroy(&icols);
1983:     ISDestroy(&irows);
1984:     return(0);
1985:   }
1986: general_assembly:
1987:   MatGetSize(mat,&rows,&cols);
1988:   ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
1989:   ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
1990:   MatGetLocalSize(mat,&lrows,&lcols);
1991:   MatGetSize(matis->A,&local_rows,&local_cols);
1992:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isseqdense);
1993:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);
1994:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQBAIJ,&isseqbaij);
1995:   PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&isseqsbaij);
1996:   if (!isseqdense && !isseqaij && !isseqbaij && !isseqsbaij) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(matis->A))->type_name);
1997: #if defined (PETSC_USE_DEBUG)
1998:   lb[0] = isseqdense;
1999:   lb[1] = isseqaij;
2000:   lb[2] = isseqbaij;
2001:   lb[3] = isseqsbaij;
2002:   MPIU_Allreduce(lb,bb,4,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));
2003:   if (!bb[0] && !bb[1] && !bb[2] && !bb[3]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Local matrices must have the same type");
2004: #endif

2006:   if (reuse != MAT_REUSE_MATRIX) {
2007:     MatCreate(PetscObjectComm((PetscObject)mat),&MT);
2008:     MatSetSizes(MT,lrows,lcols,rows,cols);
2009:     MatSetType(MT,mtype);
2010:     MatSetBlockSizes(MT,rbs,cbs);
2011:     MatISSetMPIXAIJPreallocation_Private(mat,MT,PETSC_FALSE);
2012:   } else {
2013:     PetscInt mrbs,mcbs,mrows,mcols,mlrows,mlcols;

2015:     /* some checks */
2016:     MT   = *M;
2017:     MatGetBlockSizes(MT,&mrbs,&mcbs);
2018:     MatGetSize(MT,&mrows,&mcols);
2019:     MatGetLocalSize(MT,&mlrows,&mlcols);
2020:     if (mrows != rows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows);
2021:     if (mcols != cols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols);
2022:     if (mlrows != lrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows);
2023:     if (mlcols != lcols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols);
2024:     if (mrbs != rbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong row block size (%d != %d)",rbs,mrbs);
2025:     if (mcbs != cbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong col block size (%d != %d)",cbs,mcbs);
2026:     MatZeroEntries(MT);
2027:   }

2029:   if (isseqsbaij || isseqbaij) {
2030:     MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&local_mat);
2031:     isseqaij = PETSC_TRUE;
2032:   } else {
2033:     PetscObjectReference((PetscObject)matis->A);
2034:     local_mat = matis->A;
2035:   }

2037:   /* Set values */
2038:   MatSetLocalToGlobalMapping(MT,mat->rmap->mapping,mat->cmap->mapping);
2039:   if (isseqdense) { /* special case for dense local matrices */
2040:     PetscInt          i,*dummy;

2042:     PetscMalloc1(PetscMax(local_rows,local_cols),&dummy);
2043:     for (i=0;i<PetscMax(local_rows,local_cols);i++) dummy[i] = i;
2044:     MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_FALSE);
2045:     MatDenseGetArrayRead(local_mat,&array);
2046:     MatSetValuesLocal(MT,local_rows,dummy,local_cols,dummy,array,ADD_VALUES);
2047:     MatDenseRestoreArrayRead(local_mat,&array);
2048:     PetscFree(dummy);
2049:   } else if (isseqaij) {
2050:     const PetscInt *blocks;
2051:     PetscInt       i,nvtxs,*xadj,*adjncy, nb;
2052:     PetscBool      done;
2053:     PetscScalar    *sarray;

2055:     MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);
2056:     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
2057:     MatSeqAIJGetArray(local_mat,&sarray);
2058:     MatGetVariableBlockSizes(local_mat,&nb,&blocks);
2059:     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
2060:       PetscInt sum;

2062:       for (i=0,sum=0;i<nb;i++) sum += blocks[i];
2063:       if (sum == nvtxs) {
2064:         PetscInt r;

2066:         for (i=0,r=0;i<nb;i++) {
2067: #if defined(PETSC_USE_DEBUG)
2068:           if (blocks[i] != xadj[r+1] - xadj[r]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Invalid block sizes prescribed for block %D: expected %D, got %D",i,blocks[i],xadj[r+1] - xadj[r]);
2069: #endif
2070:           MatSetValuesLocal(MT,blocks[i],adjncy+xadj[r],blocks[i],adjncy+xadj[r],sarray+xadj[r],ADD_VALUES);
2071:           r   += blocks[i];
2072:         }
2073:       } else {
2074:         for (i=0;i<nvtxs;i++) {
2075:           MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES);
2076:         }
2077:       }
2078:     } else {
2079:       for (i=0;i<nvtxs;i++) {
2080:         MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES);
2081:       }
2082:     }
2083:     MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);
2084:     if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
2085:     MatSeqAIJRestoreArray(local_mat,&sarray);
2086:   } else { /* very basic values insertion for all other matrix types */
2087:     PetscInt i;

2089:     for (i=0;i<local_rows;i++) {
2090:       PetscInt       j;
2091:       const PetscInt *local_indices_cols;

2093:       MatGetRow(local_mat,i,&j,&local_indices_cols,&array);
2094:       MatSetValuesLocal(MT,1,&i,j,local_indices_cols,array,ADD_VALUES);
2095:       MatRestoreRow(local_mat,i,&j,&local_indices_cols,&array);
2096:     }
2097:   }
2098:   MatAssemblyBegin(MT,MAT_FINAL_ASSEMBLY);
2099:   MatDestroy(&local_mat);
2100:   MatAssemblyEnd(MT,MAT_FINAL_ASSEMBLY);
2101:   if (isseqdense) {
2102:     MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_TRUE);
2103:   }
2104:   if (reuse == MAT_INPLACE_MATRIX) {
2105:     MatHeaderReplace(mat,&MT);
2106:   } else if (reuse == MAT_INITIAL_MATRIX) {
2107:     *M = MT;
2108:   }
2109:   return(0);
2110: }

2112: /*@
2113:     MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format

2115:   Input Parameter:
2116: +  mat - the matrix (should be of type MATIS)
2117: -  reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX

2119:   Output Parameter:
2120: .  newmat - the matrix in AIJ format

2122:   Level: developer

2124:   Notes:
2125:     This function has been deprecated and it will be removed in future releases. Update your code to use the MatConvert() interface.

2127: .seealso: MATIS, MatConvert()
2128: @*/
2129: PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
2130: {

2137:   if (reuse == MAT_REUSE_MATRIX) {
2140:     if (mat == *newmat) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix");
2141:   }
2142:   PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatType,MatReuse,Mat*),(mat,MATAIJ,reuse,newmat));
2143:   return(0);
2144: }

2146: PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat)
2147: {
2149:   Mat_IS         *matis = (Mat_IS*)(mat->data);
2150:   PetscInt       rbs,cbs,m,n,M,N;
2151:   Mat            B,localmat;

2154:   ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
2155:   ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
2156:   MatGetSize(mat,&M,&N);
2157:   MatGetLocalSize(mat,&m,&n);
2158:   MatCreate(PetscObjectComm((PetscObject)mat),&B);
2159:   MatSetSizes(B,m,n,M,N);
2160:   MatSetBlockSize(B,rbs == cbs ? rbs : 1);
2161:   MatSetType(B,MATIS);
2162:   MatISSetLocalMatType(B,matis->lmattype);
2163:   MatSetLocalToGlobalMapping(B,mat->rmap->mapping,mat->cmap->mapping);
2164:   MatDuplicate(matis->A,op,&localmat);
2165:   MatISSetLocalMat(B,localmat);
2166:   MatDestroy(&localmat);
2167:   MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
2168:   MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
2169:   *newmat = B;
2170:   return(0);
2171: }

2173: static PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool  *flg)
2174: {
2176:   Mat_IS         *matis = (Mat_IS*)A->data;
2177:   PetscBool      local_sym;

2180:   MatIsHermitian(matis->A,tol,&local_sym);
2181:   MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2182:   return(0);
2183: }

2185: static PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool  *flg)
2186: {
2188:   Mat_IS         *matis = (Mat_IS*)A->data;
2189:   PetscBool      local_sym;

2192:   MatIsSymmetric(matis->A,tol,&local_sym);
2193:   MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2194:   return(0);
2195: }

2197: static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A,PetscBool  *flg)
2198: {
2200:   Mat_IS         *matis = (Mat_IS*)A->data;
2201:   PetscBool      local_sym;

2204:   if (A->rmap->mapping != A->cmap->mapping) {
2205:     *flg = PETSC_FALSE;
2206:     return(0);
2207:   }
2208:   MatIsStructurallySymmetric(matis->A,&local_sym);
2209:   MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2210:   return(0);
2211: }

2213: static PetscErrorCode MatDestroy_IS(Mat A)
2214: {
2216:   Mat_IS         *b = (Mat_IS*)A->data;

2219:   PetscFree(b->bdiag);
2220:   PetscFree(b->lmattype);
2221:   MatDestroy(&b->A);
2222:   VecScatterDestroy(&b->cctx);
2223:   VecScatterDestroy(&b->rctx);
2224:   VecDestroy(&b->x);
2225:   VecDestroy(&b->y);
2226:   VecDestroy(&b->counter);
2227:   ISDestroy(&b->getsub_ris);
2228:   ISDestroy(&b->getsub_cis);
2229:   if (b->sf != b->csf) {
2230:     PetscSFDestroy(&b->csf);
2231:     PetscFree2(b->csf_rootdata,b->csf_leafdata);
2232:   } else b->csf = NULL;
2233:   PetscSFDestroy(&b->sf);
2234:   PetscFree2(b->sf_rootdata,b->sf_leafdata);
2235:   PetscFree(A->data);
2236:   PetscObjectChangeTypeName((PetscObject)A,0);
2237:   PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",NULL);
2238:   PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);
2239:   PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);
2240:   PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);
2241:   PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);
2242:   PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",NULL);
2243:   PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",NULL);
2244:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",NULL);
2245:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",NULL);
2246:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",NULL);
2247:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",NULL);
2248:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",NULL);
2249:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",NULL);
2250:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",NULL);
2251:   return(0);
2252: }

2254: static PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
2255: {
2257:   Mat_IS         *is  = (Mat_IS*)A->data;
2258:   PetscScalar    zero = 0.0;

2261:   /*  scatter the global vector x into the local work vector */
2262:   VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);
2263:   VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);

2265:   /* multiply the local matrix */
2266:   MatMult(is->A,is->x,is->y);

2268:   /* scatter product back into global memory */
2269:   VecSet(y,zero);
2270:   VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);
2271:   VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);
2272:   return(0);
2273: }

2275: static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2276: {
2277:   Vec            temp_vec;

2281:   if (v3 != v2) {
2282:     MatMult(A,v1,v3);
2283:     VecAXPY(v3,1.0,v2);
2284:   } else {
2285:     VecDuplicate(v2,&temp_vec);
2286:     MatMult(A,v1,temp_vec);
2287:     VecAXPY(temp_vec,1.0,v2);
2288:     VecCopy(temp_vec,v3);
2289:     VecDestroy(&temp_vec);
2290:   }
2291:   return(0);
2292: }

2294: static PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x)
2295: {
2296:   Mat_IS         *is = (Mat_IS*)A->data;

2300:   /*  scatter the global vector x into the local work vector */
2301:   VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);
2302:   VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);

2304:   /* multiply the local matrix */
2305:   MatMultTranspose(is->A,is->y,is->x);

2307:   /* scatter product back into global vector */
2308:   VecSet(x,0);
2309:   VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);
2310:   VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);
2311:   return(0);
2312: }

2314: static PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2315: {
2316:   Vec            temp_vec;

2320:   if (v3 != v2) {
2321:     MatMultTranspose(A,v1,v3);
2322:     VecAXPY(v3,1.0,v2);
2323:   } else {
2324:     VecDuplicate(v2,&temp_vec);
2325:     MatMultTranspose(A,v1,temp_vec);
2326:     VecAXPY(temp_vec,1.0,v2);
2327:     VecCopy(temp_vec,v3);
2328:     VecDestroy(&temp_vec);
2329:   }
2330:   return(0);
2331: }

2333: static PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
2334: {
2335:   Mat_IS         *a = (Mat_IS*)A->data;
2337:   PetscViewer    sviewer;
2338:   PetscBool      isascii,view = PETSC_TRUE;

2341:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
2342:   if (isascii)  {
2343:     PetscViewerFormat format;

2345:     PetscViewerGetFormat(viewer,&format);
2346:     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2347:   }
2348:   if (!view) return(0);
2349:   PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
2350:   MatView(a->A,sviewer);
2351:   PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
2352:   PetscViewerFlush(viewer);
2353:   return(0);
2354: }

2356: static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat,const PetscScalar **values)
2357: {
2358:   Mat_IS            *is = (Mat_IS*)mat->data;
2359:   MPI_Datatype      nodeType;
2360:   const PetscScalar *lv;
2361:   PetscInt          bs;
2362:   PetscErrorCode    ierr;

2365:   MatGetBlockSize(mat,&bs);
2366:   MatSetBlockSize(is->A,bs);
2367:   MatInvertBlockDiagonal(is->A,&lv);
2368:   if (!is->bdiag) {
2369:     PetscMalloc1(bs*mat->rmap->n,&is->bdiag);
2370:   }
2371:   MPI_Type_contiguous(bs,MPIU_SCALAR,&nodeType);
2372:   MPI_Type_commit(&nodeType);
2373:   PetscSFReduceBegin(is->sf,nodeType,lv,is->bdiag,MPIU_REPLACE);
2374:   PetscSFReduceEnd(is->sf,nodeType,lv,is->bdiag,MPIU_REPLACE);
2375:   MPI_Type_free(&nodeType);
2376:   if (values) *values = is->bdiag;
2377:   return(0);
2378: }

2380: static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2381: {
2382:   Vec            cglobal,rglobal;
2383:   IS             from;
2384:   Mat_IS         *is = (Mat_IS*)A->data;
2385:   PetscScalar    sum;
2386:   const PetscInt *garray;
2387:   PetscInt       nr,rbs,nc,cbs;
2388:   PetscBool      iscuda;

2392:   ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nr);
2393:   ISLocalToGlobalMappingGetBlockSize(A->rmap->mapping,&rbs);
2394:   ISLocalToGlobalMappingGetSize(A->cmap->mapping,&nc);
2395:   ISLocalToGlobalMappingGetBlockSize(A->cmap->mapping,&cbs);
2396:   VecDestroy(&is->x);
2397:   VecDestroy(&is->y);
2398:   VecDestroy(&is->counter);
2399:   VecScatterDestroy(&is->rctx);
2400:   VecScatterDestroy(&is->cctx);
2401:   MatCreateVecs(is->A,&is->x,&is->y);
2402:   VecBindToCPU(is->y,PETSC_TRUE);
2403:   PetscObjectTypeCompare((PetscObject)is->y,VECSEQCUDA,&iscuda);
2404:   if (iscuda) {
2405:     PetscFree(A->defaultvectype);
2406:     PetscStrallocpy(VECCUDA,&A->defaultvectype);
2407:   }
2408:   MatCreateVecs(A,&cglobal,&rglobal);
2409:   VecBindToCPU(rglobal,PETSC_TRUE);
2410:   ISLocalToGlobalMappingGetBlockIndices(A->rmap->mapping,&garray);
2411:   ISCreateBlock(PetscObjectComm((PetscObject)A),rbs,nr/rbs,garray,PETSC_USE_POINTER,&from);
2412:   VecScatterCreate(rglobal,from,is->y,NULL,&is->rctx);
2413:   ISLocalToGlobalMappingRestoreBlockIndices(A->rmap->mapping,&garray);
2414:   ISDestroy(&from);
2415:   if (A->rmap->mapping != A->cmap->mapping) {
2416:     ISLocalToGlobalMappingGetBlockIndices(A->cmap->mapping,&garray);
2417:     ISCreateBlock(PetscObjectComm((PetscObject)A),cbs,nc/cbs,garray,PETSC_USE_POINTER,&from);
2418:     VecScatterCreate(cglobal,from,is->x,NULL,&is->cctx);
2419:     ISLocalToGlobalMappingRestoreBlockIndices(A->cmap->mapping,&garray);
2420:     ISDestroy(&from);
2421:   } else {
2422:     PetscObjectReference((PetscObject)is->rctx);
2423:     is->cctx = is->rctx;
2424:   }
2425:   VecDestroy(&cglobal);

2427:   /* interface counter vector (local) */
2428:   VecDuplicate(is->y,&is->counter);
2429:   VecBindToCPU(is->counter,PETSC_TRUE);
2430:   VecSet(is->y,1.);
2431:   VecScatterBegin(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);
2432:   VecScatterEnd(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);
2433:   VecScatterBegin(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);
2434:   VecScatterEnd(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);
2435:   VecBindToCPU(is->y,PETSC_FALSE);
2436:   VecBindToCPU(is->counter,PETSC_FALSE);

2438:   /* special functions for block-diagonal matrices */
2439:   VecSum(rglobal,&sum);
2440:   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && A->rmap->mapping == A->cmap->mapping) {
2441:     A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
2442:   } else {
2443:     A->ops->invertblockdiagonal = NULL;
2444:   }
2445:   VecDestroy(&rglobal);

2447:   /* setup SF for general purpose shared indices based communications */
2448:   MatISSetUpSF_IS(A);
2449:   return(0);
2450: }

2452: static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
2453: {
2455:   PetscInt       nr,rbs,nc,cbs;
2456:   Mat_IS         *is = (Mat_IS*)A->data;

2461:   MatDestroy(&is->A);
2462:   if (is->csf != is->sf) {
2463:     PetscSFDestroy(&is->csf);
2464:     PetscFree2(is->csf_rootdata,is->csf_leafdata);
2465:   } else is->csf = NULL;
2466:   PetscSFDestroy(&is->sf);
2467:   PetscFree2(is->sf_rootdata,is->sf_leafdata);
2468:   PetscFree(is->bdiag);

2470:   /* Setup Layout and set local to global maps */
2471:   PetscLayoutSetUp(A->rmap);
2472:   PetscLayoutSetUp(A->cmap);
2473:   ISLocalToGlobalMappingGetSize(rmapping,&nr);
2474:   ISLocalToGlobalMappingGetBlockSize(rmapping,&rbs);
2475:   ISLocalToGlobalMappingGetSize(cmapping,&nc);
2476:   ISLocalToGlobalMappingGetBlockSize(cmapping,&cbs);
2477:   /* check if the two mappings are actually the same for square matrices (DOLFIN passes 2 different objects) */
2478:   if (rmapping != cmapping && A->rmap->N == A->cmap->N) {
2479:     PetscBool same,gsame;

2481:     same = PETSC_FALSE;
2482:     if (nr == nc && cbs == rbs) {
2483:       const PetscInt *idxs1,*idxs2;

2485:       ISLocalToGlobalMappingGetBlockIndices(rmapping,&idxs1);
2486:       ISLocalToGlobalMappingGetBlockIndices(cmapping,&idxs2);
2487:       PetscArraycmp(idxs1,idxs2,nr/rbs,&same);
2488:       ISLocalToGlobalMappingRestoreBlockIndices(rmapping,&idxs1);
2489:       ISLocalToGlobalMappingRestoreBlockIndices(cmapping,&idxs2);
2490:     }
2491:     MPIU_Allreduce(&same,&gsame,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2492:     if (gsame) cmapping = rmapping;
2493:   }
2494:   PetscLayoutSetBlockSize(A->rmap,rbs);
2495:   PetscLayoutSetBlockSize(A->cmap,cbs);
2496:   PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);
2497:   PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);

2499:   /* Create the local matrix A */
2500:   MatCreate(PETSC_COMM_SELF,&is->A);
2501:   MatSetType(is->A,is->lmattype);
2502:   MatSetSizes(is->A,nr,nc,nr,nc);
2503:   MatSetBlockSizes(is->A,rbs,cbs);
2504:   MatSetOptionsPrefix(is->A,"is_");
2505:   MatAppendOptionsPrefix(is->A,((PetscObject)A)->prefix);
2506:   PetscLayoutSetUp(is->A->rmap);
2507:   PetscLayoutSetUp(is->A->cmap);

2509:   if (!is->islocalref) { /* setup scatters and local vectors for MatMult */
2510:     MatISSetUpScatters_Private(A);
2511:   }
2512:   MatSetUp(A);
2513:   return(0);
2514: }

2516: static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2517: {
2518:   Mat_IS         *is = (Mat_IS*)mat->data;
2520: #if defined(PETSC_USE_DEBUG)
2521:   PetscInt       i,zm,zn;
2522: #endif
2523:   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];

2526: #if defined(PETSC_USE_DEBUG)
2527:   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);
2528:   /* count negative indices */
2529:   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2530:   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2531: #endif
2532:   ISGlobalToLocalMappingApply(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);
2533:   ISGlobalToLocalMappingApply(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);
2534: #if defined(PETSC_USE_DEBUG)
2535:   /* count negative indices (should be the same as before) */
2536:   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2537:   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2538:   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");
2539:   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");
2540: #endif
2541:   MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);
2542:   return(0);
2543: }

2545: static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2546: {
2547:   Mat_IS         *is = (Mat_IS*)mat->data;
2549: #if defined(PETSC_USE_DEBUG)
2550:   PetscInt       i,zm,zn;
2551: #endif
2552:   PetscInt       rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];

2555: #if defined(PETSC_USE_DEBUG)
2556:   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);
2557:   /* count negative indices */
2558:   for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2559:   for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2560: #endif
2561:   ISGlobalToLocalMappingApplyBlock(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);
2562:   ISGlobalToLocalMappingApplyBlock(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);
2563: #if defined(PETSC_USE_DEBUG)
2564:   /* count negative indices (should be the same as before) */
2565:   for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2566:   for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2567:   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");
2568:   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");
2569: #endif
2570:   MatSetValuesBlocked(is->A,m,rows_l,n,cols_l,values,addv);
2571:   return(0);
2572: }

2574: static PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2575: {
2577:   Mat_IS         *is = (Mat_IS*)A->data;

2580:   if (is->A->rmap->mapping) {
2581:     MatSetValuesLocal(is->A,m,rows,n,cols,values,addv);
2582:   } else {
2583:     MatSetValues(is->A,m,rows,n,cols,values,addv);
2584:   }
2585:   return(0);
2586: }

2588: static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2589: {
2591:   Mat_IS         *is = (Mat_IS*)A->data;

2594:   if (is->A->rmap->mapping) {
2595: #if defined(PETSC_USE_DEBUG)
2596:     PetscInt ibs,bs;

2598:     ISLocalToGlobalMappingGetBlockSize(is->A->rmap->mapping,&ibs);
2599:     MatGetBlockSize(is->A,&bs);
2600:     if (ibs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Different block sizes! local mat %D, local l2g map %D",bs,ibs);
2601: #endif
2602:     MatSetValuesBlockedLocal(is->A,m,rows,n,cols,values,addv);
2603:   } else {
2604:     MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);
2605:   }
2606:   return(0);
2607: }

2609: static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,PetscBool columns)
2610: {
2611:   Mat_IS         *is = (Mat_IS*)A->data;

2615:   if (!n) {
2616:     is->pure_neumann = PETSC_TRUE;
2617:   } else {
2618:     PetscInt i;
2619:     is->pure_neumann = PETSC_FALSE;

2621:     if (columns) {
2622:       MatZeroRowsColumns(is->A,n,rows,diag,0,0);
2623:     } else {
2624:       MatZeroRows(is->A,n,rows,diag,0,0);
2625:     }
2626:     if (diag != 0.) {
2627:       const PetscScalar *array;
2628:       VecGetArrayRead(is->counter,&array);
2629:       for (i=0; i<n; i++) {
2630:         MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);
2631:       }
2632:       VecRestoreArrayRead(is->counter,&array);
2633:     }
2634:     MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);
2635:     MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY);
2636:   }
2637:   return(0);
2638: }

2640: static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b,PetscBool columns)
2641: {
2642:   Mat_IS         *matis = (Mat_IS*)A->data;
2643:   PetscInt       nr,nl,len,i;
2644:   PetscInt       *lrows;

2648: #if defined(PETSC_USE_DEBUG)
2649:   if (columns || diag != 0. || (x && b)) {
2650:     PetscBool cong;

2652:     PetscLayoutCompare(A->rmap,A->cmap,&cong);
2653:     cong = (PetscBool)(cong && matis->sf == matis->csf);
2654:     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");
2655:     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");
2656:     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");
2657:   }
2658: #endif
2659:   /* get locally owned rows */
2660:   PetscLayoutMapLocal(A->rmap,n,rows,&len,&lrows,NULL);
2661:   /* fix right hand side if needed */
2662:   if (x && b) {
2663:     const PetscScalar *xx;
2664:     PetscScalar       *bb;

2666:     VecGetArrayRead(x, &xx);
2667:     VecGetArray(b, &bb);
2668:     for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]];
2669:     VecRestoreArrayRead(x, &xx);
2670:     VecRestoreArray(b, &bb);
2671:   }
2672:   /* get rows associated to the local matrices */
2673:   MatGetSize(matis->A,&nl,NULL);
2674:   PetscArrayzero(matis->sf_leafdata,nl);
2675:   PetscArrayzero(matis->sf_rootdata,A->rmap->n);
2676:   for (i=0;i<len;i++) matis->sf_rootdata[lrows[i]] = 1;
2677:   PetscFree(lrows);
2678:   PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
2679:   PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
2680:   PetscMalloc1(nl,&lrows);
2681:   for (i=0,nr=0;i<nl;i++) if (matis->sf_leafdata[i]) lrows[nr++] = i;
2682:   MatISZeroRowsColumnsLocal_Private(A,nr,lrows,diag,columns);
2683:   PetscFree(lrows);
2684:   return(0);
2685: }

2687: static PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2688: {

2692:   MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_FALSE);
2693:   return(0);
2694: }

2696: static PetscErrorCode MatZeroRowsColumns_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2697: {

2701:   MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_TRUE);
2702:   return(0);
2703: }

2705: static PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
2706: {
2707:   Mat_IS         *is = (Mat_IS*)A->data;

2711:   MatAssemblyBegin(is->A,type);
2712:   return(0);
2713: }

2715: static PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
2716: {
2717:   Mat_IS         *is = (Mat_IS*)A->data;

2721:   MatAssemblyEnd(is->A,type);
2722:   /* fix for local empty rows/cols */
2723:   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2724:     Mat                    newlA;
2725:     ISLocalToGlobalMapping rl2g,cl2g;
2726:     IS                     nzr,nzc;
2727:     PetscInt               nr,nc,nnzr,nnzc;
2728:     PetscBool              lnewl2g,newl2g;

2730:     MatGetSize(is->A,&nr,&nc);
2731:     MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_FALSE,PETSC_SMALL,&nzr);
2732:     if (!nzr) {
2733:       ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&nzr);
2734:     }
2735:     MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_TRUE,PETSC_SMALL,&nzc);
2736:     if (!nzc) {
2737:       ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&nzc);
2738:     }
2739:     ISGetSize(nzr,&nnzr);
2740:     ISGetSize(nzc,&nnzc);
2741:     if (nnzr != nr || nnzc != nc) {
2742:       ISLocalToGlobalMapping l2g;
2743:       IS                     is1,is2;

2745:       /* need new global l2g map */
2746:       lnewl2g = PETSC_TRUE;
2747:       MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));

2749:       /* extract valid submatrix */
2750:       MatCreateSubMatrix(is->A,nzr,nzc,MAT_INITIAL_MATRIX,&newlA);

2752:       /* attach local l2g maps for successive calls of MatSetValues on the local matrix */
2753:       ISLocalToGlobalMappingCreateIS(nzr,&l2g);
2754:       ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&is1);
2755:       ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);
2756:       ISLocalToGlobalMappingDestroy(&l2g);
2757:       if (is->A->rmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2758:         const PetscInt *idxs1,*idxs2;
2759:         PetscInt       j,i,nl,*tidxs;

2761:         ISLocalToGlobalMappingGetSize(is->A->rmap->mapping,&nl);
2762:         ISLocalToGlobalMappingGetIndices(is->A->rmap->mapping,&idxs1);
2763:         PetscMalloc1(nl,&tidxs);
2764:         ISGetIndices(is2,&idxs2);
2765:         for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2766:         if (j != nr) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nr);
2767:         ISLocalToGlobalMappingRestoreIndices(is->A->rmap->mapping,&idxs1);
2768:         ISRestoreIndices(is2,&idxs2);
2769:         ISDestroy(&is2);
2770:         ISCreateGeneral(PetscObjectComm((PetscObject)is->A->rmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);
2771:       }
2772:       ISLocalToGlobalMappingCreateIS(is2,&rl2g);
2773:       ISDestroy(&is1);
2774:       ISDestroy(&is2);

2776:       ISLocalToGlobalMappingCreateIS(nzc,&l2g);
2777:       ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&is1);
2778:       ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);
2779:       ISLocalToGlobalMappingDestroy(&l2g);
2780:       if (is->A->cmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2781:         const PetscInt *idxs1,*idxs2;
2782:         PetscInt       j,i,nl,*tidxs;

2784:         ISLocalToGlobalMappingGetSize(is->A->cmap->mapping,&nl);
2785:         ISLocalToGlobalMappingGetIndices(is->A->cmap->mapping,&idxs1);
2786:         PetscMalloc1(nl,&tidxs);
2787:         ISGetIndices(is2,&idxs2);
2788:         for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2789:         if (j != nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nc);
2790:         ISLocalToGlobalMappingRestoreIndices(is->A->cmap->mapping,&idxs1);
2791:         ISRestoreIndices(is2,&idxs2);
2792:         ISDestroy(&is2);
2793:         ISCreateGeneral(PetscObjectComm((PetscObject)is->A->cmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);
2794:       }
2795:       ISLocalToGlobalMappingCreateIS(is2,&cl2g);
2796:       ISDestroy(&is1);
2797:       ISDestroy(&is2);

2799:       MatSetLocalToGlobalMapping(newlA,rl2g,cl2g);

2801:       ISLocalToGlobalMappingDestroy(&rl2g);
2802:       ISLocalToGlobalMappingDestroy(&cl2g);
2803:     } else { /* local matrix fully populated */
2804:       lnewl2g = PETSC_FALSE;
2805:       MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));
2806:       PetscObjectReference((PetscObject)is->A);
2807:       newlA   = is->A;
2808:     }
2809:     /* attach new global l2g map if needed */
2810:     if (newl2g) {
2811:       IS             gnzr,gnzc;
2812:       const PetscInt *grid,*gcid;

2814:       ISLocalToGlobalMappingApplyIS(A->rmap->mapping,nzr,&gnzr);
2815:       ISLocalToGlobalMappingApplyIS(A->cmap->mapping,nzc,&gnzc);
2816:       ISGetIndices(gnzr,&grid);
2817:       ISGetIndices(gnzc,&gcid);
2818:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzr,grid,PETSC_COPY_VALUES,&rl2g);
2819:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzc,gcid,PETSC_COPY_VALUES,&cl2g);
2820:       ISRestoreIndices(gnzr,&grid);
2821:       ISRestoreIndices(gnzc,&gcid);
2822:       ISDestroy(&gnzr);
2823:       ISDestroy(&gnzc);
2824:       MatSetLocalToGlobalMapping(A,rl2g,cl2g);
2825:       ISLocalToGlobalMappingDestroy(&rl2g);
2826:       ISLocalToGlobalMappingDestroy(&cl2g);
2827:     }
2828:     MatISSetLocalMat(A,newlA);
2829:     MatDestroy(&newlA);
2830:     ISDestroy(&nzr);
2831:     ISDestroy(&nzc);
2832:     is->locempty = PETSC_FALSE;
2833:   }
2834:   return(0);
2835: }

2837: static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
2838: {
2839:   Mat_IS *is = (Mat_IS*)mat->data;

2842:   *local = is->A;
2843:   return(0);
2844: }

2846: static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local)
2847: {
2849:   *local = NULL;
2850:   return(0);
2851: }

2853: /*@
2854:     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.

2856:   Input Parameter:
2857: .  mat - the matrix

2859:   Output Parameter:
2860: .  local - the local matrix

2862:   Level: advanced

2864:   Notes:
2865:     This can be called if you have precomputed the nonzero structure of the
2866:   matrix and want to provide it to the inner matrix object to improve the performance
2867:   of the MatSetValues() operation.

2869:   Call MatISRestoreLocalMat() when finished with the local matrix.

2871: .seealso: MATIS
2872: @*/
2873: PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
2874: {

2880:   PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));
2881:   return(0);
2882: }

2884: /*@
2885:     MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()

2887:   Input Parameter:
2888: .  mat - the matrix

2890:   Output Parameter:
2891: .  local - the local matrix

2893:   Level: advanced

2895: .seealso: MATIS
2896: @*/
2897: PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local)
2898: {

2904:   PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local));
2905:   return(0);
2906: }

2908: static PetscErrorCode MatISSetLocalMatType_IS(Mat mat,MatType mtype)
2909: {
2910:   Mat_IS         *is = (Mat_IS*)mat->data;

2914:   if (is->A) {
2915:     MatSetType(is->A,mtype);
2916:   }
2917:   PetscFree(is->lmattype);
2918:   PetscStrallocpy(mtype,&is->lmattype);
2919:   return(0);
2920: }

2922: /*@
2923:     MatISSetLocalMatType - Specifies the type of local matrix

2925:   Input Parameter:
2926: +  mat - the matrix
2927: -  mtype - the local matrix type

2929:   Output Parameter:

2931:   Level: advanced

2933: .seealso: MATIS, MatSetType(), MatType
2934: @*/
2935: PetscErrorCode MatISSetLocalMatType(Mat mat,MatType mtype)
2936: {

2941:   PetscUseMethod(mat,"MatISSetLocalMatType_C",(Mat,MatType),(mat,mtype));
2942:   return(0);
2943: }

2945: static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
2946: {
2947:   Mat_IS         *is = (Mat_IS*)mat->data;
2948:   PetscInt       nrows,ncols,orows,ocols;
2950:   MatType        mtype,otype;
2951:   PetscBool      sametype = PETSC_TRUE;

2954:   if (is->A) {
2955:     MatGetSize(is->A,&orows,&ocols);
2956:     MatGetSize(local,&nrows,&ncols);
2957:     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);
2958:     MatGetType(local,&mtype);
2959:     MatGetType(is->A,&otype);
2960:     PetscStrcmp(mtype,otype,&sametype);
2961:   }
2962:   PetscObjectReference((PetscObject)local);
2963:   MatDestroy(&is->A);
2964:   is->A = local;
2965:   MatGetType(is->A,&mtype);
2966:   MatISSetLocalMatType(mat,mtype);
2967:   if (!sametype && !is->islocalref) {
2968:     MatISSetUpScatters_Private(mat);
2969:   }
2970:   return(0);
2971: }

2973: /*@
2974:     MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.

2976:   Collective on Mat

2978:   Input Parameter:
2979: +  mat - the matrix
2980: -  local - the local matrix

2982:   Output Parameter:

2984:   Level: advanced

2986:   Notes:
2987:     This can be called if you have precomputed the local matrix and
2988:   want to provide it to the matrix object MATIS.

2990: .seealso: MATIS
2991: @*/
2992: PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
2993: {

2999:   PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));
3000:   return(0);
3001: }

3003: static PetscErrorCode MatZeroEntries_IS(Mat A)
3004: {
3005:   Mat_IS         *a = (Mat_IS*)A->data;

3009:   MatZeroEntries(a->A);
3010:   return(0);
3011: }

3013: static PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
3014: {
3015:   Mat_IS         *is = (Mat_IS*)A->data;

3019:   MatScale(is->A,a);
3020:   return(0);
3021: }

3023: static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3024: {
3025:   Mat_IS         *is = (Mat_IS*)A->data;

3029:   /* get diagonal of the local matrix */
3030:   MatGetDiagonal(is->A,is->y);

3032:   /* scatter diagonal back into global vector */
3033:   VecSet(v,0);
3034:   VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);
3035:   VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);
3036:   return(0);
3037: }

3039: static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
3040: {
3041:   Mat_IS         *a = (Mat_IS*)A->data;

3045:   MatSetOption(a->A,op,flg);
3046:   return(0);
3047: }

3049: static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str)
3050: {
3051:   Mat_IS         *y = (Mat_IS*)Y->data;
3052:   Mat_IS         *x;
3053: #if defined(PETSC_USE_DEBUG)
3054:   PetscBool      ismatis;
3055: #endif

3059: #if defined(PETSC_USE_DEBUG)
3060:   PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis);
3061:   if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
3062: #endif
3063:   x = (Mat_IS*)X->data;
3064:   MatAXPY(y->A,a,x->A,str);
3065:   return(0);
3066: }

3068: static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat)
3069: {
3070:   Mat                    lA;
3071:   Mat_IS                 *matis;
3072:   ISLocalToGlobalMapping rl2g,cl2g;
3073:   IS                     is;
3074:   const PetscInt         *rg,*rl;
3075:   PetscInt               nrg;
3076:   PetscInt               N,M,nrl,i,*idxs;
3077:   PetscErrorCode         ierr;

3080:   ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg);
3081:   ISGetLocalSize(row,&nrl);
3082:   ISGetIndices(row,&rl);
3083:   ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg);
3084: #if defined(PETSC_USE_DEBUG)
3085:   for (i=0;i<nrl;i++) if (rl[i]>=nrg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row index %D -> %D greater then maximum possible %D",i,rl[i],nrg);
3086: #endif
3087:   PetscMalloc1(nrg,&idxs);
3088:   /* map from [0,nrl) to row */
3089:   for (i=0;i<nrl;i++) idxs[i] = rl[i];
3090:   for (i=nrl;i<nrg;i++) idxs[i] = -1;
3091:   ISRestoreIndices(row,&rl);
3092:   ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg);
3093:   ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is);
3094:   ISLocalToGlobalMappingCreateIS(is,&rl2g);
3095:   ISDestroy(&is);
3096:   /* compute new l2g map for columns */
3097:   if (col != row || A->rmap->mapping != A->cmap->mapping) {
3098:     const PetscInt *cg,*cl;
3099:     PetscInt       ncg;
3100:     PetscInt       ncl;

3102:     ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg);
3103:     ISGetLocalSize(col,&ncl);
3104:     ISGetIndices(col,&cl);
3105:     ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg);
3106: #if defined(PETSC_USE_DEBUG)
3107:     for (i=0;i<ncl;i++) if (cl[i]>=ncg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local column index %D -> %D greater then maximum possible %D",i,cl[i],ncg);
3108: #endif
3109:     PetscMalloc1(ncg,&idxs);
3110:     /* map from [0,ncl) to col */
3111:     for (i=0;i<ncl;i++) idxs[i] = cl[i];
3112:     for (i=ncl;i<ncg;i++) idxs[i] = -1;
3113:     ISRestoreIndices(col,&cl);
3114:     ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg);
3115:     ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is);
3116:     ISLocalToGlobalMappingCreateIS(is,&cl2g);
3117:     ISDestroy(&is);
3118:   } else {
3119:     PetscObjectReference((PetscObject)rl2g);
3120:     cl2g = rl2g;
3121:   }
3122:   /* create the MATIS submatrix */
3123:   MatGetSize(A,&M,&N);
3124:   MatCreate(PetscObjectComm((PetscObject)A),submat);
3125:   MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N);
3126:   MatSetType(*submat,MATIS);
3127:   matis = (Mat_IS*)((*submat)->data);
3128:   matis->islocalref = PETSC_TRUE;
3129:   MatSetLocalToGlobalMapping(*submat,rl2g,cl2g);
3130:   MatISGetLocalMat(A,&lA);
3131:   MatISSetLocalMat(*submat,lA);
3132:   MatSetUp(*submat);
3133:   MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY);
3134:   MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY);
3135:   ISLocalToGlobalMappingDestroy(&rl2g);
3136:   ISLocalToGlobalMappingDestroy(&cl2g);
3137:   /* remove unsupported ops */
3138:   PetscMemzero((*submat)->ops,sizeof(struct _MatOps));
3139:   (*submat)->ops->destroy               = MatDestroy_IS;
3140:   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3141:   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3142:   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3143:   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3144:   return(0);
3145: }

3147: static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A)
3148: {
3149:   Mat_IS         *a = (Mat_IS*)A->data;
3150:   char           type[256];
3151:   PetscBool      flg;

3155:   PetscOptionsHead(PetscOptionsObject,"MATIS options");
3156:   PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns","MatISFixLocalEmpty",a->locempty,&a->locempty,NULL);
3157:   PetscOptionsBool("-matis_storel2l","Store local-to-local matrices generated from PtAP operations","MatISStoreL2L",a->storel2l,&a->storel2l,NULL);
3158:   PetscOptionsFList("-matis_localmat_type","Matrix type","MatISSetLocalMatType",MatList,a->lmattype,type,256,&flg);
3159:   if (flg) {
3160:     MatISSetLocalMatType(A,type);
3161:   }
3162:   if (a->A) {
3163:     MatSetFromOptions(a->A);
3164:   }
3165:   PetscOptionsTail();
3166:   return(0);
3167: }

3169: /*@
3170:     MatCreateIS - Creates a "process" unassembled matrix, assembled on each
3171:        process but not across processes.

3173:    Input Parameters:
3174: +     comm    - MPI communicator that will share the matrix
3175: .     bs      - block size of the matrix
3176: .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3177: .     rmap    - local to global map for rows
3178: -     cmap    - local to global map for cols

3180:    Output Parameter:
3181: .    A - the resulting matrix

3183:    Level: advanced

3185:    Notes:
3186:     See MATIS for more details.
3187:           m and n are NOT related to the size of the map; they represent the size of the local parts of the vectors
3188:           used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
3189:           If either rmap or cmap are NULL, then the matrix is assumed to be square.

3191: .seealso: MATIS, MatSetLocalToGlobalMapping()
3192: @*/
3193: PetscErrorCode  MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A)
3194: {

3198:   if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mappings");
3199:   MatCreate(comm,A);
3200:   MatSetSizes(*A,m,n,M,N);
3201:   if (bs > 0) {
3202:     MatSetBlockSize(*A,bs);
3203:   }
3204:   MatSetType(*A,MATIS);
3205:   if (rmap && cmap) {
3206:     MatSetLocalToGlobalMapping(*A,rmap,cmap);
3207:   } else if (!rmap) {
3208:     MatSetLocalToGlobalMapping(*A,cmap,cmap);
3209:   } else {
3210:     MatSetLocalToGlobalMapping(*A,rmap,rmap);
3211:   }
3212:   return(0);
3213: }

3215: /*MC
3216:    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
3217:    This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3218:    product is handled "implicitly".

3220:    Options Database Keys:
3221: + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
3222: . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
3223: - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().

3225:    Notes:
3226:     Options prefix for the inner matrix are given by -is_mat_xxx

3228:           You must call MatSetLocalToGlobalMapping() before using this matrix type.

3230:           You can do matrix preallocation on the local matrix after you obtain it with
3231:           MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()

3233:   Level: advanced

3235: .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), MatCreateIS(), PCBDDC, KSPFETIDP

3237: M*/

3239: PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3240: {
3242:   Mat_IS         *b;

3245:   PetscNewLog(A,&b);
3246:   PetscStrallocpy(MATAIJ,&b->lmattype);
3247:   A->data = (void*)b;

3249:   /* matrix ops */
3250:   PetscMemzero(A->ops,sizeof(struct _MatOps));
3251:   A->ops->mult                    = MatMult_IS;
3252:   A->ops->multadd                 = MatMultAdd_IS;
3253:   A->ops->multtranspose           = MatMultTranspose_IS;
3254:   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3255:   A->ops->destroy                 = MatDestroy_IS;
3256:   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3257:   A->ops->setvalues               = MatSetValues_IS;
3258:   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3259:   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3260:   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
3261:   A->ops->zerorows                = MatZeroRows_IS;
3262:   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3263:   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3264:   A->ops->assemblyend             = MatAssemblyEnd_IS;
3265:   A->ops->view                    = MatView_IS;
3266:   A->ops->zeroentries             = MatZeroEntries_IS;
3267:   A->ops->scale                   = MatScale_IS;
3268:   A->ops->getdiagonal             = MatGetDiagonal_IS;
3269:   A->ops->setoption               = MatSetOption_IS;
3270:   A->ops->ishermitian             = MatIsHermitian_IS;
3271:   A->ops->issymmetric             = MatIsSymmetric_IS;
3272:   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3273:   A->ops->duplicate               = MatDuplicate_IS;
3274:   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
3275:   A->ops->copy                    = MatCopy_IS;
3276:   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
3277:   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3278:   A->ops->axpy                    = MatAXPY_IS;
3279:   A->ops->diagonalset             = MatDiagonalSet_IS;
3280:   A->ops->shift                   = MatShift_IS;
3281:   A->ops->transpose               = MatTranspose_IS;
3282:   A->ops->getinfo                 = MatGetInfo_IS;
3283:   A->ops->diagonalscale           = MatDiagonalScale_IS;
3284:   A->ops->setfromoptions          = MatSetFromOptions_IS;

3286:   /* special MATIS functions */
3287:   PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",MatISSetLocalMatType_IS);
3288:   PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);
3289:   PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS);
3290:   PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);
3291:   PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatConvert_IS_XAIJ);
3292:   PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);
3293:   PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",MatISStoreL2L_IS);
3294:   PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",MatISFixLocalEmpty_IS);
3295:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",MatConvert_IS_XAIJ);
3296:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",MatConvert_IS_XAIJ);
3297:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",MatConvert_IS_XAIJ);
3298:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",MatConvert_IS_XAIJ);
3299:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",MatConvert_IS_XAIJ);
3300:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",MatConvert_IS_XAIJ);
3301:   PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",MatConvert_IS_XAIJ);
3302:   PetscObjectChangeTypeName((PetscObject)A,MATIS);
3303:   return(0);
3304: }