xref: /petsc/src/mat/impls/nest/matnest.c (revision ea5d4fccf296dd2bbd0f9c3a3343651cb1066da7)
1 
2 #include "matnestimpl.h" /*I   "petscmat.h"   I*/
3 
4 static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
5 static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left);
6 
7 /* private functions */
8 #undef __FUNCT__
9 #define __FUNCT__ "MatNestGetSizes_Private"
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;
14   PetscErrorCode ierr;
15 
16   PetscFunctionBegin;
17   *m = *n = *M = *N = 0;
18   for (i=0; i<bA->nr; i++) {  /* rows */
19     PetscInt sm,sM;
20     ierr = ISGetLocalSize(bA->isglobal.row[i],&sm);CHKERRQ(ierr);
21     ierr = ISGetSize(bA->isglobal.row[i],&sM);CHKERRQ(ierr);
22     *m += sm;
23     *M += sM;
24   }
25   for (j=0; j<bA->nc; j++) {  /* cols */
26     PetscInt sn,sN;
27     ierr = ISGetLocalSize(bA->isglobal.col[j],&sn);CHKERRQ(ierr);
28     ierr = ISGetSize(bA->isglobal.col[j],&sN);CHKERRQ(ierr);
29     *n += sn;
30     *N += sN;
31   }
32   PetscFunctionReturn(0);
33 }
34 
35 /* operations */
36 #undef __FUNCT__
37 #define __FUNCT__ "MatMult_Nest"
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;
43   PetscErrorCode ierr;
44 
45   PetscFunctionBegin;
46   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
47   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
48   for (i=0; i<nr; i++) {
49     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
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       ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr);
54     }
55   }
56   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
57   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
58   PetscFunctionReturn(0);
59 }
60 
61 #undef __FUNCT__
62 #define __FUNCT__ "MatMultAdd_Nest"
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;
68   PetscErrorCode ierr;
69 
70   PetscFunctionBegin;
71   for (i=0; i<nr; i++) {ierr = VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
72   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
73   for (i=0; i<nr; i++) {
74     if (y != z) {
75       Vec by;
76       ierr = VecGetSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
77       ierr = VecCopy(by,bz[i]);CHKERRQ(ierr);
78       ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
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       ierr = MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);CHKERRQ(ierr);
84     }
85   }
86   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
87   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
88   PetscFunctionReturn(0);
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "MatMultTranspose_Nest"
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;
98   PetscErrorCode ierr;
99 
100   PetscFunctionBegin;
101   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
102   for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
103   for (j=0; j<nc; j++) {
104     ierr = VecZeroEntries(by[j]);CHKERRQ(ierr);
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       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr);
109     }
110   }
111   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
112   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
113   PetscFunctionReturn(0);
114 }
115 
116 #undef __FUNCT__
117 #define __FUNCT__ "MatMultTransposeAdd_Nest"
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;
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
127   for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
128   for (j=0; j<nc; j++) {
129     if (y != z) {
130       Vec by;
131       ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
132       ierr = VecCopy(by,bz[j]);CHKERRQ(ierr);
133       ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
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       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr);
139     }
140   }
141   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
142   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
143   PetscFunctionReturn(0);
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "MatNestDestroyISList"
148 static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
149 {
150   PetscErrorCode ierr;
151   IS             *lst = *list;
152   PetscInt       i;
153 
154   PetscFunctionBegin;
155   if (!lst) PetscFunctionReturn(0);
156   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
157   ierr = PetscFree(lst);CHKERRQ(ierr);
158   *list = PETSC_NULL;
159   PetscFunctionReturn(0);
160 }
161 
162 #undef __FUNCT__
163 #define __FUNCT__ "MatDestroy_Nest"
164 static PetscErrorCode MatDestroy_Nest(Mat A)
165 {
166   Mat_Nest       *vs = (Mat_Nest*)A->data;
167   PetscInt       i,j;
168   PetscErrorCode ierr;
169 
170   PetscFunctionBegin;
171   /* release the matrices and the place holders */
172   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
173   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
174   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
175   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
176 
177   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
178   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
179 
180   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
181 
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         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
187       }
188       ierr = PetscFree( vs->m[i] );CHKERRQ(ierr);
189     }
190     ierr = PetscFree(vs->m);CHKERRQ(ierr);
191   }
192   ierr = PetscFree(A->data);CHKERRQ(ierr);
193 
194   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "",0);CHKERRQ(ierr);
195   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C",   "",0);CHKERRQ(ierr);
196   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "",0);CHKERRQ(ierr);
197   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "",0);CHKERRQ(ierr);
198   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetISs_C",      "",0);CHKERRQ(ierr);
199   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetLocalISs_C", "",0);CHKERRQ(ierr);
200   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "",0);CHKERRQ(ierr);
201   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",   "",0);CHKERRQ(ierr);
202   PetscFunctionReturn(0);
203 }
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "MatAssemblyBegin_Nest"
207 static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
208 {
209   Mat_Nest       *vs = (Mat_Nest*)A->data;
210   PetscInt       i,j;
211   PetscErrorCode ierr;
212 
213   PetscFunctionBegin;
214   for (i=0; i<vs->nr; i++) {
215     for (j=0; j<vs->nc; j++) {
216       if (vs->m[i][j]) {
217         ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr);
218         if (!vs->splitassembly) {
219           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
220            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
221            * already performing an assembly, but the result would by more complicated and appears to offer less
222            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
223            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
224            */
225           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
226         }
227       }
228     }
229   }
230   PetscFunctionReturn(0);
231 }
232 
233 #undef __FUNCT__
234 #define __FUNCT__ "MatAssemblyEnd_Nest"
235 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
236 {
237   Mat_Nest       *vs = (Mat_Nest*)A->data;
238   PetscInt       i,j;
239   PetscErrorCode ierr;
240 
241   PetscFunctionBegin;
242   for (i=0; i<vs->nr; i++) {
243     for (j=0; j<vs->nc; j++) {
244       if (vs->m[i][j]) {
245         if (vs->splitassembly) {
246           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
247         }
248       }
249     }
250   }
251   PetscFunctionReturn(0);
252 }
253 
254 #undef __FUNCT__
255 #define __FUNCT__ "MatNestFindNonzeroSubMatRow"
256 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
257 {
258   PetscErrorCode ierr;
259   Mat_Nest       *vs = (Mat_Nest*)A->data;
260   PetscInt       j;
261   Mat            sub;
262 
263   PetscFunctionBegin;
264   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)PETSC_NULL; /* Prefer to find on the diagonal */
265   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
266   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
267   *B = sub;
268   PetscFunctionReturn(0);
269 }
270 
271 #undef __FUNCT__
272 #define __FUNCT__ "MatNestFindNonzeroSubMatCol"
273 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
274 {
275   PetscErrorCode ierr;
276   Mat_Nest       *vs = (Mat_Nest*)A->data;
277   PetscInt       i;
278   Mat            sub;
279 
280   PetscFunctionBegin;
281   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)PETSC_NULL; /* Prefer to find on the diagonal */
282   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
283   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
284   *B = sub;
285   PetscFunctionReturn(0);
286 }
287 
288 #undef __FUNCT__
289 #define __FUNCT__ "MatNestFindIS"
290 static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
291 {
292   PetscErrorCode ierr;
293   PetscInt       i;
294   PetscBool      flg;
295 
296   PetscFunctionBegin;
297   PetscValidPointer(list,3);
298   PetscValidHeaderSpecific(is,IS_CLASSID,4);
299   PetscValidIntPointer(found,5);
300   *found = -1;
301   for (i=0; i<n; i++) {
302     if (!list[i]) continue;
303     ierr = ISEqual(list[i],is,&flg);CHKERRQ(ierr);
304     if (flg) {
305       *found = i;
306       PetscFunctionReturn(0);
307     }
308   }
309   SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Could not find index set");
310   PetscFunctionReturn(0);
311 }
312 
313 #undef __FUNCT__
314 #define __FUNCT__ "MatNestGetRow"
315 /* Get a block row as a new MatNest */
316 static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
317 {
318   Mat_Nest       *vs = (Mat_Nest*)A->data;
319   char           keyname[256];
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   *B = PETSC_NULL;
324   ierr = PetscSNPrintf(keyname,sizeof keyname,"NestRow_%D",row);CHKERRQ(ierr);
325   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
326   if (*B) PetscFunctionReturn(0);
327 
328   ierr = MatCreateNest(((PetscObject)A)->comm,1,PETSC_NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
329   (*B)->assembled = A->assembled;
330   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
331   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
332   PetscFunctionReturn(0);
333 }
334 
335 #undef __FUNCT__
336 #define __FUNCT__ "MatNestFindSubMat"
337 static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
338 {
339   Mat_Nest       *vs = (Mat_Nest*)A->data;
340   PetscErrorCode ierr;
341   PetscInt       row,col;
342   PetscBool      same,isFullCol,isFullColGlobal;
343 
344   PetscFunctionBegin;
345   /* Check if full column space. This is a hack */
346   isFullCol = PETSC_FALSE;
347   ierr = PetscTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
348   if (same) {
349     PetscInt n,first,step,i,an,am,afirst,astep;
350     ierr = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
351     ierr = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
352     isFullCol = PETSC_TRUE;
353     for (i=0,an=A->cmap->rstart; i<vs->nc; i++) {
354       ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr);
355       ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr);
356       if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
357       an += am;
358     }
359     if (an != A->cmap->rstart+n) isFullCol = PETSC_FALSE;
360   }
361   ierr = MPI_Allreduce(&isFullCol,&isFullColGlobal,1,MPI_INT,MPI_LAND,((PetscObject)iscol)->comm);CHKERRQ(ierr);
362 
363   if (isFullColGlobal) {
364     PetscInt row;
365     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
366     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
367   } else {
368     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
369     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
370     *B = vs->m[row][col];
371   }
372   PetscFunctionReturn(0);
373 }
374 
375 #undef __FUNCT__
376 #define __FUNCT__ "MatGetSubMatrix_Nest"
377 static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
378 {
379   PetscErrorCode ierr;
380   Mat_Nest       *vs = (Mat_Nest*)A->data;
381   Mat            sub;
382 
383   PetscFunctionBegin;
384   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
385   switch (reuse) {
386   case MAT_INITIAL_MATRIX:
387     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
388     *B = sub;
389     break;
390   case MAT_REUSE_MATRIX:
391     if (sub != *B) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
392     break;
393   case MAT_IGNORE_MATRIX:       /* Nothing to do */
394     break;
395   }
396   PetscFunctionReturn(0);
397 }
398 
399 #undef __FUNCT__
400 #define __FUNCT__ "MatGetLocalSubMatrix_Nest"
401 PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
402 {
403   PetscErrorCode ierr;
404   Mat_Nest       *vs = (Mat_Nest*)A->data;
405   Mat            sub;
406 
407   PetscFunctionBegin;
408   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
409   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
410   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
411   *B = sub;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "MatRestoreLocalSubMatrix_Nest"
417 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
418 {
419   PetscErrorCode ierr;
420   Mat_Nest       *vs = (Mat_Nest*)A->data;
421   Mat            sub;
422 
423   PetscFunctionBegin;
424   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
425   if (*B != sub) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
426   if (sub) {
427     if (((PetscObject)sub)->refct <= 1) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
428     ierr = MatDestroy(B);CHKERRQ(ierr);
429   }
430   PetscFunctionReturn(0);
431 }
432 
433 #undef __FUNCT__
434 #define __FUNCT__ "MatGetDiagonal_Nest"
435 static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
436 {
437   Mat_Nest       *bA = (Mat_Nest*)A->data;
438   PetscInt       i;
439   PetscErrorCode ierr;
440 
441   PetscFunctionBegin;
442   for (i=0; i<bA->nr; i++) {
443     Vec bv;
444     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
445     if (bA->m[i][i]) {
446       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
447     } else {
448       ierr = VecSet(bv,1.0);CHKERRQ(ierr);
449     }
450     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
451   }
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "MatDiagonalScale_Nest"
457 static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
458 {
459   Mat_Nest       *bA = (Mat_Nest*)A->data;
460   Vec            bl,*br;
461   PetscInt       i,j;
462   PetscErrorCode ierr;
463 
464   PetscFunctionBegin;
465   ierr = PetscMalloc(bA->nc*sizeof(Vec),&br);CHKERRQ(ierr);
466   for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
467   for (i=0; i<bA->nr; i++) {
468     ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
469     for (j=0; j<bA->nc; j++) {
470       if (bA->m[i][j]) {
471         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
472       }
473     }
474     ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
475   }
476   for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
477   ierr = PetscFree(br);CHKERRQ(ierr);
478   PetscFunctionReturn(0);
479 }
480 
481 #undef __FUNCT__
482 #define __FUNCT__ "MatScale_Nest"
483 static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
484 {
485   Mat_Nest       *bA = (Mat_Nest*)A->data;
486   PetscInt       i,j;
487   PetscErrorCode ierr;
488 
489   PetscFunctionBegin;
490   for (i=0; i<bA->nr; i++) {
491     for (j=0; j<bA->nc; j++) {
492       if (bA->m[i][j]) {
493         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
494       }
495     }
496   }
497   PetscFunctionReturn(0);
498 }
499 
500 #undef __FUNCT__
501 #define __FUNCT__ "MatShift_Nest"
502 static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
503 {
504   Mat_Nest       *bA = (Mat_Nest*)A->data;
505   PetscInt       i;
506   PetscErrorCode ierr;
507 
508   PetscFunctionBegin;
509   for (i=0; i<bA->nr; i++) {
510     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);
511     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
512   }
513   PetscFunctionReturn(0);
514 }
515 
516 #undef __FUNCT__
517 #define __FUNCT__ "MatGetVecs_Nest"
518 static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left)
519 {
520   Mat_Nest       *bA = (Mat_Nest*)A->data;
521   Vec            *L,*R;
522   MPI_Comm       comm;
523   PetscInt       i,j;
524   PetscErrorCode ierr;
525 
526   PetscFunctionBegin;
527   comm = ((PetscObject)A)->comm;
528   if (right) {
529     /* allocate R */
530     ierr = PetscMalloc( sizeof(Vec) * bA->nc, &R );CHKERRQ(ierr);
531     /* Create the right vectors */
532     for (j=0; j<bA->nc; j++) {
533       for (i=0; i<bA->nr; i++) {
534         if (bA->m[i][j]) {
535           ierr = MatGetVecs(bA->m[i][j],&R[j],PETSC_NULL);CHKERRQ(ierr);
536           break;
537         }
538       }
539       if (i==bA->nr) {
540         /* have an empty column */
541         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
542       }
543     }
544     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
545     /* hand back control to the nest vector */
546     for (j=0; j<bA->nc; j++) {
547       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
548     }
549     ierr = PetscFree(R);CHKERRQ(ierr);
550   }
551 
552   if (left) {
553     /* allocate L */
554     ierr = PetscMalloc( sizeof(Vec) * bA->nr, &L );CHKERRQ(ierr);
555     /* Create the left vectors */
556     for (i=0; i<bA->nr; i++) {
557       for (j=0; j<bA->nc; j++) {
558         if (bA->m[i][j]) {
559           ierr = MatGetVecs(bA->m[i][j],PETSC_NULL,&L[i]);CHKERRQ(ierr);
560           break;
561         }
562       }
563       if (j==bA->nc) {
564         /* have an empty row */
565         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
566       }
567     }
568 
569     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
570     for (i=0; i<bA->nr; i++) {
571       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
572     }
573 
574     ierr = PetscFree(L);CHKERRQ(ierr);
575   }
576   PetscFunctionReturn(0);
577 }
578 
579 #undef __FUNCT__
580 #define __FUNCT__ "MatView_Nest"
581 static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
582 {
583   Mat_Nest       *bA = (Mat_Nest*)A->data;
584   PetscBool      isascii;
585   PetscInt       i,j;
586   PetscErrorCode ierr;
587 
588   PetscFunctionBegin;
589   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
590   if (isascii) {
591 
592     PetscViewerASCIIPrintf(viewer,"Matrix object: \n" );
593     PetscViewerASCIIPushTab( viewer );    /* push0 */
594     PetscViewerASCIIPrintf( viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc);
595 
596     PetscViewerASCIIPrintf(viewer,"MatNest structure: \n" );
597     for (i=0; i<bA->nr; i++) {
598       for (j=0; j<bA->nc; j++) {
599         const MatType type;
600         char name[256] = "",prefix[256] = "";
601         PetscInt NR,NC;
602         PetscBool isNest = PETSC_FALSE;
603 
604         if (!bA->m[i][j]) {
605           PetscViewerASCIIPrintf( viewer, "(%D,%D) : PETSC_NULL \n",i,j);
606           continue;
607         }
608         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
609         ierr = MatGetType( bA->m[i][j], &type );CHKERRQ(ierr);
610         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof name,"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
611         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof prefix,"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
612         ierr = PetscTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
613 
614         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
615 
616         if (isNest) {
617           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
618           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
619           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
620         }
621       }
622     }
623     PetscViewerASCIIPopTab(viewer);    /* pop0 */
624   }
625   PetscFunctionReturn(0);
626 }
627 
628 #undef __FUNCT__
629 #define __FUNCT__ "MatZeroEntries_Nest"
630 static PetscErrorCode MatZeroEntries_Nest(Mat A)
631 {
632   Mat_Nest       *bA = (Mat_Nest*)A->data;
633   PetscInt       i,j;
634   PetscErrorCode ierr;
635 
636   PetscFunctionBegin;
637   for (i=0; i<bA->nr; i++) {
638     for (j=0; j<bA->nc; j++) {
639       if (!bA->m[i][j]) continue;
640       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
641     }
642   }
643   PetscFunctionReturn(0);
644 }
645 
646 #undef __FUNCT__
647 #define __FUNCT__ "MatDuplicate_Nest"
648 static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
649 {
650   Mat_Nest       *bA = (Mat_Nest*)A->data;
651   Mat            *b;
652   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
653   PetscErrorCode ierr;
654 
655   PetscFunctionBegin;
656   ierr = PetscMalloc(nr*nc*sizeof(Mat),&b);CHKERRQ(ierr);
657   for (i=0; i<nr; i++) {
658     for (j=0; j<nc; j++) {
659       if (bA->m[i][j]) {
660         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
661       } else {
662         b[i*nc+j] = PETSC_NULL;
663       }
664     }
665   }
666   ierr = MatCreateNest(((PetscObject)A)->comm,nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
667   /* Give the new MatNest exclusive ownership */
668   for (i=0; i<nr*nc; i++) {
669     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
670   }
671   ierr = PetscFree(b);CHKERRQ(ierr);
672 
673   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
674   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677 
678 /* nest api */
679 EXTERN_C_BEGIN
680 #undef __FUNCT__
681 #define __FUNCT__ "MatNestGetSubMat_Nest"
682 PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
683 {
684   Mat_Nest *bA = (Mat_Nest*)A->data;
685   PetscFunctionBegin;
686   if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
687   if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
688   *mat = bA->m[idxm][jdxm];
689   PetscFunctionReturn(0);
690 }
691 EXTERN_C_END
692 
693 #undef __FUNCT__
694 #define __FUNCT__ "MatNestGetSubMat"
695 /*@C
696  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
697 
698  Not collective
699 
700  Input Parameters:
701 +   A  - nest matrix
702 .   idxm - index of the matrix within the nest matrix
703 -   jdxm - index of the matrix within the nest matrix
704 
705  Output Parameter:
706 .   sub - matrix at index idxm,jdxm within the nest matrix
707 
708  Level: developer
709 
710 .seealso: MatNestGetSize(), MatNestGetSubMats()
711 @*/
712 PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
713 {
714   PetscErrorCode ierr;
715 
716   PetscFunctionBegin;
717   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
718   PetscFunctionReturn(0);
719 }
720 
721 EXTERN_C_BEGIN
722 #undef __FUNCT__
723 #define __FUNCT__ "MatNestSetSubMat_Nest"
724 PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
725 {
726   Mat_Nest *bA = (Mat_Nest*)A->data;
727   PetscInt m,n,M,N,mi,ni,Mi,Ni;
728   PetscErrorCode ierr;
729 
730   PetscFunctionBegin;
731   if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
732   if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
733   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
734   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
735   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
736   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
737   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
738   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
739   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);
740   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);
741   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
742   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
743   bA->m[idxm][jdxm] = mat;
744   PetscFunctionReturn(0);
745 }
746 EXTERN_C_END
747 
748 #undef __FUNCT__
749 #define __FUNCT__ "MatNestSetSubMat"
750 /*@C
751  MatNestSetSubMat - Set a single submatrix in the nest matrix.
752 
753  Logically collective on the submatrix communicator
754 
755  Input Parameters:
756 +   A  - nest matrix
757 .   idxm - index of the matrix within the nest matrix
758 .   jdxm - index of the matrix within the nest matrix
759 -   sub - matrix at index idxm,jdxm within the nest matrix
760 
761  Notes:
762  The new submatrix must have the same size and communicator as that block of the nest.
763 
764  This increments the reference count of the submatrix.
765 
766  Level: developer
767 
768 .seealso: MatNestSetSubMats(), MatNestGetSubMat()
769 @*/
770 PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
771 {
772   PetscErrorCode ierr;
773 
774   PetscFunctionBegin;
775   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
776   PetscFunctionReturn(0);
777 }
778 
779 EXTERN_C_BEGIN
780 #undef __FUNCT__
781 #define __FUNCT__ "MatNestGetSubMats_Nest"
782 PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
783 {
784   Mat_Nest *bA = (Mat_Nest*)A->data;
785   PetscFunctionBegin;
786   if (M)   { *M   = bA->nr; }
787   if (N)   { *N   = bA->nc; }
788   if (mat) { *mat = bA->m;  }
789   PetscFunctionReturn(0);
790 }
791 EXTERN_C_END
792 
793 #undef __FUNCT__
794 #define __FUNCT__ "MatNestGetSubMats"
795 /*@C
796  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
797 
798  Not collective
799 
800  Input Parameters:
801 .   A  - nest matrix
802 
803  Output Parameter:
804 +   M - number of rows in the nest matrix
805 .   N - number of cols in the nest matrix
806 -   mat - 2d array of matrices
807 
808  Notes:
809 
810  The user should not free the array mat.
811 
812  Level: developer
813 
814 .seealso: MatNestGetSize(), MatNestGetSubMat()
815 @*/
816 PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
817 {
818   PetscErrorCode ierr;
819 
820   PetscFunctionBegin;
821   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
822   PetscFunctionReturn(0);
823 }
824 
825 EXTERN_C_BEGIN
826 #undef __FUNCT__
827 #define __FUNCT__ "MatNestGetSize_Nest"
828 PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
829 {
830   Mat_Nest  *bA = (Mat_Nest*)A->data;
831 
832   PetscFunctionBegin;
833   if (M) { *M  = bA->nr; }
834   if (N) { *N  = bA->nc; }
835   PetscFunctionReturn(0);
836 }
837 EXTERN_C_END
838 
839 #undef __FUNCT__
840 #define __FUNCT__ "MatNestGetSize"
841 /*@C
842  MatNestGetSize - Returns the size of the nest matrix.
843 
844  Not collective
845 
846  Input Parameters:
847 .   A  - nest matrix
848 
849  Output Parameter:
850 +   M - number of rows in the nested mat
851 -   N - number of cols in the nested mat
852 
853  Notes:
854 
855  Level: developer
856 
857 .seealso: MatNestGetSubMat(), MatNestGetSubMats()
858 @*/
859 PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
860 {
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
865   PetscFunctionReturn(0);
866 }
867 
868 #undef __FUNCT__
869 #define __FUNCT__ "MatNestGetISs_Nest"
870 PETSC_EXTERN_C PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
871 {
872   Mat_Nest       *vs = (Mat_Nest*)A->data;
873   PetscInt i;
874 
875   PetscFunctionBegin;
876   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
877   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
878   PetscFunctionReturn(0);
879 }
880 
881 #undef __FUNCT__
882 #define __FUNCT__ "MatNestGetISs"
883 /*@C
884  MatNestGetISs - Returns the index sets partitioning the row and column spaces
885 
886  Not collective
887 
888  Input Parameters:
889 .   A  - nest matrix
890 
891  Output Parameter:
892 +   rows - array of row index sets
893 -   cols - array of column index sets
894 
895  Level: advanced
896 
897  Notes:
898  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
899 
900 .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs()
901 @*/
902 PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
903 {
904   PetscErrorCode ierr;
905 
906   PetscFunctionBegin;
907   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
908   ierr = PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
909   PetscFunctionReturn(0);
910 }
911 
912 #undef __FUNCT__
913 #define __FUNCT__ "MatNestGetLocalISs_Nest"
914 PETSC_EXTERN_C PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
915 {
916   Mat_Nest       *vs = (Mat_Nest*)A->data;
917   PetscInt i;
918 
919   PetscFunctionBegin;
920   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
921   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
922   PetscFunctionReturn(0);
923 }
924 
925 #undef __FUNCT__
926 #define __FUNCT__ "MatNestGetLocalISs"
927 /*@C
928  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
929 
930  Not collective
931 
932  Input Parameters:
933 .   A  - nest matrix
934 
935  Output Parameter:
936 +   rows - array of row index sets (or PETSC_NULL to ignore)
937 -   cols - array of column index sets (or PETSC_NULL to ignore)
938 
939  Level: advanced
940 
941  Notes:
942  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
943 
944 .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs()
945 @*/
946 PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
947 {
948   PetscErrorCode ierr;
949 
950   PetscFunctionBegin;
951   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
952   ierr = PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
953   PetscFunctionReturn(0);
954 }
955 
956 EXTERN_C_BEGIN
957 #undef __FUNCT__
958 #define __FUNCT__ "MatNestSetVecType_Nest"
959 PetscErrorCode  MatNestSetVecType_Nest(Mat A,const VecType vtype)
960 {
961   PetscErrorCode ierr;
962   PetscBool      flg;
963 
964   PetscFunctionBegin;
965   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
966   /* In reality, this only distinguishes VECNEST and "other" */
967   A->ops->getvecs       = flg ? MatGetVecs_Nest : (PetscErrorCode (*)(Mat,Vec*,Vec*))0;
968  PetscFunctionReturn(0);
969 }
970 EXTERN_C_END
971 
972 #undef __FUNCT__
973 #define __FUNCT__ "MatNestSetVecType"
974 /*@C
975  MatNestSetVecType - Sets the type of Vec returned by MatGetVecs()
976 
977  Not collective
978 
979  Input Parameters:
980 +  A  - nest matrix
981 -  vtype - type to use for creating vectors
982 
983  Notes:
984 
985  Level: developer
986 
987 .seealso: MatGetVecs()
988 @*/
989 PetscErrorCode  MatNestSetVecType(Mat A,const VecType vtype)
990 {
991   PetscErrorCode ierr;
992 
993   PetscFunctionBegin;
994   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,const VecType),(A,vtype));CHKERRQ(ierr);
995   PetscFunctionReturn(0);
996 }
997 
998 EXTERN_C_BEGIN
999 #undef __FUNCT__
1000 #define __FUNCT__ "MatNestSetSubMats_Nest"
1001 PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1002 {
1003   Mat_Nest       *s = (Mat_Nest*)A->data;
1004   PetscInt       i,j,m,n,M,N;
1005   PetscErrorCode ierr;
1006 
1007   PetscFunctionBegin;
1008   s->nr = nr;
1009   s->nc = nc;
1010 
1011   /* Create space for submatrices */
1012   ierr = PetscMalloc(sizeof(Mat*)*nr,&s->m);CHKERRQ(ierr);
1013   for (i=0; i<nr; i++) {
1014     ierr = PetscMalloc(sizeof(Mat)*nc,&s->m[i]);CHKERRQ(ierr);
1015   }
1016   for (i=0; i<nr; i++) {
1017     for (j=0; j<nc; j++) {
1018       s->m[i][j] = a[i*nc+j];
1019       if (a[i*nc+j]) {
1020         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
1021       }
1022     }
1023   }
1024 
1025   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
1026 
1027   ierr = PetscMalloc(sizeof(PetscInt)*nr,&s->row_len);CHKERRQ(ierr);
1028   ierr = PetscMalloc(sizeof(PetscInt)*nc,&s->col_len);CHKERRQ(ierr);
1029   for (i=0; i<nr; i++) s->row_len[i]=-1;
1030   for (j=0; j<nc; j++) s->col_len[j]=-1;
1031 
1032   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
1033 
1034   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
1035   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
1036   ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr);
1037   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
1038   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
1039   ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr);
1040 
1041   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1042   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1043 
1044   ierr = PetscMalloc2(nr,Vec,&s->left,nc,Vec,&s->right);CHKERRQ(ierr);
1045   ierr = PetscMemzero(s->left,nr*sizeof(Vec));CHKERRQ(ierr);
1046   ierr = PetscMemzero(s->right,nc*sizeof(Vec));CHKERRQ(ierr);
1047   PetscFunctionReturn(0);
1048 }
1049 EXTERN_C_END
1050 
1051 #undef __FUNCT__
1052 #define __FUNCT__ "MatNestSetSubMats"
1053 /*@
1054    MatNestSetSubMats - Sets the nested submatrices
1055 
1056    Collective on Mat
1057 
1058    Input Parameter:
1059 +  N - nested matrix
1060 .  nr - number of nested row blocks
1061 .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
1062 .  nc - number of nested column blocks
1063 .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
1064 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL
1065 
1066    Level: advanced
1067 
1068 .seealso: MatCreateNest(), MATNEST
1069 @*/
1070 PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1071 {
1072   PetscErrorCode ierr;
1073   PetscInt i;
1074 
1075   PetscFunctionBegin;
1076   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1077   if (nr < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1078   if (nr && is_row) {
1079     PetscValidPointer(is_row,3);
1080     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1081   }
1082   if (nc < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
1083   if (nc && is_col) {
1084     PetscValidPointer(is_col,5);
1085     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1086   }
1087   if (nr*nc) PetscValidPointer(a,6);
1088   ierr = PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));CHKERRQ(ierr);
1089   PetscFunctionReturn(0);
1090 }
1091 
1092 #undef __FUNCT__
1093 #define __FUNCT__ "MatNestCreateAggregateL2G_Private"
1094 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog,ISLocalToGlobalMapping *ltogb)
1095 {
1096   PetscErrorCode ierr;
1097   PetscBool flg;
1098   PetscInt i,j,m,mi,*ix;
1099 
1100   PetscFunctionBegin;
1101   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
1102     if (islocal[i]) {
1103       ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
1104       flg = PETSC_TRUE;       /* We found a non-trivial entry */
1105     } else {
1106       ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
1107     }
1108     m += mi;
1109   }
1110   if (flg) {
1111     ierr = PetscMalloc(m*sizeof(*ix),&ix);CHKERRQ(ierr);
1112     for (i=0,n=0; i<n; i++) {
1113       ISLocalToGlobalMapping smap = PETSC_NULL;
1114       VecScatter scat;
1115       IS isreq;
1116       Vec lvec,gvec;
1117       union {char padding[sizeof(PetscScalar)]; PetscInt integer;} *x;
1118       Mat sub;
1119 
1120       if (sizeof (*x) != sizeof(PetscScalar)) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support when scalars smaller than integers");
1121       if (colflg) {
1122         ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1123       } else {
1124         ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
1125       }
1126       if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&smap,PETSC_NULL);CHKERRQ(ierr);}
1127       if (islocal[i]) {
1128         ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
1129       } else {
1130         ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
1131       }
1132       for (j=0; j<mi; j++) ix[m+j] = j;
1133       if (smap) {ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);}
1134       /*
1135         Now we need to extract the monolithic global indices that correspond to the given split global indices.
1136         In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1137         The approach here is ugly because it uses VecScatter to move indices.
1138        */
1139       ierr = VecCreateSeq(PETSC_COMM_SELF,mi,&lvec);CHKERRQ(ierr);
1140       ierr = VecCreateMPI(((PetscObject)isglobal[i])->comm,mi,PETSC_DECIDE,&gvec);CHKERRQ(ierr);
1141       ierr = ISCreateGeneral(((PetscObject)isglobal[i])->comm,mi,ix+m,PETSC_COPY_VALUES,&isreq);CHKERRQ(ierr);
1142       ierr = VecScatterCreate(gvec,isreq,lvec,PETSC_NULL,&scat);CHKERRQ(ierr);
1143       ierr = VecGetArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr);
1144       for (j=0; j<mi; j++) x[j].integer = ix[m+j];
1145       ierr = VecRestoreArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr);
1146       ierr = VecScatterBegin(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1147       ierr = VecScatterEnd(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1148       ierr = VecGetArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr);
1149       for (j=0; j<mi; j++) ix[m+j] = x[j].integer;
1150       ierr = VecRestoreArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr);
1151       ierr = VecDestroy(&lvec);CHKERRQ(ierr);
1152       ierr = VecDestroy(&gvec);CHKERRQ(ierr);
1153       ierr = ISDestroy(&isreq);CHKERRQ(ierr);
1154       ierr = VecScatterDestroy(&scat);CHKERRQ(ierr);
1155       m += mi;
1156     }
1157     ierr = ISLocalToGlobalMappingCreate(((PetscObject)A)->comm,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1158     *ltogb = PETSC_NULL;
1159   } else {
1160     *ltog = PETSC_NULL;
1161     *ltogb = PETSC_NULL;
1162   }
1163   PetscFunctionReturn(0);
1164 }
1165 
1166 
1167 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1168 /*
1169   nprocessors = NP
1170   Nest x^T = ( (g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1) )
1171        proc 0: => (g_0,h_0,)
1172        proc 1: => (g_1,h_1,)
1173        ...
1174        proc nprocs-1: => (g_NP-1,h_NP-1,)
1175 
1176             proc 0:                      proc 1:                    proc nprocs-1:
1177     is[0] = ( 0,1,2,...,nlocal(g_0)-1 )  ( 0,1,...,nlocal(g_1)-1 )  ( 0,1,...,nlocal(g_NP-1) )
1178 
1179             proc 0:
1180     is[1] = ( nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1 )
1181             proc 1:
1182     is[1] = ( nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1 )
1183 
1184             proc NP-1:
1185     is[1] = ( nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1 )
1186 */
1187 #undef __FUNCT__
1188 #define __FUNCT__ "MatSetUp_NestIS_Private"
1189 static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1190 {
1191   Mat_Nest       *vs = (Mat_Nest*)A->data;
1192   PetscInt       i,j,offset,n,nsum,bs;
1193   PetscErrorCode ierr;
1194   Mat            sub;
1195 
1196   PetscFunctionBegin;
1197   ierr = PetscMalloc(sizeof(IS)*nr,&vs->isglobal.row);CHKERRQ(ierr);
1198   ierr = PetscMalloc(sizeof(IS)*nc,&vs->isglobal.col);CHKERRQ(ierr);
1199   if (is_row) { /* valid IS is passed in */
1200     /* refs on is[] are incremeneted */
1201     for (i=0; i<vs->nr; i++) {
1202       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
1203       vs->isglobal.row[i] = is_row[i];
1204     }
1205   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
1206     nsum = 0;
1207     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
1208       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1209       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
1210       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
1211       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1212       nsum += n;
1213     }
1214     offset = 0;
1215 #if defined(PETSC_HAVE_MPI_EXSCAN)
1216     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
1217 #else
1218     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");
1219 #endif
1220     for (i=0; i<vs->nr; i++) {
1221       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1222       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
1223       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1224       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1225       ierr = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
1226       offset += n;
1227     }
1228   }
1229 
1230   if (is_col) { /* valid IS is passed in */
1231     /* refs on is[] are incremeneted */
1232     for (j=0; j<vs->nc; j++) {
1233       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
1234       vs->isglobal.col[j] = is_col[j];
1235     }
1236   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
1237     offset = A->cmap->rstart;
1238     nsum = 0;
1239     for (j=0; j<vs->nc; j++) {
1240       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1241       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
1242       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
1243       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1244       nsum += n;
1245     }
1246     offset = 0;
1247 #if defined(PETSC_HAVE_MPI_EXSCAN)
1248     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
1249 #else
1250     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");
1251 #endif
1252     for (j=0; j<vs->nc; j++) {
1253       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1254       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
1255       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1256       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1257       ierr = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
1258       offset += n;
1259     }
1260   }
1261 
1262   /* Set up the local ISs */
1263   ierr = PetscMalloc(vs->nr*sizeof(IS),&vs->islocal.row);CHKERRQ(ierr);
1264   ierr = PetscMalloc(vs->nc*sizeof(IS),&vs->islocal.col);CHKERRQ(ierr);
1265   for (i=0,offset=0; i<vs->nr; i++) {
1266     IS                     isloc;
1267     ISLocalToGlobalMapping rmap = PETSC_NULL;
1268     PetscInt               nlocal,bs;
1269     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1270     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,PETSC_NULL);CHKERRQ(ierr);}
1271     if (rmap) {
1272       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1273       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1274       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1275       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1276     } else {
1277       nlocal = 0;
1278       isloc  = PETSC_NULL;
1279     }
1280     vs->islocal.row[i] = isloc;
1281     offset += nlocal;
1282   }
1283   for (i=0,offset=0; i<vs->nc; i++) {
1284     IS                     isloc;
1285     ISLocalToGlobalMapping cmap = PETSC_NULL;
1286     PetscInt               nlocal,bs;
1287     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
1288     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,PETSC_NULL,&cmap);CHKERRQ(ierr);}
1289     if (cmap) {
1290       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1291       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1292       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1293       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1294     } else {
1295       nlocal = 0;
1296       isloc  = PETSC_NULL;
1297     }
1298     vs->islocal.col[i] = isloc;
1299     offset += nlocal;
1300   }
1301 
1302   /* Set up the aggregate ISLocalToGlobalMapping */
1303   {
1304     ISLocalToGlobalMapping rmap,rmapb,cmap,cmapb;
1305     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap,&rmapb);CHKERRQ(ierr);
1306     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap,&cmapb);CHKERRQ(ierr);
1307     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
1308     if (rmapb && cmapb) {ierr = MatSetLocalToGlobalMappingBlock(A,rmapb,cmapb);CHKERRQ(ierr);}
1309     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
1310     ierr = ISLocalToGlobalMappingDestroy(&rmapb);CHKERRQ(ierr);
1311     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
1312     ierr = ISLocalToGlobalMappingDestroy(&cmapb);CHKERRQ(ierr);
1313   }
1314 
1315 #if defined(PETSC_USE_DEBUG)
1316   for (i=0; i<vs->nr; i++) {
1317     for (j=0; j<vs->nc; j++) {
1318       PetscInt m,n,M,N,mi,ni,Mi,Ni;
1319       Mat B = vs->m[i][j];
1320       if (!B) continue;
1321       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
1322       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
1323       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
1324       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
1325       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
1326       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1327       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);
1328       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);
1329     }
1330   }
1331 #endif
1332 
1333   /* Set A->assembled if all non-null blocks are currently assembled */
1334   for (i=0; i<vs->nr; i++) {
1335     for (j=0; j<vs->nc; j++) {
1336       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1337     }
1338   }
1339   A->assembled = PETSC_TRUE;
1340   PetscFunctionReturn(0);
1341 }
1342 
1343 #undef __FUNCT__
1344 #define __FUNCT__ "MatCreateNest"
1345 /*@
1346    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1347 
1348    Collective on Mat
1349 
1350    Input Parameter:
1351 +  comm - Communicator for the new Mat
1352 .  nr - number of nested row blocks
1353 .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
1354 .  nc - number of nested column blocks
1355 .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
1356 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL
1357 
1358    Output Parameter:
1359 .  B - new matrix
1360 
1361    Level: advanced
1362 
1363 .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST
1364 @*/
1365 PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1366 {
1367   Mat            A;
1368   PetscErrorCode ierr;
1369 
1370   PetscFunctionBegin;
1371   *B = 0;
1372   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1373   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
1374   ierr = MatSetUp(A);CHKERRQ(ierr);
1375   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1376   *B = A;
1377   PetscFunctionReturn(0);
1378 }
1379 
1380 /*MC
1381   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1382 
1383   Level: intermediate
1384 
1385   Notes:
1386   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1387   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1388   It is usually used with DMComposite and DMCreateMatrix()
1389 
1390 .seealso: MatCreate(), MatType, MatCreateNest()
1391 M*/
1392 EXTERN_C_BEGIN
1393 #undef __FUNCT__
1394 #define __FUNCT__ "MatCreate_Nest"
1395 PetscErrorCode MatCreate_Nest(Mat A)
1396 {
1397   Mat_Nest       *s;
1398   PetscErrorCode ierr;
1399 
1400   PetscFunctionBegin;
1401   ierr = PetscNewLog(A,Mat_Nest,&s);CHKERRQ(ierr);
1402   A->data = (void*)s;
1403 
1404   s->nr            = -1;
1405   s->nc            = -1;
1406   s->m             = PETSC_NULL;
1407   s->splitassembly = PETSC_FALSE;
1408 
1409   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
1410   A->ops->mult                  = MatMult_Nest;
1411   A->ops->multadd               = MatMultAdd_Nest;
1412   A->ops->multtranspose         = MatMultTranspose_Nest;
1413   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
1414   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1415   A->ops->assemblyend           = MatAssemblyEnd_Nest;
1416   A->ops->zeroentries           = MatZeroEntries_Nest;
1417   A->ops->duplicate             = MatDuplicate_Nest;
1418   A->ops->getsubmatrix          = MatGetSubMatrix_Nest;
1419   A->ops->destroy               = MatDestroy_Nest;
1420   A->ops->view                  = MatView_Nest;
1421   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
1422   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
1423   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
1424   A->ops->getdiagonal           = MatGetDiagonal_Nest;
1425   A->ops->diagonalscale         = MatDiagonalScale_Nest;
1426   A->ops->scale                 = MatScale_Nest;
1427   A->ops->shift                 = MatShift_Nest;
1428 
1429   A->spptr        = 0;
1430   A->same_nonzero = PETSC_FALSE;
1431   A->assembled    = PETSC_FALSE;
1432 
1433   /* expose Nest api's */
1434   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "MatNestGetSubMat_Nest",   MatNestGetSubMat_Nest);CHKERRQ(ierr);
1435   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C",   "MatNestSetSubMat_Nest",   MatNestSetSubMat_Nest);CHKERRQ(ierr);
1436   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "MatNestGetSubMats_Nest",  MatNestGetSubMats_Nest);CHKERRQ(ierr);
1437   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "MatNestGetSize_Nest",     MatNestGetSize_Nest);CHKERRQ(ierr);
1438   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetISs_C",      "MatNestGetISs_Nest",      MatNestGetISs_Nest);CHKERRQ(ierr);
1439   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetLocalISs_C", "MatNestGetLocalISs_Nest", MatNestGetLocalISs_Nest);CHKERRQ(ierr);
1440   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "MatNestSetVecType_Nest",  MatNestSetVecType_Nest);CHKERRQ(ierr);
1441   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",  "MatNestSetSubMats_Nest",  MatNestSetSubMats_Nest);CHKERRQ(ierr);
1442 
1443   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
1444   PetscFunctionReturn(0);
1445 }
1446 EXTERN_C_END
1447