xref: /petsc/src/mat/impls/nest/matnest.c (revision 8188e55adec81f61b4511e7984c970fbc87f0a5c)
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 #undef __FUNCT__
36 #define __FUNCT__ "PETSc_MatNest_CheckMatVecCompatibility2"
37 PETSC_UNUSED
38 static PetscErrorCode PETSc_MatNest_CheckMatVecCompatibility2(Mat A,Vec x,Vec y)
39 {
40   PetscBool      isANest, isxNest, isyNest;
41   PetscErrorCode ierr;
42 
43   PetscFunctionBegin;
44   isANest = isxNest = isyNest = PETSC_FALSE;
45   ierr = PetscTypeCompare( (PetscObject)A, MATNEST, &isANest );CHKERRQ(ierr);
46   ierr = PetscTypeCompare( (PetscObject)x, VECNEST, &isxNest );CHKERRQ(ierr);
47   ierr = PetscTypeCompare( (PetscObject)y, VECNEST, &isyNest );CHKERRQ(ierr);
48 
49   if (isANest && isxNest && isyNest) {
50     PetscFunctionReturn(0);
51   } else {
52     SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_SUP, "Operation only valid for Mat(Nest)-Vec(Nest) combinations");
53     PetscFunctionReturn(0);
54   }
55   PetscFunctionReturn(0);
56 }
57 
58 /*
59  This function is called every time we insert a sub matrix the Nest.
60  It ensures that every Nest along row r, and col c has the same dimensions
61  as the submat being inserted.
62 */
63 #undef __FUNCT__
64 #define __FUNCT__ "PETSc_MatNest_CheckConsistency"
65 PETSC_UNUSED
66 static PetscErrorCode PETSc_MatNest_CheckConsistency(Mat A,Mat submat,PetscInt r,PetscInt c)
67 {
68   Mat_Nest       *b = (Mat_Nest*)A->data;
69   PetscInt       i,j;
70   PetscInt       nr,nc;
71   PetscInt       sM,sN,M,N;
72   Mat            mat;
73   PetscErrorCode ierr;
74 
75   PetscFunctionBegin;
76   nr = b->nr;
77   nc = b->nc;
78   ierr = MatGetSize(submat,&sM,&sN);CHKERRQ(ierr);
79   for (i=0; i<nr; i++) {
80     mat = b->m[i][c];
81     if (mat) {
82       ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
83       /* Check columns match */
84       if (sN != N) {
85         SETERRQ3(((PetscObject)A)->comm,PETSC_ERR_SUP,"Inserted incompatible submatrix into Nest at (%D,%D). Submatrix must have %D rows",r,c,N );
86       }
87     }
88   }
89 
90   for (j=0; j<nc; j++) {
91     mat = b->m[r][j];
92     if (mat) {
93       ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
94       /* Check rows match */
95       if (sM != M) {
96         SETERRQ3(((PetscObject)A)->comm,PETSC_ERR_SUP,"Inserted incompatible submatrix into Nest at (%D,%D). Submatrix must have %D cols",r,c,M );
97       }
98     }
99   }
100   PetscFunctionReturn(0);
101 }
102 
103 /*
104  Checks if the row/col's contain a complete set of IS's.
105  Once they are filled, the offsets are computed. This saves having to update
106  the index set entries each time we insert something new.
107  */
108 #undef __FUNCT__
109 #define __FUNCT__ "PETSc_MatNest_UpdateStructure"
110 PETSC_UNUSED
111 static PetscErrorCode PETSc_MatNest_UpdateStructure(Mat A,PetscInt ridx,PetscInt cidx)
112 {
113   Mat_Nest       *b = (Mat_Nest*)A->data;
114   PetscInt       m,n,i,j;
115   PetscBool      fullrow,fullcol;
116   PetscErrorCode ierr;
117 
118   PetscFunctionBegin;
119   ierr = MatGetLocalSize(b->m[ridx][cidx],&m,&n);CHKERRQ(ierr);
120   b->row_len[ridx] = m;
121   b->col_len[cidx] = n;
122 
123   fullrow = PETSC_TRUE;
124   for (i=0; i<b->nr; i++) {
125     if (b->row_len[i]==-1) { fullrow = PETSC_FALSE; break; }
126   }
127   if ( (fullrow) && (!b->isglobal.row[0]) ){
128     PetscInt cnt = 0;
129     for (i=0; i<b->nr; i++) {
130       ierr = ISCreateStride(PETSC_COMM_SELF,b->row_len[i],cnt,1,&b->isglobal.row[i]);CHKERRQ(ierr);
131       cnt = cnt + b->row_len[i];
132     }
133   }
134 
135   fullcol = PETSC_TRUE;
136   for (j=0; j<b->nc; j++) {
137     if (b->col_len[j]==-1) { fullcol = PETSC_FALSE; break; }
138   }
139   if( (fullcol) && (!b->isglobal.col[0]) ){
140     PetscInt cnt = 0;
141     for (j=0; j<b->nc; j++) {
142       ierr = ISCreateStride(PETSC_COMM_SELF,b->col_len[j],cnt,1,&b->isglobal.col[j]);CHKERRQ(ierr);
143       cnt = cnt + b->col_len[j];
144     }
145   }
146   PetscFunctionReturn(0);
147 }
148 
149 /* operations */
150 #undef __FUNCT__
151 #define __FUNCT__ "MatMult_Nest"
152 static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
153 {
154   Mat_Nest       *bA = (Mat_Nest*)A->data;
155   Vec            *bx = bA->right,*by = bA->left;
156   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
157   PetscErrorCode ierr;
158 
159   PetscFunctionBegin;
160   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
161   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
162   for (i=0; i<nr; i++) {
163     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
164     for (j=0; j<nc; j++) {
165       if (!bA->m[i][j]) continue;
166       /* y[i] <- y[i] + A[i][j] * x[j] */
167       ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr);
168     }
169   }
170   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
171   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
172   PetscFunctionReturn(0);
173 }
174 
175 #undef __FUNCT__
176 #define __FUNCT__ "MatMultTranspose_Nest"
177 static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
178 {
179   Mat_Nest       *bA = (Mat_Nest*)A->data;
180   Vec            *bx = bA->left,*by = bA->right;
181   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
182   PetscErrorCode ierr;
183 
184   PetscFunctionBegin;
185   if (A->symmetric) {
186     ierr = MatMult_Nest(A,x,y);CHKERRQ(ierr);
187     PetscFunctionReturn(0);
188   }
189   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
190   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
191   for (i=0; i<nr; i++) {
192     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
193     for (j=0; j<nc; j++) {
194       if (!bA->m[j][i]) continue;
195       /* y[i] <- y[i] + A^T[i][j] * x[j], so we swap i,j in mat[][] */
196       ierr = MatMultTransposeAdd(bA->m[j][i],bx[j],by[i],by[i]);CHKERRQ(ierr);
197     }
198   }
199   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
200   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
201   PetscFunctionReturn(0);
202 }
203 
204 #undef __FUNCT__
205 #define __FUNCT__ "MatNestDestroyISList"
206 static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
207 {
208   PetscErrorCode ierr;
209   IS             *lst = *list;
210   PetscInt       i;
211 
212   PetscFunctionBegin;
213   if (!lst) PetscFunctionReturn(0);
214   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
215   ierr = PetscFree(lst);CHKERRQ(ierr);
216   *list = PETSC_NULL;
217   PetscFunctionReturn(0);
218 }
219 
220 #undef __FUNCT__
221 #define __FUNCT__ "MatDestroy_Nest"
222 static PetscErrorCode MatDestroy_Nest(Mat A)
223 {
224   Mat_Nest       *vs = (Mat_Nest*)A->data;
225   PetscInt       i,j;
226   PetscErrorCode ierr;
227 
228   PetscFunctionBegin;
229   /* release the matrices and the place holders */
230   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
231   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
232   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
233   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
234 
235   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
236   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
237 
238   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
239 
240   /* release the matrices and the place holders */
241   if (vs->m) {
242     for (i=0; i<vs->nr; i++) {
243       for (j=0; j<vs->nc; j++) {
244         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
245       }
246       ierr = PetscFree( vs->m[i] );CHKERRQ(ierr);
247     }
248     ierr = PetscFree(vs->m);CHKERRQ(ierr);
249   }
250   ierr = PetscFree(A->data);CHKERRQ(ierr);
251 
252   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "",0);CHKERRQ(ierr);
253   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "",0);CHKERRQ(ierr);
254   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "",0);CHKERRQ(ierr);
255   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "",0);CHKERRQ(ierr);
256   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",   "",0);CHKERRQ(ierr);
257   PetscFunctionReturn(0);
258 }
259 
260 #undef __FUNCT__
261 #define __FUNCT__ "MatAssemblyBegin_Nest"
262 static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
263 {
264   Mat_Nest       *vs = (Mat_Nest*)A->data;
265   PetscInt       i,j;
266   PetscErrorCode ierr;
267 
268   PetscFunctionBegin;
269   for (i=0; i<vs->nr; i++) {
270     for (j=0; j<vs->nc; j++) {
271       if (vs->m[i][j]) { ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr); }
272     }
273   }
274   PetscFunctionReturn(0);
275 }
276 
277 #undef __FUNCT__
278 #define __FUNCT__ "MatAssemblyEnd_Nest"
279 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
280 {
281   Mat_Nest       *vs = (Mat_Nest*)A->data;
282   PetscInt       i,j;
283   PetscErrorCode ierr;
284 
285   PetscFunctionBegin;
286   for (i=0; i<vs->nr; i++) {
287     for (j=0; j<vs->nc; j++) {
288       if (vs->m[i][j]) { ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr); }
289     }
290   }
291   PetscFunctionReturn(0);
292 }
293 
294 #undef __FUNCT__
295 #define __FUNCT__ "MatNestFindNonzeroSubMatRow"
296 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
297 {
298   PetscErrorCode ierr;
299   Mat_Nest       *vs = (Mat_Nest*)A->data;
300   PetscInt       j;
301   Mat            sub;
302 
303   PetscFunctionBegin;
304   sub = (row < vs->nc) ? vs->m[row][row] : PETSC_NULL; /* Prefer to find on the diagonal */
305   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
306   if (sub) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */
307   *B = sub;
308   PetscFunctionReturn(0);
309 }
310 
311 #undef __FUNCT__
312 #define __FUNCT__ "MatNestFindNonzeroSubMatCol"
313 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
314 {
315   PetscErrorCode ierr;
316   Mat_Nest       *vs = (Mat_Nest*)A->data;
317   PetscInt       i;
318   Mat            sub;
319 
320   PetscFunctionBegin;
321   sub = (col < vs->nr) ? vs->m[col][col] : PETSC_NULL; /* Prefer to find on the diagonal */
322   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
323   if (sub) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */
324   *B = sub;
325   PetscFunctionReturn(0);
326 }
327 
328 #undef __FUNCT__
329 #define __FUNCT__ "MatNestFindIS"
330 static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
331 {
332   PetscErrorCode ierr;
333   PetscInt       i;
334   PetscBool      flg;
335 
336   PetscFunctionBegin;
337   PetscValidPointer(list,3);
338   PetscValidHeaderSpecific(is,IS_CLASSID,4);
339   PetscValidIntPointer(found,5);
340   *found = -1;
341   for (i=0; i<n; i++) {
342     if (!list[i]) continue;
343     ierr = ISEqual(list[i],is,&flg);CHKERRQ(ierr);
344     if (flg) {
345       *found = i;
346       PetscFunctionReturn(0);
347     }
348   }
349   SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Could not find index set");
350   PetscFunctionReturn(0);
351 }
352 
353 #undef __FUNCT__
354 #define __FUNCT__ "MatNestGetRow"
355 /* Get a block row as a new MatNest */
356 static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
357 {
358   Mat_Nest       *vs = (Mat_Nest*)A->data;
359   Mat            C;
360   char           keyname[256];
361   PetscErrorCode ierr;
362 
363   PetscFunctionBegin;
364   *B = PETSC_NULL;
365   ierr = PetscSNPrintf(keyname,sizeof keyname,"NestRow_%D",row);CHKERRQ(ierr);
366   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
367   if (*B) PetscFunctionReturn(0);
368 
369   ierr = MatCreateNest(((PetscObject)A)->comm,1,PETSC_NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
370   (*B)->assembled = A->assembled;
371   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
372   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
373   PetscFunctionReturn(0);
374 }
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "MatNestFindSubMat"
378 static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
379 {
380   Mat_Nest       *vs = (Mat_Nest*)A->data;
381   PetscErrorCode ierr;
382   PetscInt       row,col,i;
383   IS             *iscopy;
384   Mat            *matcopy;
385   PetscBool      same,isFullCol;
386 
387   PetscFunctionBegin;
388   /* Check if full column space. This is a hack */
389   isFullCol = PETSC_FALSE;
390   ierr = PetscTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
391   if (same) {
392     PetscInt n,first,step;
393     ierr = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
394     ierr = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
395     if (A->cmap->n == n && A->cmap->rstart == first && step == 1) isFullCol = PETSC_TRUE;
396   }
397 
398   if (isFullCol) {
399     PetscInt row;
400     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
401     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
402   } else {
403     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
404     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
405     *B = vs->m[row][col];
406   }
407   PetscFunctionReturn(0);
408 }
409 
410 #undef __FUNCT__
411 #define __FUNCT__ "MatGetSubMatrix_Nest"
412 static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
413 {
414   PetscErrorCode ierr;
415   Mat_Nest       *vs = (Mat_Nest*)A->data;
416   Mat            sub;
417 
418   PetscFunctionBegin;
419   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
420   switch (reuse) {
421   case MAT_INITIAL_MATRIX:
422     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
423     *B = sub;
424     break;
425   case MAT_REUSE_MATRIX:
426     if (sub != *B) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
427     break;
428   case MAT_IGNORE_MATRIX:       /* Nothing to do */
429     break;
430   }
431   PetscFunctionReturn(0);
432 }
433 
434 #undef __FUNCT__
435 #define __FUNCT__ "MatGetLocalSubMatrix_Nest"
436 PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
437 {
438   PetscErrorCode ierr;
439   Mat_Nest       *vs = (Mat_Nest*)A->data;
440   Mat            sub;
441 
442   PetscFunctionBegin;
443   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
444   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
445   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
446   *B = sub;
447   PetscFunctionReturn(0);
448 }
449 
450 #undef __FUNCT__
451 #define __FUNCT__ "MatRestoreLocalSubMatrix_Nest"
452 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
453 {
454   PetscErrorCode ierr;
455   Mat_Nest       *vs = (Mat_Nest*)A->data;
456   Mat            sub;
457 
458   PetscFunctionBegin;
459   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
460   if (*B != sub) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
461   if (sub) {
462     if (((PetscObject)sub)->refct <= 1) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
463     ierr = MatDestroy(B);CHKERRQ(ierr);
464   }
465   PetscFunctionReturn(0);
466 }
467 
468 #undef __FUNCT__
469 #define __FUNCT__ "MatGetDiagonal_Nest"
470 static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
471 {
472   Mat_Nest       *bA = (Mat_Nest*)A->data;
473   Vec            *bdiag;
474   PetscInt       i;
475   PetscErrorCode ierr;
476 
477   PetscFunctionBegin;
478   /*  ierr = MatGetVecs_Nest(A,&diag,PETSC_NULL);CHKERRQ(ierr); */
479   /*  ierr = VecNestGetSubVecs(diag,PETSC_NULL,&bdiag);CHKERRQ(ierr); */
480   ierr = VecNestGetSubVecs(v,PETSC_NULL,&bdiag);CHKERRQ(ierr);
481   for (i=0; i<bA->nr; i++) {
482     if (bA->m[i][i]) {
483       ierr = MatGetDiagonal(bA->m[i][i],bdiag[i]);CHKERRQ(ierr);
484     } else {
485       ierr = VecSet(bdiag[i],1.0);CHKERRQ(ierr);
486     }
487   }
488   PetscFunctionReturn(0);
489 }
490 
491 #undef __FUNCT__
492 #define __FUNCT__ "MatGetDiagonal_Nest2"
493 static PetscErrorCode MatGetDiagonal_Nest2(Mat A,Vec v)
494 {
495   Mat_Nest       *bA = (Mat_Nest*)A->data;
496   Vec            diag,*bdiag;
497   VecScatter     *vscat;
498   PetscInt       i;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   ierr = MatGetVecs_Nest(A,&diag,PETSC_NULL);CHKERRQ(ierr);
503   ierr = MatGetDiagonal_Nest(A,diag);CHKERRQ(ierr);
504 
505   /* scatter diag into v */
506   ierr = VecNestGetSubVecs(diag,PETSC_NULL,&bdiag);CHKERRQ(ierr);
507   ierr = PetscMalloc( sizeof(VecScatter) * bA->nr, &vscat );CHKERRQ(ierr);
508   for (i=0; i<bA->nr; i++) {
509     ierr = VecScatterCreate(v,bA->isglobal.row[i], bdiag[i],PETSC_NULL,&vscat[i]);CHKERRQ(ierr);
510     ierr = VecScatterBegin(vscat[i],bdiag[i],v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
511   }
512   for (i=0; i<bA->nr; i++) {
513     ierr = VecScatterEnd(vscat[i],bdiag[i],v,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
514   }
515   for (i=0; i<bA->nr; i++) {
516     ierr = VecScatterDestroy(&vscat[i]);CHKERRQ(ierr);
517   }
518   ierr = PetscFree(vscat);CHKERRQ(ierr);
519   ierr = VecDestroy(&diag);CHKERRQ(ierr);
520   PetscFunctionReturn(0);
521 }
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "MatDiagonalScale_Nest"
525 static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
526 {
527   Mat_Nest       *bA = (Mat_Nest*)A->data;
528   Vec            *bl,*br;
529   PetscInt       i,j;
530   PetscErrorCode ierr;
531 
532   PetscFunctionBegin;
533   ierr = VecNestGetSubVecs(l,PETSC_NULL,&bl);CHKERRQ(ierr);
534   ierr = VecNestGetSubVecs(r,PETSC_NULL,&br);CHKERRQ(ierr);
535   for (i=0; i<bA->nr; i++) {
536     for (j=0; j<bA->nc; j++) {
537       if (bA->m[i][j]) {
538         ierr = MatDiagonalScale(bA->m[i][j],bl[i],br[j]);CHKERRQ(ierr);
539       }
540     }
541   }
542   PetscFunctionReturn(0);
543 }
544 
545 #undef __FUNCT__
546 #define __FUNCT__ "MatDiagonalScale_Nest2"
547 static PetscErrorCode MatDiagonalScale_Nest2(Mat A,Vec l,Vec r)
548 {
549   Mat_Nest       *bA = (Mat_Nest*)A->data;
550   Vec            bl,br,*ble,*bre;
551   VecScatter     *vscatl,*vscatr;
552   PetscInt       i;
553   PetscErrorCode ierr;
554 
555   PetscFunctionBegin;
556   /* scatter l,r into bl,br */
557   ierr = MatGetVecs_Nest(A,&bl,&br);CHKERRQ(ierr);
558   ierr = VecNestGetSubVecs(bl,PETSC_NULL,&ble);CHKERRQ(ierr);
559   ierr = VecNestGetSubVecs(br,PETSC_NULL,&bre);CHKERRQ(ierr);
560 
561   /* row */
562   ierr = PetscMalloc( sizeof(VecScatter) * bA->nr, &vscatl );CHKERRQ(ierr);
563   for (i=0; i<bA->nr; i++) {
564     ierr = VecScatterCreate(l,bA->isglobal.row[i], ble[i],PETSC_NULL,&vscatl[i]);CHKERRQ(ierr);
565     ierr = VecScatterBegin(vscatl[i],l,ble[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
566   }
567   for (i=0; i<bA->nr; i++) {
568     ierr = VecScatterEnd(vscatl[i],l,ble[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
569   }
570   /* col */
571   ierr = PetscMalloc( sizeof(VecScatter) * bA->nc, &vscatr );CHKERRQ(ierr);
572   for (i=0; i<bA->nc; i++) {
573     ierr = VecScatterCreate(r,bA->isglobal.col[i], bre[i],PETSC_NULL,&vscatr[i]);CHKERRQ(ierr);
574     ierr = VecScatterBegin(vscatr[i],l,bre[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
575   }
576   for (i=0; i<bA->nc; i++) {
577     ierr = VecScatterEnd(vscatr[i],r,bre[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
578   }
579 
580   ierr = MatDiagonalScale_Nest(A,bl,br);CHKERRQ(ierr);
581 
582   for (i=0; i<bA->nr; i++) {
583     ierr = VecScatterDestroy(&vscatl[i]);CHKERRQ(ierr);
584   }
585   for (i=0; i<bA->nc; i++) {
586     ierr = VecScatterDestroy(&vscatr[i]);CHKERRQ(ierr);
587   }
588   ierr = PetscFree(vscatl);CHKERRQ(ierr);
589   ierr = PetscFree(vscatr);CHKERRQ(ierr);
590   ierr = VecDestroy(&bl);CHKERRQ(ierr);
591   ierr = VecDestroy(&br);CHKERRQ(ierr);
592   PetscFunctionReturn(0);
593 }
594 
595 #undef __FUNCT__
596 #define __FUNCT__ "MatGetVecs_Nest"
597 static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left)
598 {
599   Mat_Nest       *bA = (Mat_Nest*)A->data;
600   Vec            *L,*R;
601   MPI_Comm       comm;
602   PetscInt       i,j;
603   PetscErrorCode ierr;
604 
605   PetscFunctionBegin;
606   comm = ((PetscObject)A)->comm;
607   if (right) {
608     /* allocate R */
609     ierr = PetscMalloc( sizeof(Vec) * bA->nc, &R );CHKERRQ(ierr);
610     /* Create the right vectors */
611     for (j=0; j<bA->nc; j++) {
612       for (i=0; i<bA->nr; i++) {
613         if (bA->m[i][j]) {
614           ierr = MatGetVecs(bA->m[i][j],&R[j],PETSC_NULL);CHKERRQ(ierr);
615           break;
616         }
617       }
618       if (i==bA->nr) {
619         /* have an empty column */
620         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
621       }
622     }
623     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
624     /* hand back control to the nest vector */
625     for (j=0; j<bA->nc; j++) {
626       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
627     }
628     ierr = PetscFree(R);CHKERRQ(ierr);
629   }
630 
631   if (left) {
632     /* allocate L */
633     ierr = PetscMalloc( sizeof(Vec) * bA->nr, &L );CHKERRQ(ierr);
634     /* Create the left vectors */
635     for (i=0; i<bA->nr; i++) {
636       for (j=0; j<bA->nc; j++) {
637         if (bA->m[i][j]) {
638           ierr = MatGetVecs(bA->m[i][j],PETSC_NULL,&L[i]);CHKERRQ(ierr);
639           break;
640         }
641       }
642       if (j==bA->nc) {
643         /* have an empty row */
644         SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
645       }
646     }
647 
648     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
649     for (i=0; i<bA->nr; i++) {
650       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
651     }
652 
653     ierr = PetscFree(L);CHKERRQ(ierr);
654   }
655   PetscFunctionReturn(0);
656 }
657 
658 #undef __FUNCT__
659 #define __FUNCT__ "MatView_Nest"
660 static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
661 {
662   Mat_Nest       *bA = (Mat_Nest*)A->data;
663   PetscBool      isascii;
664   PetscInt       i,j;
665   PetscErrorCode ierr;
666 
667   PetscFunctionBegin;
668   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
669   if (isascii) {
670 
671     PetscViewerASCIIPrintf(viewer,"Matrix object: \n" );
672     PetscViewerASCIIPushTab( viewer );    /* push0 */
673     PetscViewerASCIIPrintf( viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc);
674 
675     PetscViewerASCIIPrintf(viewer,"MatNest structure: \n" );
676     for (i=0; i<bA->nr; i++) {
677       for (j=0; j<bA->nc; j++) {
678         const MatType type;
679         const char *name;
680         PetscInt NR,NC;
681         PetscBool isNest = PETSC_FALSE;
682 
683         if (!bA->m[i][j]) {
684           PetscViewerASCIIPrintf( viewer, "(%D,%D) : PETSC_NULL \n",i,j);
685           continue;
686         }
687         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
688         ierr = MatGetType( bA->m[i][j], &type );CHKERRQ(ierr);
689         name = ((PetscObject)bA->m[i][j])->prefix;
690         ierr = PetscTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
691 
692         PetscViewerASCIIPrintf( viewer, "(%D,%D) : name=\"%s\", type=%s, rows=%D, cols=%D \n",i,j,name,type,NR,NC);
693 
694         if (isNest) {
695           PetscViewerASCIIPushTab( viewer );  /* push1 */
696           ierr = MatView( bA->m[i][j], viewer );CHKERRQ(ierr);
697           PetscViewerASCIIPopTab(viewer);    /* pop1 */
698         }
699       }
700     }
701     PetscViewerASCIIPopTab(viewer);    /* pop0 */
702   }
703   PetscFunctionReturn(0);
704 }
705 
706 #undef __FUNCT__
707 #define __FUNCT__ "MatZeroEntries_Nest"
708 static PetscErrorCode MatZeroEntries_Nest(Mat A)
709 {
710   Mat_Nest       *bA = (Mat_Nest*)A->data;
711   PetscInt       i,j;
712   PetscErrorCode ierr;
713 
714   PetscFunctionBegin;
715   for (i=0; i<bA->nr; i++) {
716     for (j=0; j<bA->nc; j++) {
717       if (!bA->m[i][j]) continue;
718       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
719     }
720   }
721   PetscFunctionReturn(0);
722 }
723 
724 #undef __FUNCT__
725 #define __FUNCT__ "MatDuplicate_Nest"
726 static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
727 {
728   Mat_Nest       *bA = (Mat_Nest*)A->data;
729   Mat            *b;
730   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
731   PetscErrorCode ierr;
732 
733   PetscFunctionBegin;
734   ierr = PetscMalloc(nr*nc*sizeof(Mat),&b);CHKERRQ(ierr);
735   for (i=0; i<nr; i++) {
736     for (j=0; j<nc; j++) {
737       if (bA->m[i][j]) {
738         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
739       } else {
740         b[i*nc+j] = PETSC_NULL;
741       }
742     }
743   }
744   ierr = MatCreateNest(((PetscObject)A)->comm,nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
745   /* Give the new MatNest exclusive ownership */
746   for (i=0; i<nr*nc; i++) {
747     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
748   }
749   ierr = PetscFree(b);CHKERRQ(ierr);
750 
751   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
752   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
753   PetscFunctionReturn(0);
754 }
755 
756 /* nest api */
757 EXTERN_C_BEGIN
758 #undef __FUNCT__
759 #define __FUNCT__ "MatNestGetSubMat_Nest"
760 PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
761 {
762   Mat_Nest *bA = (Mat_Nest*)A->data;
763   PetscFunctionBegin;
764   if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
765   if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
766   *mat = bA->m[idxm][jdxm];
767   PetscFunctionReturn(0);
768 }
769 EXTERN_C_END
770 
771 #undef __FUNCT__
772 #define __FUNCT__ "MatNestGetSubMat"
773 /*@C
774  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
775 
776  Not collective
777 
778  Input Parameters:
779  .  A  - nest matrix
780  .  idxm - index of the matrix within the nest matrix
781  .  jdxm - index of the matrix within the nest matrix
782 
783  Output Parameter:
784  .  sub - matrix at index idxm,jdxm within the nest matrix
785 
786  Notes:
787 
788  Level: developer
789 
790  .seealso: MatNestGetSize(), MatNestGetSubMats()
791 @*/
792 PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
793 {
794   PetscErrorCode ierr;
795 
796   PetscFunctionBegin;
797   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
798   PetscFunctionReturn(0);
799 }
800 
801 EXTERN_C_BEGIN
802 #undef __FUNCT__
803 #define __FUNCT__ "MatNestGetSubMats_Nest"
804 PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
805 {
806   Mat_Nest *bA = (Mat_Nest*)A->data;
807   PetscFunctionBegin;
808   if (M)   { *M   = bA->nr; }
809   if (N)   { *N   = bA->nc; }
810   if (mat) { *mat = bA->m;  }
811   PetscFunctionReturn(0);
812 }
813 EXTERN_C_END
814 
815 #undef __FUNCT__
816 #define __FUNCT__ "MatNestGetSubMats"
817 /*@C
818  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
819 
820  Not collective
821 
822  Input Parameters:
823  .  A  - nest matri
824 
825  Output Parameter:
826  .  M - number of rows in the nest matrix
827  .  N - number of cols in the nest matrix
828  .  mat - 2d array of matrices
829 
830  Notes:
831 
832  The user should not free the array mat.
833 
834  Level: developer
835 
836  .seealso: MatNestGetSize(), MatNestGetSubMat()
837 @*/
838 PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
839 {
840   PetscErrorCode ierr;
841 
842   PetscFunctionBegin;
843   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
844   PetscFunctionReturn(0);
845 }
846 
847 EXTERN_C_BEGIN
848 #undef __FUNCT__
849 #define __FUNCT__ "MatNestGetSize_Nest"
850 PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
851 {
852   Mat_Nest  *bA = (Mat_Nest*)A->data;
853 
854   PetscFunctionBegin;
855   if (M) { *M  = bA->nr; }
856   if (N) { *N  = bA->nc; }
857   PetscFunctionReturn(0);
858 }
859 EXTERN_C_END
860 
861 #undef __FUNCT__
862 #define __FUNCT__ "MatNestGetSize"
863 /*@C
864  MatNestGetSize - Returns the size of the nest matrix.
865 
866  Not collective
867 
868  Input Parameters:
869  .  A  - nest matrix
870 
871  Output Parameter:
872  .  M - number of rows in the nested mat
873  .  N - number of cols in the nested mat
874 
875  Notes:
876 
877  Level: developer
878 
879  .seealso: MatNestGetSubMat(), MatNestGetSubMats()
880 @*/
881 PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
882 {
883   PetscErrorCode ierr;
884 
885   PetscFunctionBegin;
886   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
887   PetscFunctionReturn(0);
888 }
889 
890 EXTERN_C_BEGIN
891 #undef __FUNCT__
892 #define __FUNCT__ "MatNestSetVecType_Nest"
893 PetscErrorCode  MatNestSetVecType_Nest(Mat A,const VecType vtype)
894 {
895   PetscErrorCode ierr;
896   PetscBool      flg;
897 
898   PetscFunctionBegin;
899   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
900   /* In reality, this only distinguishes VECNEST and "other" */
901   A->ops->getvecs       = flg ? MatGetVecs_Nest       : 0;
902   A->ops->getdiagonal   = flg ? MatGetDiagonal_Nest   : 0;
903   A->ops->diagonalscale = flg ? MatDiagonalScale_Nest : 0;
904 
905  PetscFunctionReturn(0);
906 }
907 EXTERN_C_END
908 
909 #undef __FUNCT__
910 #define __FUNCT__ "MatNestSetVecType"
911 /*@C
912  MatNestSetVecType - Sets the type of Vec returned by MatGetVecs()
913 
914  Not collective
915 
916  Input Parameters:
917 +  A  - nest matrix
918 -  vtype - type to use for creating vectors
919 
920  Notes:
921 
922  Level: developer
923 
924  .seealso: MatGetVecs()
925 @*/
926 PetscErrorCode  MatNestSetVecType(Mat A,const VecType vtype)
927 {
928   PetscErrorCode ierr;
929 
930   PetscFunctionBegin;
931   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,const VecType),(A,vtype));CHKERRQ(ierr);
932   PetscFunctionReturn(0);
933 }
934 
935 EXTERN_C_BEGIN
936 #undef __FUNCT__
937 #define __FUNCT__ "MatNestSetSubMats_Nest"
938 PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
939 {
940   Mat_Nest       *s = (Mat_Nest*)A->data;
941   PetscInt       i,j,m,n,M,N;
942   PetscErrorCode ierr;
943 
944   PetscFunctionBegin;
945   s->nr = nr;
946   s->nc = nc;
947 
948   /* Create space for submatrices */
949   ierr = PetscMalloc(sizeof(Mat*)*nr,&s->m);CHKERRQ(ierr);
950   for (i=0; i<nr; i++) {
951     ierr = PetscMalloc(sizeof(Mat)*nc,&s->m[i]);CHKERRQ(ierr);
952   }
953   for (i=0; i<nr; i++) {
954     for (j=0; j<nc; j++) {
955       s->m[i][j] = a[i*nc+j];
956       if (a[i*nc+j]) {
957         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
958       }
959     }
960   }
961 
962   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
963 
964   ierr = PetscMalloc(sizeof(PetscInt)*nr,&s->row_len);CHKERRQ(ierr);
965   ierr = PetscMalloc(sizeof(PetscInt)*nc,&s->col_len);CHKERRQ(ierr);
966   for (i=0; i<nr; i++) s->row_len[i]=-1;
967   for (j=0; j<nc; j++) s->col_len[j]=-1;
968 
969   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
970 
971   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
972   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
973   ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr);
974   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
975   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
976   ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr);
977 
978   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
979   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
980 
981   ierr = PetscMalloc2(nr,Vec,&s->left,nc,Vec,&s->right);CHKERRQ(ierr);
982   ierr = PetscMemzero(s->left,nr*sizeof(Vec));CHKERRQ(ierr);
983   ierr = PetscMemzero(s->right,nc*sizeof(Vec));CHKERRQ(ierr);
984   PetscFunctionReturn(0);
985 }
986 EXTERN_C_END
987 
988 #undef __FUNCT__
989 #define __FUNCT__ "MatNestSetSubMats"
990 /*@
991    MatNestSetSubMats - Sets the nested submatrices
992 
993    Collective on Mat
994 
995    Input Parameter:
996 +  N - nested matrix
997 .  nr - number of nested row blocks
998 .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
999 .  nc - number of nested column blocks
1000 .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
1001 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL
1002 
1003    Level: advanced
1004 
1005 .seealso: MatCreateNest(), MATNEST
1006 @*/
1007 PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1008 {
1009   PetscErrorCode ierr;
1010   PetscInt i;
1011 
1012   PetscFunctionBegin;
1013   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1014   if (nr < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1015   if (nr && is_row) {
1016     PetscValidPointer(is_row,3);
1017     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1018   }
1019   if (nc < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
1020   if (nc && is_row) {
1021     PetscValidPointer(is_col,5);
1022     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1023   }
1024   if (nr*nc) PetscValidPointer(a,6);
1025   ierr = PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));CHKERRQ(ierr);
1026   PetscFunctionReturn(0);
1027 }
1028 
1029 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1030 /*
1031   nprocessors = NP
1032   Nest x^T = ( (g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1) )
1033        proc 0: => (g_0,h_0,)
1034        proc 1: => (g_1,h_1,)
1035        ...
1036        proc nprocs-1: => (g_NP-1,h_NP-1,)
1037 
1038             proc 0:                      proc 1:                    proc nprocs-1:
1039     is[0] = ( 0,1,2,...,nlocal(g_0)-1 )  ( 0,1,...,nlocal(g_1)-1 )  ( 0,1,...,nlocal(g_NP-1) )
1040 
1041             proc 0:
1042     is[1] = ( nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1 )
1043             proc 1:
1044     is[1] = ( nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1 )
1045 
1046             proc NP-1:
1047     is[1] = ( nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1 )
1048 */
1049 #undef __FUNCT__
1050 #define __FUNCT__ "MatSetUp_NestIS_Private"
1051 static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1052 {
1053   Mat_Nest       *vs = (Mat_Nest*)A->data;
1054   PetscInt       i,j,offset,n,nsum,bs;
1055   PetscErrorCode ierr;
1056   Mat            sub;
1057 
1058   PetscFunctionBegin;
1059   ierr = PetscMalloc(sizeof(IS)*nr,&vs->isglobal.row);CHKERRQ(ierr);
1060   ierr = PetscMalloc(sizeof(IS)*nc,&vs->isglobal.col);CHKERRQ(ierr);
1061   if (is_row) { /* valid IS is passed in */
1062     /* refs on is[] are incremeneted */
1063     for (i=0; i<vs->nr; i++) {
1064       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
1065       vs->isglobal.row[i] = is_row[i];
1066     }
1067   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
1068     nsum = 0;
1069     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
1070       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1071       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
1072       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
1073       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1074       nsum += n;
1075     }
1076     offset = 0;
1077     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
1078     for (i=0; i<vs->nr; i++) {
1079       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1080       ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr);
1081       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1082       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1083       ierr = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
1084       offset += n;
1085     }
1086   }
1087 
1088   if (is_col) { /* valid IS is passed in */
1089     /* refs on is[] are incremeneted */
1090     for (j=0; j<vs->nc; j++) {
1091       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
1092       vs->isglobal.col[j] = is_col[j];
1093     }
1094   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
1095     offset = A->cmap->rstart;
1096     nsum = 0;
1097     for (j=0; j<vs->nc; j++) {
1098       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1099       if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
1100       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
1101       if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1102       nsum += n;
1103     }
1104     offset = 0;
1105     ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr);
1106     for (j=0; j<vs->nc; j++) {
1107       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1108       ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr);
1109       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1110       ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1111       ierr = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
1112       offset += n;
1113     }
1114   }
1115 
1116   /* Set up the local ISs */
1117   ierr = PetscMalloc(vs->nr*sizeof(IS),&vs->islocal.row);CHKERRQ(ierr);
1118   ierr = PetscMalloc(vs->nc*sizeof(IS),&vs->islocal.col);CHKERRQ(ierr);
1119   for (i=0,offset=0; i<vs->nr; i++) {
1120     IS                     isloc;
1121     ISLocalToGlobalMapping rmap = PETSC_NULL;
1122     PetscInt               nlocal,bs;
1123     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1124     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,PETSC_NULL);CHKERRQ(ierr);}
1125     if (rmap) {
1126       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1127       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1128       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1129       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1130     } else {
1131       nlocal = 0;
1132       isloc  = PETSC_NULL;
1133     }
1134     vs->islocal.row[i] = isloc;
1135     offset += nlocal;
1136   }
1137   for (i=0,offset=0; i<vs->nc; i++) {
1138     IS                     isloc;
1139     ISLocalToGlobalMapping cmap = PETSC_NULL;
1140     PetscInt               nlocal,bs;
1141     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
1142     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,PETSC_NULL,&cmap);CHKERRQ(ierr);}
1143     if (cmap) {
1144       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1145       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1146       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1147       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1148     } else {
1149       nlocal = 0;
1150       isloc  = PETSC_NULL;
1151     }
1152     vs->islocal.col[i] = isloc;
1153     offset += nlocal;
1154   }
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "MatCreateNest"
1160 /*@
1161    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1162 
1163    Collective on Mat
1164 
1165    Input Parameter:
1166 +  comm - Communicator for the new Mat
1167 .  nr - number of nested row blocks
1168 .  is_row - index sets for each nested row block, or PETSC_NULL to make contiguous
1169 .  nc - number of nested column blocks
1170 .  is_col - index sets for each nested column block, or PETSC_NULL to make contiguous
1171 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL
1172 
1173    Output Parameter:
1174 .  B - new matrix
1175 
1176    Level: advanced
1177 
1178 .seealso: MatCreate(), VecCreateNest(), DMGetMatrix(), MATNEST
1179 @*/
1180 PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1181 {
1182   Mat            A;
1183   PetscErrorCode ierr;
1184 
1185   PetscFunctionBegin;
1186   *B = 0;
1187   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1188   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
1189   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1190   *B = A;
1191   PetscFunctionReturn(0);
1192 }
1193 
1194 /*MC
1195   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1196 
1197   Level: intermediate
1198 
1199   Notes:
1200   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1201   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1202   It is usually used with DMComposite and DMGetMatrix()
1203 
1204 .seealso: MatCreate(), MatType, MatCreateNest()
1205 M*/
1206 EXTERN_C_BEGIN
1207 #undef __FUNCT__
1208 #define __FUNCT__ "MatCreate_Nest"
1209 PetscErrorCode MatCreate_Nest(Mat A)
1210 {
1211   Mat_Nest       *s;
1212   PetscErrorCode ierr;
1213 
1214   PetscFunctionBegin;
1215   ierr = PetscNewLog(A,Mat_Nest,&s);CHKERRQ(ierr);
1216   A->data         = (void*)s;
1217   s->nr = s->nc   = -1;
1218   s->m            = PETSC_NULL;
1219 
1220   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
1221   A->ops->mult                  = MatMult_Nest;
1222   A->ops->multadd               = 0;
1223   A->ops->multtranspose         = MatMultTranspose_Nest;
1224   A->ops->multtransposeadd      = 0;
1225   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1226   A->ops->assemblyend           = MatAssemblyEnd_Nest;
1227   A->ops->zeroentries           = MatZeroEntries_Nest;
1228   A->ops->duplicate             = MatDuplicate_Nest;
1229   A->ops->getsubmatrix          = MatGetSubMatrix_Nest;
1230   A->ops->destroy               = MatDestroy_Nest;
1231   A->ops->view                  = MatView_Nest;
1232   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
1233   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
1234   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
1235   A->ops->getdiagonal           = MatGetDiagonal_Nest2; /* VECNEST version activated by calling MatNestSetVecType(A,VECNEST) */
1236   A->ops->diagonalscale         = MatDiagonalScale_Nest2; /* VECNEST version activated by calling MatNestSetVecType(A,VECNEST) */
1237 
1238   A->spptr        = 0;
1239   A->same_nonzero = PETSC_FALSE;
1240   A->assembled    = PETSC_FALSE;
1241 
1242   /* expose Nest api's */
1243   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C",   "MatNestGetSubMat_Nest",   MatNestGetSubMat_Nest);CHKERRQ(ierr);
1244   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C",  "MatNestGetSubMats_Nest",  MatNestGetSubMats_Nest);CHKERRQ(ierr);
1245   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C",     "MatNestGetSize_Nest",     MatNestGetSize_Nest);CHKERRQ(ierr);
1246   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C",  "MatNestSetVecType_Nest",  MatNestSetVecType_Nest);CHKERRQ(ierr);
1247   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C",  "MatNestSetSubMats_Nest",  MatNestSetSubMats_Nest);CHKERRQ(ierr);
1248 
1249   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
1250   PetscFunctionReturn(0);
1251 }
1252 EXTERN_C_END
1253