Actual source code: matnest.c

 2:  #include matnestimpl.h

  4: static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
  5: static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left);

  7: /* private functions */
 10: static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
 11: {
 12:   Mat_Nest       *bA = (Mat_Nest*)A->data;
 13:   PetscInt       i,j;

 17:   *m = *n = *M = *N = 0;
 18:   for (i=0; i<bA->nr; i++) {  /* rows */
 19:     PetscInt sm,sM;
 20:     ISGetLocalSize(bA->isglobal.row[i],&sm);
 21:     ISGetSize(bA->isglobal.row[i],&sM);
 22:     *m += sm;
 23:     *M += sM;
 24:   }
 25:   for (j=0; j<bA->nc; j++) {  /* cols */
 26:     PetscInt sn,sN;
 27:     ISGetLocalSize(bA->isglobal.col[j],&sn);
 28:     ISGetSize(bA->isglobal.col[j],&sN);
 29:     *n += sn;
 30:     *N += sN;
 31:   }
 32:   return(0);
 33: }

 35: /* operations */
 38: static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
 39: {
 40:   Mat_Nest       *bA = (Mat_Nest*)A->data;
 41:   Vec            *bx = bA->right,*by = bA->left;
 42:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

 46:   for (i=0; i<nr; i++) {VecGetSubVector(y,bA->isglobal.row[i],&by[i]);}
 47:   for (i=0; i<nc; i++) {VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);}
 48:   for (i=0; i<nr; i++) {
 49:     VecZeroEntries(by[i]);
 50:     for (j=0; j<nc; j++) {
 51:       if (!bA->m[i][j]) continue;
 52:       /* y[i] <- y[i] + A[i][j] * x[j] */
 53:       MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);
 54:     }
 55:   }
 56:   for (i=0; i<nr; i++) {VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);}
 57:   for (i=0; i<nc; i++) {VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);}
 58:   return(0);
 59: }

 63: static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
 64: {
 65:   Mat_Nest       *bA = (Mat_Nest*)A->data;
 66:   Vec            *bx = bA->right,*bz = bA->left;
 67:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

 71:   for (i=0; i<nr; i++) {VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);}
 72:   for (i=0; i<nc; i++) {VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);}
 73:   for (i=0; i<nr; i++) {
 74:     if (y != z) {
 75:       Vec by;
 76:       VecGetSubVector(y,bA->isglobal.row[i],&by);
 77:       VecCopy(by,bz[i]);
 78:       VecRestoreSubVector(y,bA->isglobal.row[i],&by);
 79:     }
 80:     for (j=0; j<nc; j++) {
 81:       if (!bA->m[i][j]) continue;
 82:       /* y[i] <- y[i] + A[i][j] * x[j] */
 83:       MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);
 84:     }
 85:   }
 86:   for (i=0; i<nr; i++) {VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);}
 87:   for (i=0; i<nc; i++) {VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);}
 88:   return(0);
 89: }

 93: static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
 94: {
 95:   Mat_Nest       *bA = (Mat_Nest*)A->data;
 96:   Vec            *bx = bA->left,*by = bA->right;
 97:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

101:   for (i=0; i<nr; i++) {VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);}
102:   for (i=0; i<nc; i++) {VecGetSubVector(y,bA->isglobal.col[i],&by[i]);}
103:   for (j=0; j<nc; j++) {
104:     VecZeroEntries(by[j]);
105:     for (i=0; i<nr; i++) {
106:       if (!bA->m[j][i]) continue;
107:       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
108:       MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);
109:     }
110:   }
111:   for (i=0; i<nr; i++) {VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);}
112:   for (i=0; i<nc; i++) {VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);}
113:   return(0);
114: }

118: static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
119: {
120:   Mat_Nest       *bA = (Mat_Nest*)A->data;
121:   Vec            *bx = bA->left,*bz = bA->right;
122:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

126:   for (i=0; i<nr; i++) {VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);}
127:   for (i=0; i<nc; i++) {VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);}
128:   for (j=0; j<nc; j++) {
129:     if (y != z) {
130:       Vec by;
131:       VecGetSubVector(y,bA->isglobal.col[j],&by);
132:       VecCopy(by,bz[j]);
133:       VecRestoreSubVector(y,bA->isglobal.col[j],&by);
134:     }
135:     for (i=0; i<nr; i++) {
136:       if (!bA->m[j][i]) continue;
137:       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
138:       MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);
139:     }
140:   }
141:   for (i=0; i<nr; i++) {VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);}
142:   for (i=0; i<nc; i++) {VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);}
143:   return(0);
144: }

148: static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
149: {
151:   IS             *lst = *list;
152:   PetscInt       i;

155:   if (!lst) return(0);
156:   for (i=0; i<n; i++) if (lst[i]) {ISDestroy(&lst[i]);}
157:   PetscFree(lst);
158:   *list = PETSC_NULL;
159:   return(0);
160: }

