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: }