xref: /petsc/src/mat/impls/nest/matnest.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
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,"MatNestSetVecType_C",  "",0);CHKERRQ(ierr);
199   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",   "",0);CHKERRQ(ierr);
200   PetscFunctionReturn(0);
201 }
202 
203 #undef __FUNCT__
204 #define __FUNCT__ "MatAssemblyBegin_Nest"
205 static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
206 {
207   Mat_Nest       *vs = (Mat_Nest*)A->data;
208   PetscInt       i,j;
209   PetscErrorCode ierr;
210 
211   PetscFunctionBegin;
212   for (i=0; i<vs->nr; i++) {
213     for (j=0; j<vs->nc; j++) {
214       if (vs->m[i][j]) { ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr); }
215     }
216   }
217   PetscFunctionReturn(0);
218 }
219 
220 #undef __FUNCT__
221 #define __FUNCT__ "MatAssemblyEnd_Nest"
222 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
223 {
224   Mat_Nest       *vs = (Mat_Nest*)A->data;
225   PetscInt       i,j;
226   PetscErrorCode ierr;
227 
228   PetscFunctionBegin;
229   for (i=0; i<vs->nr; i++) {
230     for (j=0; j<vs->nc; j++) {
231       if (vs->m[i][j]) { ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr); }
232     }
233   }
234   PetscFunctionReturn(0);
235 }
236 
237 #undef __FUNCT__
238 #define __FUNCT__ "MatNestFindNonzeroSubMatRow"
239 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
240 {
241   PetscErrorCode ierr;
242   Mat_Nest       *vs = (Mat_Nest*)A->data;
243   PetscInt       j;
244   Mat            sub;
245 
246   PetscFunctionBegin;
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) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */
250   *B = sub;
251   PetscFunctionReturn(0);
252 }
253 
254 #undef __FUNCT__
255 #define __FUNCT__ "MatNestFindNonzeroSubMatCol"
256 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
257 {
258   PetscErrorCode ierr;
259   Mat_Nest       *vs = (Mat_Nest*)A->data;
260   PetscInt       i;
261   Mat            sub;
262 
263   PetscFunctionBegin;
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) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */
267   *B = sub;
268   PetscFunctionReturn(0);
269 }
270 
271 #undef __FUNCT__
272 #define __FUNCT__ "MatNestFindIS"
273 static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
274 {
275   PetscErrorCode ierr;
276   PetscInt       i;
277   PetscBool      flg;
278 
279   PetscFunctionBegin;
280   PetscValidPointer(list,3);
281   PetscValidHeaderSpecific(is,IS_CLASSID,4);
282   PetscValidIntPointer(found,5);
283   *found = -1;
284   for (i=0; i<n; i++) {
285     if (!list[i]) continue;
286     ierr = ISEqual(list[i],is,&flg);CHKERRQ(ierr);
287     if (flg) {
288       *found = i;
289       PetscFunctionReturn(0);
290     }
291   }
292   SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Could not find index set");
293   PetscFunctionReturn(0);
294 }
295 
296 #undef __FUNCT__
297 #define __FUNCT__ "MatNestGetRow"
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];
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   *B = PETSC_NULL;
307   ierr = PetscSNPrintf(keyname,sizeof keyname,"NestRow_%D",row);CHKERRQ(ierr);
308   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
309   if (*B) PetscFunctionReturn(0);
310 
311   ierr = MatCreateNest(((PetscObject)A)->comm,1,PETSC_NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
312   (*B)->assembled = A->assembled;
313   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
314   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "MatNestFindSubMat"
320 static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
321 {
322   Mat_Nest       *vs = (Mat_Nest*)A->data;
323   PetscErrorCode ierr;
324   PetscInt       row,col;
325   PetscBool      same,isFullCol;
326 
327   PetscFunctionBegin;
328   /* Check if full column space. This is a hack */
329   isFullCol = PETSC_FALSE;
330   ierr = PetscTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
331   if (same) {
332     PetscInt n,first,step,i,an,am,afirst,astep;
333     ierr = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
334     ierr = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
335     isFullCol = PETSC_TRUE;
336     for (i=0,an=0; i<vs->nc; i++) {
337       ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr);
338       ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr);
339       if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
340       an += am;
341     }
342     if (an != n) isFullCol = PETSC_FALSE;
343   }
344 
345   if (isFullCol) {
346     PetscInt row;
347     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
348     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
349   } else {
350     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
351     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
352     *B = vs->m[row][col];
353   }
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "MatGetSubMatrix_Nest"
359 static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
360 {
361   PetscErrorCode ierr;
362   Mat_Nest       *vs = (Mat_Nest*)A->data;
363   Mat            sub;
364 
365   PetscFunctionBegin;
366   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
367   switch (reuse) {
368   case MAT_INITIAL_MATRIX:
369     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
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   PetscFunctionReturn(0);
379 }
380 
381 #undef __FUNCT__
382 #define __FUNCT__ "MatGetLocalSubMatrix_Nest"
383 PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
384 {
385   PetscErrorCode ierr;
386   Mat_Nest       *vs = (Mat_Nest*)A->data;
387   Mat            sub;
388 
389   PetscFunctionBegin;
390   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
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) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
393   *B = sub;
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "MatRestoreLocalSubMatrix_Nest"
399 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
400 {
401   PetscErrorCode ierr;
402   Mat_Nest       *vs = (Mat_Nest*)A->data;
403   Mat            sub;
404 
405   PetscFunctionBegin;
406   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
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     ierr = MatDestroy(B);CHKERRQ(ierr);
411   }
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "MatGetDiagonal_Nest"
417 static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
418 {
419   Mat_Nest       *bA = (Mat_Nest*)A->data;
420   PetscInt       i;
421   PetscErrorCode ierr;
422 
423   PetscFunctionBegin;
424   for (i=0; i<bA->nr; i++) {
425     Vec bv;
426     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
427     if (bA->m[i][i]) {
428       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
429     } else {
430       ierr = VecSet(bv,1.0);CHKERRQ(ierr);
431     }
432     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
433   }
434   PetscFunctionReturn(0);
435 }
436 
437 #undef __FUNCT__
438 #define __FUNCT__ "MatDiagonalScale_Nest"
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;
444   PetscErrorCode ierr;
445 
446   PetscFunctionBegin;
447   ierr = PetscMalloc(bA->nc*sizeof(Vec),&br);CHKERRQ(ierr);
448   for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
449   for (i=0; i<bA->nr; i++) {
450     ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
451     for (j=0; j<bA->nc; j++) {
452       if (bA->m[i][j]) {
453         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
454       }
455     }
456     ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
457   }
458   for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
459   ierr = PetscFree(br);CHKERRQ(ierr);
460   PetscFunctionReturn(0);
461 }
462 
463 #undef __FUNCT__
464 #define __FUNCT__ "MatScale_Nest"
465 static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
466 {
467   Mat_Nest       *bA = (Mat_Nest*)A->data;
468   PetscInt       i,j;
469   PetscErrorCode ierr;
470 
471   PetscFunctionBegin;
472   for (i=0; i<bA->nr; i++) {
473     for (j=0; j<bA->nc; j++) {
474       if (bA->m[i][j]) {
475         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
476       }
477     }
478   }
479   PetscFunctionReturn(0);
480 }
481 
482 #undef __FUNCT__
483 #define __FUNCT__ "MatShift_Nest"
484 static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
485 {
486   Mat_Nest       *bA = (Mat_Nest*)A->data;
487   PetscInt       i;
488   PetscErrorCode ierr;
489 
490   PetscFunctionBegin;
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     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
494   }
495   PetscFunctionReturn(0);
496 }
497 
498 #undef __FUNCT__
499 #define __FUNCT__ "MatGetVecs_Nest"
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;
506   PetscErrorCode ierr;
507 
508   PetscFunctionBegin;
509   comm = ((PetscObject)A)->comm;
510   if (right) {
511     /* allocate R */
512     ierr = PetscMalloc( sizeof(Vec) * bA->nc, &R );CHKERRQ(ierr);
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           ierr = MatGetVecs(bA->m[i][j],&R[j],PETSC_NULL);CHKERRQ(ierr);
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     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
527     /* hand back control to the nest vector */
528     for (j=0; j<bA->nc; j++) {
529       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
530     }
531     ierr = PetscFree(R);CHKERRQ(ierr);
532   }
533 
534   if (left) {
535     /* allocate L */
536     ierr = PetscMalloc( sizeof(Vec) * bA->nr, &L );CHKERRQ(ierr);
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           ierr = MatGetVecs(bA->m[i][j],PETSC_NULL,&L[i]);CHKERRQ(ierr);
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     }
550 
551     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
552     for (i=0; i<bA->nr; i++) {
553       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
554     }
555 
556     ierr = PetscFree(L);CHKERRQ(ierr);
557   }
558   PetscFunctionReturn(0);
559 }
560 
561 #undef __FUNCT__
562 #define __FUNCT__ "MatView_Nest"
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;
568   PetscErrorCode ierr;
569 
570   PetscFunctionBegin;
571   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
572   if (isascii) {
573 
574     PetscViewerASCIIPrintf(viewer,"Matrix object: \n" );
575     PetscViewerASCIIPushTab( viewer );    /* push0 */
576     PetscViewerASCIIPrintf( viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc);
577 
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;
585 
586         if (!bA->m[i][j]) {
587           PetscViewerASCIIPrintf( viewer, "(%D,%D) : PETSC_NULL \n",i,j);
588           continue;
589         }
590         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
591         ierr = MatGetType( bA->m[i][j], &type );CHKERRQ(ierr);
592         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof name,"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
593         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof prefix,"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
594         ierr = PetscTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
595 
596         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
597 
598         if (isNest) {
599           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
600           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
601           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
602         }
603       }
604     }
605     PetscViewerASCIIPopTab(viewer);    /* pop0 */
606   }
607   PetscFunctionReturn(0);
608 }
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "MatZeroEntries_Nest"
612 static PetscErrorCode MatZeroEntries_Nest(Mat A)
613 {
614   Mat_Nest       *bA = (Mat_Nest*)A->data;
615   PetscInt       i,j;
616   PetscErrorCode ierr;
617 
618   PetscFunctionBegin;
619   for (i=0; i<bA->nr; i++) {
620     for (j=0; j<bA->nc; j++) {
621       if (!bA->m[i][j]) continue;
622       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
623     }
624   }
625   PetscFunctionReturn(0);
626 }
627 
628 #undef __FUNCT__
629 #define __FUNCT__ "MatDuplicate_Nest"
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;
635   PetscErrorCode ierr;
636 
637   PetscFunctionBegin;
638   ierr = PetscMalloc(nr*nc*sizeof(Mat),&b);CHKERRQ(ierr);
639   for (i=0; i<nr; i++) {
640     for (j=0; j<nc; j++) {
641       if (bA->m[i][j]) {
642         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
643       } else {
644         b[i*nc+j] = PETSC_NULL;
645       }
646     }
647   }
648   ierr = MatCreateNest(((PetscObject)A)->comm,nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
649   /* Give the new MatNest exclusive ownership */
650   for (i=0; i<nr*nc; i++) {
651     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
652   }
653   ierr = PetscFree(b);CHKERRQ(ierr);
654 
655   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
656   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
657   PetscFunctionReturn(0);
658 }
659 
660 /* nest api */
661 EXTERN_C_BEGIN
662 #undef __FUNCT__
663 #define __FUNCT__ "MatNestGetSubMat_Nest"
664 PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
665 {
666   Mat_Nest *bA = (Mat_Nest*)A->data;
667   PetscFunctionBegin;
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   PetscFunctionReturn(0);
672 }
673 EXTERN_C_END
674 
675 #undef __FUNCT__
676 #define __FUNCT__ "MatNestGetSubMat"
677 /*@C
678  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
679 
680  Not collective
681 
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
686 
687  Output Parameter:
688 .   sub - matrix at index idxm,jdxm within the nest matrix
689 
690  Level: developer
691 
692 .seealso: MatNestGetSize(), MatNestGetSubMats()
693 @*/
694 PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
695 {
696   PetscErrorCode ierr;
697 
698   PetscFunctionBegin;
699   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
700   PetscFunctionReturn(0);
701 }
702 
703 EXTERN_C_BEGIN
704 #undef __FUNCT__
705 #define __FUNCT__ "MatNestSetSubMat_Nest"
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;
710   PetscErrorCode ierr;
711 
712   PetscFunctionBegin;
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   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
716   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
717   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
718   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
719   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
720   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
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   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
724   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
725   bA->m[idxm][jdxm] = mat;
726   PetscFunctionReturn(0);
727 }
728 EXTERN_C_END
729 
730 #undef __FUNCT__
731 #define __FUNCT__ "MatNestSetSubMat"
732 /*@C
733  MatNestSetSubMat - Set a single submatrix in the nest matrix.
734 
735  Logically collective on the submatrix communicator
736 
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
742 
743  Notes:
744  The new submatrix must have the same size and communicator as that block of the nest.
745 
746  This increments the reference count of the submatrix.
747 
748  Level: developer
749 
750 .seealso: MatNestSetSubMats(), MatNestGetSubMat()
751 @*/
752 PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
753 {
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
758   PetscFunctionReturn(0);
759 }
760 
761 EXTERN_C_BEGIN
762 #undef __FUNCT__
763 #define __FUNCT__ "MatNestGetSubMats_Nest"
764 PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
765 {
766   Mat_Nest *bA = (Mat_Nest*)A->data;
767   PetscFunctionBegin;
768   if (M)   { *M   = bA->nr; }
769   if (N)   { *N   = bA->nc; }
770   if (mat) { *mat = bA->m;  }
771   PetscFunctionReturn(0);
772 }
773 EXTERN_C_END
774 
775 #undef __FUNCT__
776 #define __FUNCT__ "MatNestGetSubMats"
777 /*@C
778  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
779 
780  Not collective
781 
782  Input Parameters:
783 .   A  - nest matrix
784 
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
789 
790  Notes:
791 
792  The user should not free the array mat.
793 
794  Level: developer
795 
796 .seealso: MatNestGetSize(), MatNestGetSubMat()
797 @*/
798 PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
799 {
800   PetscErrorCode ierr;
801 
802   PetscFunctionBegin;
803   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
804   PetscFunctionReturn(0);
805 }
806 
807 EXTERN_C_BEGIN
808 #undef __FUNCT__
809 #define __FUNCT__ "MatNestGetSize_Nest"
810 PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
811 {
812   Mat_Nest  *bA = (Mat_Nest*)A->data;
813 
814   PetscFunctionBegin;
815   if (M) { *M  = bA->nr; }
816   if (N) { *N  = bA->nc; }
817   PetscFunctionReturn(0);
818 }
819 EXTERN_C_END
820 
821 #undef __FUNCT__
822 #define __FUNCT__ "MatNestGetSize"
823 /*@C
824  MatNestGetSize - Returns the size of the nest matrix.
825 
826  Not collective
827 
828  Input Parameters:
829 .   A  - nest matrix
830 
831  Output Parameter:
832 +   M - number of rows in the nested mat
833 -   N - number of cols in the nested mat
834 
835  Notes:
836 
837  Level: developer
838 
839 .seealso: MatNestGetSubMat(), MatNestGetSubMats()
840 @*/
841 PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
842 {
843   PetscErrorCode ierr;
844 
845   PetscFunctionBegin;
846   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
847   PetscFunctionReturn(0);
848 }
849 
850 EXTERN_C_BEGIN
851 #undef __FUNCT__
852 #define __FUNCT__ "MatNestSetVecType_Nest"
853 PetscErrorCode  MatNestSetVecType_Nest(Mat A,const VecType vtype)
854 {
855   PetscErrorCode ierr;
856   PetscBool      flg;
857 
858   PetscFunctionBegin;
859   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
860   /* In reality, this only distinguishes VECNEST and "other" */
861   A->ops->getvecs       = flg ? MatGetVecs_Nest       : 0;
862  PetscFunctionReturn(0);
863 }
864 EXTERN_C_END
865 
866 #undef __FUNCT__
867 #define __FUNCT__ "MatNestSetVecType"
868 /*@C
869  MatNestSetVecType - Sets the type of Vec returned by MatGetVecs()
870 
871  Not collective
872 
873  Input Parameters:
874 +  A  - nest matrix
875 -  vtype - type to use for creating vectors
876 
877  Notes:
878 
879  Level: developer
880 
881 .seealso: MatGetVecs()
882 @*/
883 PetscErrorCode  MatNestSetVecType(Mat A,const VecType vtype)
884 {
885   PetscErrorCode ierr;
886 
887   PetscFunctionBegin;
888   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,const VecType),(A,vtype));CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 EXTERN_C_BEGIN
893 #undef __FUNCT__
894 #define __FUNCT__ "MatNestSetSubMats_Nest"
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;
899   PetscErrorCode ierr;
900 
901   PetscFunctionBegin;
902   s->nr = nr;
903   s->nc = nc;
904 
905   /* Create space for submatrices */
906   ierr = PetscMalloc(sizeof(Mat*)*nr,&s->m);CHKERRQ(ierr);
907   for (i=0; i<nr; i++) {
908     ierr = PetscMalloc(sizeof(Mat)*nc,&s->m[i]);CHKERRQ(ierr);
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         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
915       }
916     }
917   }
918 
919   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
920 
921   ierr = PetscMalloc(sizeof(PetscInt)*nr,&s->row_len);CHKERRQ(ierr);
922   ierr = PetscMalloc(sizeof(PetscInt)*nc,&s->col_len);CHKERRQ(ierr);
923   for (i=0; i<nr; i++) s->row_len[i]=-1;
924   for (j=0; j<nc; j++) s->col_len[j]=-1;
925 
926   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
927 
928   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
929   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
930   ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr);
931   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
932   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
933   ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr);
934 
935   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
936   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
937 
938   ierr = PetscMalloc2(nr,Vec,&s->left,nc,Vec,&s->right);CHKERRQ(ierr);
939   ierr = PetscMemzero(s->left,nr*sizeof(Vec));CHKERRQ(ierr);
940   ierr = PetscMemzero(s->right,nc*sizeof(Vec));CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 EXTERN_C_END
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "MatNestSetSubMats"
947 /*@
948    MatNestSetSubMats - Sets the nested submatrices
949 
950    Collective on Mat
951 
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
959 
960    Level: advanced
961 
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 {
966   PetscErrorCode ierr;
967   PetscInt i;
968 
969   PetscFunctionBegin;
970   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
971   if (nr < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
972   if (nr && is_row) {
973     PetscValidPointer(is_row,3);
974     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
975   }
976   if (nc < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
977   if (nc && is_col) {
978     PetscValidPointer(is_col,5);
979     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
980   }
981   if (nr*nc) PetscValidPointer(a,6);
982   ierr = PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));CHKERRQ(ierr);
983   PetscFunctionReturn(0);
984 }
985 
986 #undef __FUNCT__
987 #define __FUNCT__ "MatNestCreateAggregateL2G_Private"
988 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog,ISLocalToGlobalMapping *ltogb)
989 {
990   PetscErrorCode ierr;
991   PetscBool flg;
992   PetscInt i,j,m,mi,*ix;
993 
994   PetscFunctionBegin;
995   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
996     if (islocal[i]) {
997       ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
998       flg = PETSC_TRUE;       /* We found a non-trivial entry */
999     } else {
1000       ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
1001     }
1002     m += mi;
1003   }
1004   if (flg) {
1005     ierr = PetscMalloc(m*sizeof(*ix),&ix);CHKERRQ(ierr);
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;
1013 
1014       if (sizeof (*x) != sizeof(PetscScalar)) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support when scalars smaller than integers");
1015       if (colflg) {
1016         ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1017       } else {
1018         ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
1019       }
1020       if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&smap,PETSC_NULL);CHKERRQ(ierr);}
1021       if (islocal[i]) {
1022         ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
1023       } else {
1024         ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
1025       }
1026       for (j=0; j<mi; j++) ix[m+j] = j;
1027       if (smap) {ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);}
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       ierr = VecCreateSeq(PETSC_COMM_SELF,mi,&lvec);CHKERRQ(ierr);
1034       ierr = VecCreateMPI(((PetscObject)isglobal[i])->comm,mi,PETSC_DECIDE,&gvec);CHKERRQ(ierr);
1035       ierr = ISCreateGeneral(((PetscObject)isglobal[i])->comm,mi,ix+m,PETSC_COPY_VALUES,&isreq);CHKERRQ(ierr);
1036       ierr = VecScatterCreate(gvec,isreq,lvec,PETSC_NULL,&scat);CHKERRQ(ierr);
1037       ierr = VecGetArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr);
1038       for (j=0; j<mi; j++) x[j].integer = ix[m+j];
1039       ierr = VecRestoreArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr);
1040       ierr = VecScatterBegin(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1041       ierr = VecScatterEnd(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1042       ierr = VecGetArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr);
1043       for (j=0; j<mi; j++) ix[m+j] = x[j].integer;
1044       ierr = VecRestoreArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr);
1045       ierr = VecDestroy(&lvec);CHKERRQ(ierr);
1046       ierr = VecDestroy(&gvec);CHKERRQ(ierr);
1047       ierr = ISDestroy(&isreq);CHKERRQ(ierr);
1048       ierr = VecScatterDestroy(&scat);CHKERRQ(ierr);
1049       m += mi;
1050     }
1051     ierr = ISLocalToGlobalMappingCreate(((PetscObject)A)->comm,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1052     *ltogb = PETSC_NULL;
1053   } else {
1054     *ltog = PETSC_NULL;
1055     *ltogb = PETSC_NULL;
1056   }
1057   PetscFunctionReturn(0);
1058 }
1059 
1060 
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,)
1069 
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) )
1072 
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 )
1077 
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 */
1081 #undef __FUNCT__
1082 #define __FUNCT__ "MatSetUp_NestIS_Private"
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;
1087   PetscErrorCode ierr;
1088   Mat            sub;
1089 
1090   PetscFunctionBegin;
1091   ierr = PetscMalloc(sizeof(IS)*nr,&vs->isglobal.row);CHKERRQ(ierr);
1092   ierr = PetscMalloc(sizeof(IS)*nc,&vs->isglobal.col);CHKERRQ(ierr);
1093   if (is_row) { /* valid IS is passed in */
1094     /* refs on is[] are incremeneted */
1095     for (i=0; i<vs->nr; i++) {
1096       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
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       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1103       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
1104       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
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     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
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       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1116       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
1117       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1118       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1119       ierr = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
1120       offset += n;
1121     }
1122   }
1123 
1124   if (is_col) { /* valid IS is passed in */
1125     /* refs on is[] are incremeneted */
1126     for (j=0; j<vs->nc; j++) {
1127       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
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       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1135       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
1136       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
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     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
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       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1148       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
1149       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1150       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1151       ierr = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
1152       offset += n;
1153     }
1154   }
1155 
1156   /* Set up the local ISs */
1157   ierr = PetscMalloc(vs->nr*sizeof(IS),&vs->islocal.row);CHKERRQ(ierr);
1158   ierr = PetscMalloc(vs->nc*sizeof(IS),&vs->islocal.col);CHKERRQ(ierr);
1159   for (i=0,offset=0; i<vs->nr; i++) {
1160     IS                     isloc;
1161     ISLocalToGlobalMapping rmap = PETSC_NULL;
1162     PetscInt               nlocal,bs;
1163     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1164     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,PETSC_NULL);CHKERRQ(ierr);}
1165     if (rmap) {
1166       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1167       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1168       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1169       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
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     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
1182     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,PETSC_NULL,&cmap);CHKERRQ(ierr);}
1183     if (cmap) {
1184       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1185       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1186       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1187       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1188     } else {
1189       nlocal = 0;
1190       isloc  = PETSC_NULL;
1191     }
1192     vs->islocal.col[i] = isloc;
1193     offset += nlocal;
1194   }
1195 
1196   /* Set up the aggregate ISLocalToGlobalMapping */
1197   {
1198     ISLocalToGlobalMapping rmap,rmapb,cmap,cmapb;
1199     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap,&rmapb);CHKERRQ(ierr);
1200     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap,&cmapb);CHKERRQ(ierr);
1201     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
1202     if (rmapb && cmapb) {ierr = MatSetLocalToGlobalMappingBlock(A,rmapb,cmapb);CHKERRQ(ierr);}
1203     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
1204     ierr = ISLocalToGlobalMappingDestroy(&rmapb);CHKERRQ(ierr);
1205     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
1206     ierr = ISLocalToGlobalMappingDestroy(&cmapb);CHKERRQ(ierr);
1207   }
1208 
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       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
1216       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
1217       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
1218       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
1219       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
1220       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
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
1226 
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) PetscFunctionReturn(0);
1231     }
1232   }
1233   A->assembled = PETSC_TRUE;
1234   PetscFunctionReturn(0);
1235 }
1236 
1237 #undef __FUNCT__
1238 #define __FUNCT__ "MatCreateNest"
1239 /*@
1240    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1241 
1242    Collective on Mat
1243 
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
1251 
1252    Output Parameter:
1253 .  B - new matrix
1254 
1255    Level: advanced
1256 
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;
1262   PetscErrorCode ierr;
1263 
1264   PetscFunctionBegin;
1265   *B = 0;
1266   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1267   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
1268   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1269   *B = A;
1270   PetscFunctionReturn(0);
1271 }
1272 
1273 /*MC
1274   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1275 
1276   Level: intermediate
1277 
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()
1282 
1283 .seealso: MatCreate(), MatType, MatCreateNest()
1284 M*/
1285 EXTERN_C_BEGIN
1286 #undef __FUNCT__
1287 #define __FUNCT__ "MatCreate_Nest"
1288 PetscErrorCode MatCreate_Nest(Mat A)
1289 {
1290   Mat_Nest       *s;
1291   PetscErrorCode ierr;
1292 
1293   PetscFunctionBegin;
1294   ierr = PetscNewLog(A,Mat_Nest,&s);CHKERRQ(ierr);
1295   A->data         = (void*)s;
1296   s->nr = s->nc   = -1;
1297   s->m            = PETSC_NULL;
1298 
1299   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
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;
1318 
1319   A->spptr        = 0;
1320   A->same_nonzero = PETSC_FALSE;
1321   A->assembled    = PETSC_FALSE;
1322 
1323   /* expose Nest api's */
1324   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "MatNestGetSubMat_Nest",   MatNestGetSubMat_Nest);CHKERRQ(ierr);
1325   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C",   "MatNestSetSubMat_Nest",   MatNestSetSubMat_Nest);CHKERRQ(ierr);
1326   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "MatNestGetSubMats_Nest",  MatNestGetSubMats_Nest);CHKERRQ(ierr);
1327   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "MatNestGetSize_Nest",     MatNestGetSize_Nest);CHKERRQ(ierr);
1328   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "MatNestSetVecType_Nest",  MatNestSetVecType_Nest);CHKERRQ(ierr);
1329   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",  "MatNestSetSubMats_Nest",  MatNestSetSubMats_Nest);CHKERRQ(ierr);
1330 
1331   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
1332   PetscFunctionReturn(0);
1333 }
1334 EXTERN_C_END
1335