164: static PetscErrorCode MatDestroy_Nest(Mat A)
165: {
166:   Mat_Nest       *vs = (Mat_Nest*)A->data;
167:   PetscInt       i,j;

171:   /* release the matrices and the place holders */
172:   MatNestDestroyISList(vs->nr,&vs->isglobal.row);
173:   MatNestDestroyISList(vs->nc,&vs->isglobal.col);
174:   MatNestDestroyISList(vs->nr,&vs->islocal.row);
175:   MatNestDestroyISList(vs->nc,&vs->islocal.col);

177:   PetscFree(vs->row_len);
178:   PetscFree(vs->col_len);

180:   PetscFree2(vs->left,vs->right);

182:   /* release the matrices and the place holders */
183:   if (vs->m) {
184:     for (i=0; i<vs->nr; i++) {
185:       for (j=0; j<vs->nc; j++) {
186:         MatDestroy(&vs->m[i][j]);
187:       }
188:       PetscFree( vs->m[i] );
189:     }
190:     PetscFree(vs->m);
191:   }
192:   PetscFree(A->data);

194:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "",0);
195:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C",   "",0);
196:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "",0);
197:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "",0);
198:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "",0);
199:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",   "",0);
200:   return(0);
201: }

205: static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
206: {
207:   Mat_Nest       *vs = (Mat_Nest*)A->data;
208:   PetscInt       i,j;

212:   for (i=0; i<vs->nr; i++) {
213:     for (j=0; j<vs->nc; j++) {
214:       if (vs->m[i][j]) { MatAssemblyBegin(vs->m[i][j],type); }
215:     }
216:   }
217:   return(0);
218: }

222: static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
223: {
224:   Mat_Nest       *vs = (Mat_Nest*)A->data;
225:   PetscInt       i,j;

229:   for (i=0; i<vs->nr; i++) {
230:     for (j=0; j<vs->nc; j++) {
231:       if (vs->m[i][j]) { MatAssemblyEnd(vs->m[i][j],type); }
232:     }
233:   }
234:   return(0);
235: }

239: static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
240: {
242:   Mat_Nest       *vs = (Mat_Nest*)A->data;
243:   PetscInt       j;
244:   Mat            sub;

247:   sub = (row < vs->nc) ? vs->m[row][row] : PETSC_NULL; /* Prefer to find on the diagonal */
248:   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
249:   if (sub) {MatPreallocated(sub);} /* Ensure that the sizes are available */
250:   *B = sub;
251:   return(0);
252: }

256: static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
257: {
259:   Mat_Nest       *vs = (Mat_Nest*)A->data;
260:   PetscInt       i;
261:   Mat            sub;

264:   sub = (col < vs->nr) ? vs->m[col][col] : PETSC_NULL; /* Prefer to find on the diagonal */
265:   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
266:   if (sub) {MatPreallocated(sub);} /* Ensure that the sizes are available */
267:   *B = sub;
268:   return(0);
269: }

273: static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
274: {
276:   PetscInt       i;
277:   PetscBool      flg;

283:   *found = -1;
284:   for (i=0; i<n; i++) {
285:     if (!list[i]) continue;
286:     ISEqual(list[i],is,&flg);
287:     if (flg) {
288:       *found = i;
289:       return(0);
290:     }
291:   }
292:   SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Could not find index set");
293:   return(0);
294: }

298: /* Get a block row as a new MatNest */
299: static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
300: {
301:   Mat_Nest       *vs = (Mat_Nest*)A->data;
302:   char           keyname[256];

306:   *B = PETSC_NULL;
307:   PetscSNPrintf(keyname,sizeof keyname,"NestRow_%D",row);
308:   PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);
309:   if (*B) return(0);

311:   MatCreateNest(((PetscObject)A)->comm,1,PETSC_NULL,vs->nc,vs->isglobal.col,vs->m[row],B);
312:   (*B)->assembled = A->assembled;
313:   PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);
314:   PetscObjectDereference((PetscObject)*B); /* Leave the only remaining reference in the composition */
315:   return(0);
316: }

320: static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
321: {
322:   Mat_Nest       *vs = (Mat_Nest*)A->data;
324:   PetscInt       row,col;
325:   PetscBool      same,isFullCol;

328:   /* Check if full column space. This is a hack */
329:   isFullCol = PETSC_FALSE;
330:   PetscTypeCompare((PetscObject)iscol,ISSTRIDE,&same);
331:   if (same) {
332:     PetscInt n,first,step,i,an,am,afirst,astep;
333:     ISStrideGetInfo(iscol,&first,&step);
334:     ISGetLocalSize(iscol,&n);
335:     isFullCol = PETSC_TRUE;
336:     for (i=0,an=0; i<vs->nc; i++) {
337:       ISStrideGetInfo(is->col[i],&afirst,&astep);
338:       ISGetLocalSize(is->col[i],&am);
339:       if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
340:       an += am;
341:     }
342:     if (an != n) isFullCol = PETSC_FALSE;
343:   }

345:   if (isFullCol) {
346:     PetscInt row;
347:     MatNestFindIS(A,vs->nr,is->row,isrow,&row);
348:     MatNestGetRow(A,row,B);
349:   } else {
350:     MatNestFindIS(A,vs->nr,is->row,isrow,&row);
351:     MatNestFindIS(A,vs->nc,is->col,iscol,&col);
352:     *B = vs->m[row][col];
353:   }
354:   return(0);
355: }

359: static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
360: {
362:   Mat_Nest       *vs = (Mat_Nest*)A->data;
363:   Mat            sub;

366:   MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);
367:   switch (reuse) {
368:   case MAT_INITIAL_MATRIX:
369:     if (sub) { PetscObjectReference((PetscObject)sub); }
370:     *B = sub;
371:     break;
372:   case MAT_REUSE_MATRIX:
373:     if (sub != *B) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
374:     break;
375:   case MAT_IGNORE_MATRIX:       /* Nothing to do */
376:     break;
377:   }
378:   return(0);
379: }

383: PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
384: {
386:   Mat_Nest       *vs = (Mat_Nest*)A->data;
387:   Mat            sub;

390:   MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);
391:   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
392:   if (sub) {PetscObjectReference((PetscObject)sub);}
393:   *B = sub;
394:   return(0);
395: }

399: static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
400: {
402:   Mat_Nest       *vs = (Mat_Nest*)A->data;
403:   Mat            sub;

406:   MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);
407:   if (*B != sub) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
408:   if (sub) {
409:     if (((PetscObject)sub)->refct <= 1) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
410:     MatDestroy(B);
411:   }
412:   return(0);
413: }

417: static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
418: {
419:   Mat_Nest       *bA = (Mat_Nest*)A->data;
420:   PetscInt       i;

424:   for (i=0; i<bA->nr; i++) {
425:     Vec bv;
426:     VecGetSubVector(v,bA->isglobal.row[i],&bv);
427:     if (bA->m[i][i]) {
428:       MatGetDiagonal(bA->m[i][i],bv);
429:     } else {
430:       VecSet(bv,1.0);
431:     }
432:     VecRestoreSubVector(v,bA->isglobal.row[i],&bv);
433:   }
434:   return(0);
435: }

439: static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
440: {
441:   Mat_Nest       *bA = (Mat_Nest*)A->data;
442:   Vec            bl,*br;
443:   PetscInt       i,j;

447:   PetscMalloc(bA->nc*sizeof(Vec),&br);
448:   for (j=0; j<bA->nc; j++) {VecGetSubVector(r,bA->isglobal.col[j],&br[j]);}
449:   for (i=0; i<bA->nr; i++) {
450:     VecGetSubVector(l,bA->isglobal.row[i],&bl);
451:     for (j=0; j<bA->nc; j++) {
452:       if (bA->m[i][j]) {
453:         MatDiagonalScale(bA->m[i][j],bl,br[j]);
454:       }
455:     }
456:     VecRestoreSubVector(l,bA->isglobal.row[i],&bl);
457:   }
458:   for (j=0; j<bA->nc; j++) {VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);}
459:   PetscFree(br);
460:   return(0);
461: }

465: static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
466: {
467:   Mat_Nest       *bA = (Mat_Nest*)A->data;
468:   PetscInt       i,j;

472:   for (i=0; i<bA->nr; i++) {
473:     for (j=0; j<bA->nc; j++) {
474:       if (bA->m[i][j]) {
475:         MatScale(bA->m[i][j],a);
476:       }
477:     }
478:   }
479:   return(0);
480: }

484: static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
485: {
486:   Mat_Nest       *bA = (Mat_Nest*)A->data;
487:   PetscInt       i;

491:   for (i=0; i<bA->nr; i++) {
492:     if (!bA->m[i][i]) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%D,%D)",i,i);
493:     MatShift(bA->m[i][i],a);
494:   }
495:   return(0);
496: }

500: static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left)
501: {
502:   Mat_Nest       *bA = (Mat_Nest*)A->data;
503:   Vec            *L,*R;
504:   MPI_Comm       comm;
505:   PetscInt       i,j;

509:   comm = ((PetscObject)A)->comm;
510:   if (right) {
511:     /* allocate R */
512:     PetscMalloc( sizeof(Vec) * bA->nc, &R );
513:     /* Create the right vectors */
514:     for (j=0; j<bA->nc; j++) {
515:       for (i=0; i<bA->nr; i++) {
516:         if (bA->m[i][j]) {
517:           MatGetVecs(bA->m[i][j],&R[j],PETSC_NULL);
518:           break;
519:         }
520:       }
521:       if (i==bA->nr) {
522:         /* have an empty column */
523:         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
524:       }
525:     }
526:     VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);
527:     /* hand back control to the nest vector */
528:     for (j=0; j<bA->nc; j++) {
529:       VecDestroy(&R[j]);
530:     }
531:     PetscFree(R);
532:   }

534:   if (left) {
535:     /* allocate L */
536:     PetscMalloc( sizeof(Vec) * bA->nr, &L );
537:     /* Create the left vectors */
538:     for (i=0; i<bA->nr; i++) {
539:       for (j=0; j<bA->nc; j++) {
540:         if (bA->m[i][j]) {
541:           MatGetVecs(bA->m[i][j],PETSC_NULL,&L[i]);
542:           break;
543:         }
544:       }
545:       if (j==bA->nc) {
546:         /* have an empty row */
547:         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
548:       }
549:     }

551:     VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);
552:     for (i=0; i<bA->nr; i++) {
553:       VecDestroy(&L[i]);
554:     }

556:     PetscFree(L);
557:   }
558:   return(0);
559: }

563: static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
564: {
565:   Mat_Nest       *bA = (Mat_Nest*)A->data;
566:   PetscBool      isascii;
567:   PetscInt       i,j;

571:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
572:   if (isascii) {

574:     PetscViewerASCIIPrintf(viewer,"Matrix object: \n" );
575:     PetscViewerASCIIPushTab( viewer );    /* push0 */
576:     PetscViewerASCIIPrintf( viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc);

578:     PetscViewerASCIIPrintf(viewer,"MatNest structure: \n" );
579:     for (i=0; i<bA->nr; i++) {
580:       for (j=0; j<bA->nc; j++) {
581:         const MatType type;
582:         char name[256] = "",prefix[256] = "";
583:         PetscInt NR,NC;
584:         PetscBool isNest = PETSC_FALSE;

586:         if (!bA->m[i][j]) {
587:           PetscViewerASCIIPrintf( viewer, "(%D,%D) : PETSC_NULL \n",i,j);
588:           continue;
589:         }
590:         MatGetSize(bA->m[i][j],&NR,&NC);
591:         MatGetType( bA->m[i][j], &type );
592:         if (((PetscObject)bA->m[i][j])->name) {PetscSNPrintf(name,sizeof name,"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);}
593:         if (((PetscObject)bA->m[i][j])->prefix) {PetscSNPrintf(prefix,sizeof prefix,"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);}
594:         PetscTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);

596:         PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);

598:         if (isNest) {
599:           PetscViewerASCIIPushTab(viewer);  /* push1 */
600:           MatView(bA->m[i][j],viewer);
601:           PetscViewerASCIIPopTab(viewer);    /* pop1 */
602:         }
603:       }
604:     }
605:     PetscViewerASCIIPopTab(viewer);    /* pop0 */
606:   }
607:   return(0);
608: }

612: static PetscErrorCode MatZeroEntries_Nest(Mat A)
613: {
614:   Mat_Nest       *bA = (Mat_Nest*)A->data;
615:   PetscInt       i,j;

619:   for (i=0; i<bA->nr; i++) {
620:     for (j=0; j<bA->nc; j++) {
621:       if (!bA->m[i][j]) continue;
622:       MatZeroEntries(bA->m[i][j]);
623:     }
624:   }
625:   return(0);
626: }

630: static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
631: {
632:   Mat_Nest       *bA = (Mat_Nest*)A->data;
633:   Mat            *b;
634:   PetscInt       i,j,nr = bA->nr,nc = bA->nc;

638:   PetscMalloc(nr*nc*sizeof(Mat),&b);
639:   for (i=0; i<nr; i++) {
640:     for (j=0; j<nc; j++) {
641:       if (bA->m[i][j]) {
642:         MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);
643:       } else {
644:         b[i*nc+j] = PETSC_NULL;
645:       }
646:     }
647:   }
648:   MatCreateNest(((PetscObject)A)->comm,nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);
649:   /* Give the new MatNest exclusive ownership */
650:   for (i=0; i<nr*nc; i++) {
651:     MatDestroy(&b[i]);
652:   }
653:   PetscFree(b);

655:   MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
656:   MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
657:   return(0);
658: }

660: /* nest api */
664: PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
665: {
666:   Mat_Nest *bA = (Mat_Nest*)A->data;
668:   if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
669:   if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
670:   *mat = bA->m[idxm][jdxm];
671:   return(0);
672: }

677: /*@C
678:  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.

680:  Not collective

682:  Input Parameters:
683: +   A  - nest matrix
684: .   idxm - index of the matrix within the nest matrix
685: -   jdxm - index of the matrix within the nest matrix

687:  Output Parameter:
688: .   sub - matrix at index idxm,jdxm within the nest matrix

690:  Level: developer

692: .seealso: MatNestGetSize(), MatNestGetSubMats()
693: @*/
694: PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
695: {

699:   PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));
700:   return(0);
701: }

706: PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
707: {
708:   Mat_Nest *bA = (Mat_Nest*)A->data;
709:   PetscInt m,n,M,N,mi,ni,Mi,Ni;

713:   if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
714:   if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
715:   MatGetLocalSize(mat,&m,&n);
716:   MatGetSize(mat,&M,&N);
717:   ISGetLocalSize(bA->isglobal.row[idxm],&mi);
718:   ISGetSize(bA->isglobal.row[idxm],&Mi);
719:   ISGetLocalSize(bA->isglobal.col[jdxm],&ni);
720:   ISGetSize(bA->isglobal.col[jdxm],&Ni);
721:   if (M != Mi || N != Ni) SETERRQ4(((PetscObject)mat)->comm,PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%D,%D) incompatible with nest block (%D,%D)",M,N,Mi,Ni);
722:   if (m != mi || n != ni) SETERRQ4(((PetscObject)mat)->comm,PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%D,%D) incompatible with nest block (%D,%D)",m,n,mi,ni);
723:   PetscObjectReference((PetscObject)mat);
724:   MatDestroy(&bA->m[idxm][jdxm]);
725:   bA->m[idxm][jdxm] = mat;
726:   return(0);
727: }

732: /*@C
733:  MatNestSetSubMat - Set a single submatrix in the nest matrix.

735:  Logically collective on the submatrix communicator

737:  Input Parameters:
738: +   A  - nest matrix
739: .   idxm - index of the matrix within the nest matrix
740: .   jdxm - index of the matrix within the nest matrix
741: -   sub - matrix at index idxm,jdxm within the nest matrix

743:  Notes:
744:  The new submatrix must have the same size and communicator as that block of the nest.

746:  This increments the reference count of the submatrix.

748:  Level: developer

750: .seealso: MatNestSetSubMats(), MatNestGetSubMat()
751: @*/
752: PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
753: {

757:   PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));
758:   return(0);
759: }

764: PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
765: {
766:   Mat_Nest *bA = (Mat_Nest*)A->data;
768:   if (M)   { *M   = bA->nr; }
769:   if (N)   { *N   = bA->nc; }
770:   if (mat) { *mat = bA->m;  }
771:   return(0);
772: }

777: /*@C
778:  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.

780:  Not collective

782:  Input Parameters:
783: .   A  - nest matrix

785:  Output Parameter:
786: +   M - number of rows in the nest matrix
787: .   N - number of cols in the nest matrix
788: -   mat - 2d array of matrices

790:  Notes:

792:  The user should not free the array mat.

794:  Level: developer

796: .seealso: MatNestGetSize(), MatNestGetSubMat()
797: @*/
798: PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
799: {

803:   PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));
804:   return(0);
805: }

810: PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
811: {
812:   Mat_Nest  *bA = (Mat_Nest*)A->data;

815:   if (M) { *M  = bA->nr; }
816:   if (N) { *N  = bA->nc; }
817:   return(0);
818: }

823: /*@C
824:  MatNestGetSize - Returns the size of the nest matrix.

826:  Not collective

828:  Input Parameters:
829: .   A  - nest matrix

831:  Output Parameter:
832: +   M - number of rows in the nested mat
833: -   N - number of cols in the nested mat

835:  Notes:

837:  Level: developer

839: .seealso: MatNestGetSubMat(), MatNestGetSubMats()
840: @*/
841: PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
842: {

846:   PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));
847:   return(0);
848: }

853: PetscErrorCode  MatNestSetVecType_Nest(Mat A,const VecType vtype)
854: {
856:   PetscBool      flg;

859:   PetscStrcmp(vtype,VECNEST,&flg);
860:   /* In reality, this only distinguishes VECNEST and "other" */
861:   A->ops->getvecs       = flg ? MatGetVecs_Nest       : 0;
862:  return(0);
863: }

868: /*@C
869:  MatNestSetVecType - Sets the type of Vec returned by MatGetVecs()

871:  Not collective

873:  Input Parameters:
874: +  A  - nest matrix
875: -  vtype - type to use for creating vectors

877:  Notes:

879:  Level: developer

881: .seealso: MatGetVecs()
882: @*/
883: PetscErrorCode  MatNestSetVecType(Mat A,const VecType vtype)
884: {

888:   PetscTryMethod(A,"MatNestSetVecType_C",(Mat,const VecType),(A,vtype));
889:   return(0);
890: }

895: PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
896: {
897:   Mat_Nest       *s = (Mat_Nest*)A->data;
898:   PetscInt       i,j,m,n,M,N;

902:   s->nr = nr;
903:   s->nc = nc;

905:   /* Create space for submatrices */
906:   PetscMalloc(sizeof(Mat*)*nr,&s->m);
907:   for (i=0; i<nr; i++) {
908:     PetscMalloc(sizeof(Mat)*nc,&s->m[i]);
909:   }
910:   for (i=0; i<nr; i++) {
911:     for (j=0; j<nc; j++) {
912:       s->m[i][j] = a[i*nc+j];
913:       if (a[i*nc+j]) {
914:         PetscObjectReference((PetscObject)a[i*nc+j]);
915:       }
916:     }
917:   }

919:   MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);

921:   PetscMalloc(sizeof(PetscInt)*nr,&s->row_len);
922:   PetscMalloc(sizeof(PetscInt)*nc,&s->col_len);
923:   for (i=0; i<nr; i++) s->row_len[i]=-1;
924:   for (j=0; j<nc; j++) s->col_len[j]=-1;

926:   MatNestGetSizes_Private(A,&m,&n,&M,&N);

928:   PetscLayoutSetSize(A->rmap,M);
929:   PetscLayoutSetLocalSize(A->rmap,m);
930:   PetscLayoutSetBlockSize(A->rmap,1);
931:   PetscLayoutSetSize(A->cmap,N);
932:   PetscLayoutSetLocalSize(A->cmap,n);
933:   PetscLayoutSetBlockSize(A->cmap,1);

935:   PetscLayoutSetUp(A->rmap);
936:   PetscLayoutSetUp(A->cmap);

938:   PetscMalloc2(nr,Vec,&s->left,nc,Vec,&s->right);
939:   PetscMemzero(s->left,nr*sizeof(Vec));
940:   PetscMemzero(s->right,nc*sizeof(Vec));
941:   return(0);
942: }

947: /*@
948:    MatNestSetSubMats - Sets the nested submatrices

950:    Collective on Mat

952:    Input Parameter:
953: +  N - nested matrix
954: .  nr - number of nested row blocks
955: .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
956: .  nc - number of nested column blocks
957: .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
958: -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL

960:    Level: advanced

962: .seealso: MatCreateNest(), MATNEST
963: @*/
964: PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
965: {
967:   PetscInt i;

971:   if (nr < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
972:   if (nr && is_row) {
975:   }
976:   if (nc < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
977:   if (nc && is_col) {
980:   }
982:   PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));
983:   return(0);
984: }

988: static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog,ISLocalToGlobalMapping *ltogb)
989: {
991:   PetscBool flg;
992:   PetscInt i,j,m,mi,*ix;

995:   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
996:     if (islocal[i]) {
997:       ISGetSize(islocal[i],&mi);
998:       flg = PETSC_TRUE;       /* We found a non-trivial entry */
999:     } else {
1000:       ISGetSize(isglobal[i],&mi);
1001:     }
1002:     m += mi;
1003:   }
1004:   if (flg) {
1005:     PetscMalloc(m*sizeof(*ix),&ix);
1006:     for (i=0,n=0; i<n; i++) {
1007:       ISLocalToGlobalMapping smap = PETSC_NULL;
1008:       VecScatter scat;
1009:       IS isreq;
1010:       Vec lvec,gvec;
1011:       union {char padding[sizeof(PetscScalar)]; PetscInt integer;} *x;
1012:       Mat sub;

1014:       if (sizeof (*x) != sizeof(PetscScalar)) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support when scalars smaller than integers");
1015:       if (colflg) {
1016:         MatNestFindNonzeroSubMatRow(A,i,&sub);
1017:       } else {
1018:         MatNestFindNonzeroSubMatCol(A,i,&sub);
1019:       }
1020:       if (sub) {MatGetLocalToGlobalMapping(sub,&smap,PETSC_NULL);}
1021:       if (islocal[i]) {
1022:         ISGetSize(islocal[i],&mi);
1023:       } else {
1024:         ISGetSize(isglobal[i],&mi);
1025:       }
1026:       for (j=0; j<mi; j++) ix[m+j] = j;
1027:       if (smap) {ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);}
1028:       /*
1029:         Now we need to extract the monolithic global indices that correspond to the given split global indices.
1030:         In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1031:         The approach here is ugly because it uses VecScatter to move indices.
1032:        */
1033:       VecCreateSeq(PETSC_COMM_SELF,mi,&lvec);
1034:       VecCreateMPI(((PetscObject)isglobal[i])->comm,mi,PETSC_DECIDE,&gvec);
1035:       ISCreateGeneral(((PetscObject)isglobal[i])->comm,mi,ix+m,PETSC_COPY_VALUES,&isreq);
1036:       VecScatterCreate(gvec,isreq,lvec,PETSC_NULL,&scat);
1037:       VecGetArray(gvec,(PetscScalar**)&x);
1038:       for (j=0; j<mi; j++) x[j].integer = ix[m+j];
1039:       VecRestoreArray(gvec,(PetscScalar**)&x);
1040:       VecScatterBegin(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);
1041:       VecScatterEnd(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);
1042:       VecGetArray(lvec,(PetscScalar**)&x);
1043:       for (j=0; j<mi; j++) ix[m+j] = x[j].integer;
1044:       VecRestoreArray(lvec,(PetscScalar**)&x);
1045:       VecDestroy(&lvec);
1046:       VecDestroy(&gvec);
1047:       ISDestroy(&isreq);
1048:       VecScatterDestroy(&scat);
1049:       m += mi;
1050:     }
1051:     ISLocalToGlobalMappingCreate(((PetscObject)A)->comm,m,ix,PETSC_OWN_POINTER,ltog);
1052:     *ltogb = PETSC_NULL;
1053:   } else {
1054:     *ltog = PETSC_NULL;
1055:     *ltogb = PETSC_NULL;
1056:   }
1057:   return(0);
1058: }


1061: /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1062: /*
1063:   nprocessors = NP
1064:   Nest x^T = ( (g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1) )
1065:        proc 0: => (g_0,h_0,)
1066:        proc 1: => (g_1,h_1,)
1067:        ...
1068:        proc nprocs-1: => (g_NP-1,h_NP-1,)

1070:             proc 0:                      proc 1:                    proc nprocs-1:
1071:     is[0] = ( 0,1,2,...,nlocal(g_0)-1 )  ( 0,1,...,nlocal(g_1)-1 )  ( 0,1,...,nlocal(g_NP-1) )

1073:             proc 0:
1074:     is[1] = ( nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1 )
1075:             proc 1:
1076:     is[1] = ( nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1 )

1078:             proc NP-1:
1079:     is[1] = ( nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1 )
1080: */
1083: static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1084: {
1085:   Mat_Nest       *vs = (Mat_Nest*)A->data;
1086:   PetscInt       i,j,offset,n,nsum,bs;
1088:   Mat            sub;

1091:   PetscMalloc(sizeof(IS)*nr,&vs->isglobal.row);
1092:   PetscMalloc(sizeof(IS)*nc,&vs->isglobal.col);
1093:   if (is_row) { /* valid IS is passed in */
1094:     /* refs on is[] are incremeneted */
1095:     for (i=0; i<vs->nr; i++) {
1096:       PetscObjectReference((PetscObject)is_row[i]);
1097:       vs->isglobal.row[i] = is_row[i];
1098:     }
1099:   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
1100:     nsum = 0;
1101:     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
1102:       MatNestFindNonzeroSubMatRow(A,i,&sub);
1103:       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
1104:       MatGetLocalSize(sub,&n,PETSC_NULL);
1105:       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1106:       nsum += n;
1107:     }
1108:     offset = 0;
1109: #if defined(PETSC_HAVE_MPI_EXSCAN)
1110:     MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);
1111: #else 
1112:     SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sorry but this code requires MPI_EXSCAN that doesn't exist on your machine's version of MPI, install a MPI2 with PETSc to get this functionality");
1113: #endif
1114:     for (i=0; i<vs->nr; i++) {
1115:       MatNestFindNonzeroSubMatRow(A,i,&sub);
1116:       MatGetLocalSize(sub,&n,PETSC_NULL);
1117:       MatGetBlockSize(sub,&bs);
1118:       ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.row[i]);
1119:       ISSetBlockSize(vs->isglobal.row[i],bs);
1120:       offset += n;
1121:     }
1122:   }

1124:   if (is_col) { /* valid IS is passed in */
1125:     /* refs on is[] are incremeneted */
1126:     for (j=0; j<vs->nc; j++) {
1127:       PetscObjectReference((PetscObject)is_col[j]);
1128:       vs->isglobal.col[j] = is_col[j];
1129:     }
1130:   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
1131:     offset = A->cmap->rstart;
1132:     nsum = 0;
1133:     for (j=0; j<vs->nc; j++) {
1134:       MatNestFindNonzeroSubMatCol(A,j,&sub);
1135:       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
1136:       MatGetLocalSize(sub,PETSC_NULL,&n);
1137:       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1138:       nsum += n;
1139:     }
1140:     offset = 0;
1141: #if defined(PETSC_HAVE_MPI_EXSCAN)
1142:     MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);
1143: #else 
1144:     SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sorry but this code requires MPI_EXSCAN that doesn't exist on your machine's version of MPI, install a MPI2 with PETSc to get this functionality");
1145: #endif
1146:     for (j=0; j<vs->nc; j++) {
1147:       MatNestFindNonzeroSubMatCol(A,j,&sub);
1148:       MatGetLocalSize(sub,PETSC_NULL,&n);
1149:       MatGetBlockSize(sub,&bs);
1150:       ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.col[j]);
1151:       ISSetBlockSize(vs->isglobal.col[j],bs);
1152:       offset += n;
1153:     }
1154:   }

1156:   /* Set up the local ISs */
1157:   PetscMalloc(vs->nr*sizeof(IS),&vs->islocal.row);
1158:   PetscMalloc(vs->nc*sizeof(IS),&vs->islocal.col);
1159:   for (i=0,offset=0; i<vs->nr; i++) {
1160:     IS                     isloc;
1161:     ISLocalToGlobalMapping rmap = PETSC_NULL;
1162:     PetscInt               nlocal,bs;
1163:     MatNestFindNonzeroSubMatRow(A,i,&sub);
1164:     if (sub) {MatGetLocalToGlobalMapping(sub,&rmap,PETSC_NULL);}
1165:     if (rmap) {
1166:       MatGetBlockSize(sub,&bs);
1167:       ISLocalToGlobalMappingGetSize(rmap,&nlocal);
1168:       ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);
1169:       ISSetBlockSize(isloc,bs);
1170:     } else {
1171:       nlocal = 0;
1172:       isloc  = PETSC_NULL;
1173:     }
1174:     vs->islocal.row[i] = isloc;
1175:     offset += nlocal;
1176:   }
1177:   for (i=0,offset=0; i<vs->nc; i++) {
1178:     IS                     isloc;
1179:     ISLocalToGlobalMapping cmap = PETSC_NULL;
1180:     PetscInt               nlocal,bs;
1181:     MatNestFindNonzeroSubMatCol(A,i,&sub);
1182:     if (sub) {MatGetLocalToGlobalMapping(sub,PETSC_NULL,&cmap);}
1183:     if (cmap) {
1184:       MatGetBlockSize(sub,&bs);
1185:       ISLocalToGlobalMappingGetSize(cmap,&nlocal);
1186:       ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);
1187:       ISSetBlockSize(isloc,bs);
1188:     } else {
1189:       nlocal = 0;
1190:       isloc  = PETSC_NULL;
1191:     }
1192:     vs->islocal.col[i] = isloc;
1193:     offset += nlocal;
1194:   }

1196:   /* Set up the aggregate ISLocalToGlobalMapping */
1197:   {
1198:     ISLocalToGlobalMapping rmap,rmapb,cmap,cmapb;
1199:     MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap,&rmapb);
1200:     MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap,&cmapb);
1201:     if (rmap && cmap) {MatSetLocalToGlobalMapping(A,rmap,cmap);}
1202:     if (rmapb && cmapb) {MatSetLocalToGlobalMappingBlock(A,rmapb,cmapb);}
1203:     ISLocalToGlobalMappingDestroy(&rmap);
1204:     ISLocalToGlobalMappingDestroy(&rmapb);
1205:     ISLocalToGlobalMappingDestroy(&cmap);
1206:     ISLocalToGlobalMappingDestroy(&cmapb);
1207:   }

1209: #if defined(PETSC_USE_DEBUG)
1210:   for (i=0; i<vs->nr; i++) {
1211:     for (j=0; j<vs->nc; j++) {
1212:       PetscInt m,n,M,N,mi,ni,Mi,Ni;
1213:       Mat B = vs->m[i][j];
1214:       if (!B) continue;
1215:       MatGetSize(B,&M,&N);
1216:       MatGetLocalSize(B,&m,&n);
1217:       ISGetSize(vs->isglobal.row[i],&Mi);
1218:       ISGetSize(vs->isglobal.col[j],&Ni);
1219:       ISGetLocalSize(vs->isglobal.row[i],&mi);
1220:       ISGetLocalSize(vs->isglobal.col[j],&ni);
1221:       if (M != Mi || N != Ni) SETERRQ6(((PetscObject)sub)->comm,PETSC_ERR_ARG_INCOMP,"Global sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",M,N,i,j,Mi,Ni);
1222:       if (m != mi || n != ni) SETERRQ6(((PetscObject)sub)->comm,PETSC_ERR_ARG_INCOMP,"Local sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",m,n,i,j,mi,ni);
1223:     }
1224:   }
1225: #endif

1227:   /* Set A->assembled if all non-null blocks are currently assembled */
1228:   for (i=0; i<vs->nr; i++) {
1229:     for (j=0; j<vs->nc; j++) {
1230:       if (vs->m[i][j] && !vs->m[i][j]->assembled) return(0);
1231:     }
1232:   }
1233:   A->assembled = PETSC_TRUE;
1234:   return(0);
1235: }

1239: /*@
1240:    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately

1242:    Collective on Mat

1244:    Input Parameter:
1245: +  comm - Communicator for the new Mat
1246: .  nr - number of nested row blocks
1247: .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
1248: .  nc - number of nested column blocks
1249: .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
1250: -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL

1252:    Output Parameter:
1253: .  B - new matrix

1255:    Level: advanced

1257: .seealso: MatCreate(), VecCreateNest(), DMGetMatrix(), MATNEST
1258: @*/
1259: PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1260: {
1261:   Mat            A;

1265:   *B = 0;
1266:   MatCreate(comm,&A);
1267:   MatSetType(A,MATNEST);
1268:   MatNestSetSubMats(A,nr,is_row,nc,is_col,a);
1269:   *B = A;
1270:   return(0);
1271: }

1273: /*MC
1274:   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.

1276:   Level: intermediate

1278:   Notes:
1279:   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1280:   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1281:   It is usually used with DMComposite and DMGetMatrix()

1283: .seealso: MatCreate(), MatType, MatCreateNest()
1284: M*/
1288: PetscErrorCode MatCreate_Nest(Mat A)
1289: {
1290:   Mat_Nest       *s;

1294:   PetscNewLog(A,Mat_Nest,&s);
1295:   A->data         = (void*)s;
1296:   s->nr = s->nc   = -1;
1297:   s->m            = PETSC_NULL;

1299:   PetscMemzero(A->ops,sizeof(*A->ops));
1300:   A->ops->mult                  = MatMult_Nest;
1301:   A->ops->multadd               = MatMultAdd_Nest;
1302:   A->ops->multtranspose         = MatMultTranspose_Nest;
1303:   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
1304:   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1305:   A->ops->assemblyend           = MatAssemblyEnd_Nest;
1306:   A->ops->zeroentries           = MatZeroEntries_Nest;
1307:   A->ops->duplicate             = MatDuplicate_Nest;
1308:   A->ops->getsubmatrix          = MatGetSubMatrix_Nest;
1309:   A->ops->destroy               = MatDestroy_Nest;
1310:   A->ops->view                  = MatView_Nest;
1311:   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
1312:   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
1313:   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
1314:   A->ops->getdiagonal           = MatGetDiagonal_Nest;
1315:   A->ops->diagonalscale         = MatDiagonalScale_Nest;
1316:   A->ops->scale                 = MatScale_Nest;
1317:   A->ops->shift                 = MatShift_Nest;

1319:   A->spptr        = 0;
1320:   A->same_nonzero = PETSC_FALSE;
1321:   A->assembled    = PETSC_FALSE;

1323:   /* expose Nest api's */
1324:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "MatNestGetSubMat_Nest",   MatNestGetSubMat_Nest);
1325:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C",   "MatNestSetSubMat_Nest",   MatNestSetSubMat_Nest);
1326:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "MatNestGetSubMats_Nest",  MatNestGetSubMats_Nest);
1327:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "MatNestGetSize_Nest",     MatNestGetSize_Nest);
1328:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "MatNestSetVecType_Nest",  MatNestSetVecType_Nest);
1329:   PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",  "MatNestSetSubMats_Nest",  MatNestSetSubMats_Nest);

1331:   PetscObjectChangeTypeName((PetscObject)A,MATNEST);
1332:   return(0);
1333: }