xref: /petsc/src/mat/impls/nest/matnest.c (revision daa037dfd3c3bec8dc8659548d2b20b07c1dc6de)
1 #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
2 #include <../src/mat/impls/aij/seq/aij.h>
3 #include <petscsf.h>
4 
5 static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
6 static PetscErrorCode MatCreateVecs_Nest(Mat,Vec*,Vec*);
7 static PetscErrorCode MatReset_Nest(Mat);
8 
9 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat,MatType,MatReuse,Mat*);
10 
11 /* private functions */
12 static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
13 {
14   Mat_Nest       *bA = (Mat_Nest*)A->data;
15   PetscInt       i,j;
16 
17   PetscFunctionBegin;
18   *m = *n = *M = *N = 0;
19   for (i=0; i<bA->nr; i++) {  /* rows */
20     PetscInt sm,sM;
21     PetscCall(ISGetLocalSize(bA->isglobal.row[i],&sm));
22     PetscCall(ISGetSize(bA->isglobal.row[i],&sM));
23     *m  += sm;
24     *M  += sM;
25   }
26   for (j=0; j<bA->nc; j++) {  /* cols */
27     PetscInt sn,sN;
28     PetscCall(ISGetLocalSize(bA->isglobal.col[j],&sn));
29     PetscCall(ISGetSize(bA->isglobal.col[j],&sN));
30     *n  += sn;
31     *N  += sN;
32   }
33   PetscFunctionReturn(0);
34 }
35 
36 /* operations */
37 static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
38 {
39   Mat_Nest       *bA = (Mat_Nest*)A->data;
40   Vec            *bx = bA->right,*by = bA->left;
41   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
42 
43   PetscFunctionBegin;
44   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(y,bA->isglobal.row[i],&by[i]));
45   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(x,bA->isglobal.col[i],&bx[i]));
46   for (i=0; i<nr; i++) {
47     PetscCall(VecZeroEntries(by[i]));
48     for (j=0; j<nc; j++) {
49       if (!bA->m[i][j]) continue;
50       /* y[i] <- y[i] + A[i][j] * x[j] */
51       PetscCall(MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]));
52     }
53   }
54   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]));
55   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]));
56   PetscFunctionReturn(0);
57 }
58 
59 static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
60 {
61   Mat_Nest       *bA = (Mat_Nest*)A->data;
62   Vec            *bx = bA->right,*bz = bA->left;
63   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
64 
65   PetscFunctionBegin;
66   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(z,bA->isglobal.row[i],&bz[i]));
67   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(x,bA->isglobal.col[i],&bx[i]));
68   for (i=0; i<nr; i++) {
69     if (y != z) {
70       Vec by;
71       PetscCall(VecGetSubVector(y,bA->isglobal.row[i],&by));
72       PetscCall(VecCopy(by,bz[i]));
73       PetscCall(VecRestoreSubVector(y,bA->isglobal.row[i],&by));
74     }
75     for (j=0; j<nc; j++) {
76       if (!bA->m[i][j]) continue;
77       /* y[i] <- y[i] + A[i][j] * x[j] */
78       PetscCall(MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]));
79     }
80   }
81   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]));
82   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]));
83   PetscFunctionReturn(0);
84 }
85 
86 typedef struct {
87   Mat          *workC;    /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
88   PetscScalar  *tarray;   /* buffer for storing all temporary products A[i][j] B[j] */
89   PetscInt     *dm,*dn,k; /* displacements and number of submatrices */
90 } Nest_Dense;
91 
92 PETSC_INTERN PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
93 {
94   Mat_Nest          *bA;
95   Nest_Dense        *contents;
96   Mat               viewB,viewC,productB,workC;
97   const PetscScalar *barray;
98   PetscScalar       *carray;
99   PetscInt          i,j,M,N,nr,nc,ldb,ldc;
100   Mat               A,B;
101 
102   PetscFunctionBegin;
103   MatCheckProduct(C,3);
104   A    = C->product->A;
105   B    = C->product->B;
106   PetscCall(MatGetSize(B,NULL,&N));
107   if (!N) {
108     PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
109     PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
110     PetscFunctionReturn(0);
111   }
112   contents = (Nest_Dense*)C->product->data;
113   PetscCheck(contents,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
114   bA   = (Mat_Nest*)A->data;
115   nr   = bA->nr;
116   nc   = bA->nc;
117   PetscCall(MatDenseGetLDA(B,&ldb));
118   PetscCall(MatDenseGetLDA(C,&ldc));
119   PetscCall(MatZeroEntries(C));
120   PetscCall(MatDenseGetArrayRead(B,&barray));
121   PetscCall(MatDenseGetArray(C,&carray));
122   for (i=0; i<nr; i++) {
123     PetscCall(ISGetSize(bA->isglobal.row[i],&M));
124     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dm[i+1]-contents->dm[i],PETSC_DECIDE,M,N,carray+contents->dm[i],&viewC));
125     PetscCall(MatDenseSetLDA(viewC,ldc));
126     for (j=0; j<nc; j++) {
127       if (!bA->m[i][j]) continue;
128       PetscCall(ISGetSize(bA->isglobal.col[j],&M));
129       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB));
130       PetscCall(MatDenseSetLDA(viewB,ldb));
131 
132       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
133       workC             = contents->workC[i*nc + j];
134       productB          = workC->product->B;
135       workC->product->B = viewB; /* use newly created dense matrix viewB */
136       PetscCall(MatProductNumeric(workC));
137       PetscCall(MatDestroy(&viewB));
138       workC->product->B = productB; /* resume original B */
139 
140       /* C[i] <- workC + C[i] */
141       PetscCall(MatAXPY(viewC,1.0,contents->workC[i*nc + j],SAME_NONZERO_PATTERN));
142     }
143     PetscCall(MatDestroy(&viewC));
144   }
145   PetscCall(MatDenseRestoreArray(C,&carray));
146   PetscCall(MatDenseRestoreArrayRead(B,&barray));
147 
148   PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
149   PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
150   PetscFunctionReturn(0);
151 }
152 
153 PetscErrorCode MatNest_DenseDestroy(void *ctx)
154 {
155   Nest_Dense     *contents = (Nest_Dense*)ctx;
156   PetscInt       i;
157 
158   PetscFunctionBegin;
159   PetscCall(PetscFree(contents->tarray));
160   for (i=0; i<contents->k; i++) {
161     PetscCall(MatDestroy(contents->workC + i));
162   }
163   PetscCall(PetscFree3(contents->dm,contents->dn,contents->workC));
164   PetscCall(PetscFree(contents));
165   PetscFunctionReturn(0);
166 }
167 
168 PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
169 {
170   Mat_Nest          *bA;
171   Mat               viewB,workC;
172   const PetscScalar *barray;
173   PetscInt          i,j,M,N,m,n,nr,nc,maxm = 0,ldb;
174   Nest_Dense        *contents=NULL;
175   PetscBool         cisdense;
176   Mat               A,B;
177   PetscReal         fill;
178 
179   PetscFunctionBegin;
180   MatCheckProduct(C,4);
181   PetscCheck(!C->product->data,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
182   A    = C->product->A;
183   B    = C->product->B;
184   fill = C->product->fill;
185   bA   = (Mat_Nest*)A->data;
186   nr   = bA->nr;
187   nc   = bA->nc;
188   PetscCall(MatGetLocalSize(C,&m,&n));
189   PetscCall(MatGetSize(C,&M,&N));
190   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
191     PetscCall(MatGetLocalSize(B,NULL,&n));
192     PetscCall(MatGetSize(B,NULL,&N));
193     PetscCall(MatGetLocalSize(A,&m,NULL));
194     PetscCall(MatGetSize(A,&M,NULL));
195     PetscCall(MatSetSizes(C,m,n,M,N));
196   }
197   PetscCall(PetscObjectTypeCompareAny((PetscObject)C,&cisdense,MATSEQDENSE,MATMPIDENSE,MATSEQDENSECUDA,MATMPIDENSECUDA,""));
198   if (!cisdense) {
199     PetscCall(MatSetType(C,((PetscObject)B)->type_name));
200   }
201   PetscCall(MatSetUp(C));
202   if (!N) {
203     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
204     PetscFunctionReturn(0);
205   }
206 
207   PetscCall(PetscNew(&contents));
208   C->product->data = contents;
209   C->product->destroy = MatNest_DenseDestroy;
210   PetscCall(PetscCalloc3(nr+1,&contents->dm,nc+1,&contents->dn,nr*nc,&contents->workC));
211   contents->k = nr*nc;
212   for (i=0; i<nr; i++) {
213     PetscCall(ISGetLocalSize(bA->isglobal.row[i],contents->dm + i+1));
214     maxm = PetscMax(maxm,contents->dm[i+1]);
215     contents->dm[i+1] += contents->dm[i];
216   }
217   for (i=0; i<nc; i++) {
218     PetscCall(ISGetLocalSize(bA->isglobal.col[i],contents->dn + i+1));
219     contents->dn[i+1] += contents->dn[i];
220   }
221   PetscCall(PetscMalloc1(maxm*N,&contents->tarray));
222   PetscCall(MatDenseGetLDA(B,&ldb));
223   PetscCall(MatGetSize(B,NULL,&N));
224   PetscCall(MatDenseGetArrayRead(B,&barray));
225   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
226   for (j=0; j<nc; j++) {
227     PetscCall(ISGetSize(bA->isglobal.col[j],&M));
228     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB));
229     PetscCall(MatDenseSetLDA(viewB,ldb));
230     for (i=0; i<nr; i++) {
231       if (!bA->m[i][j]) continue;
232       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
233 
234       PetscCall(MatProductCreate(bA->m[i][j],viewB,NULL,&contents->workC[i*nc + j]));
235       workC = contents->workC[i*nc + j];
236       PetscCall(MatProductSetType(workC,MATPRODUCT_AB));
237       PetscCall(MatProductSetAlgorithm(workC,"default"));
238       PetscCall(MatProductSetFill(workC,fill));
239       PetscCall(MatProductSetFromOptions(workC));
240       PetscCall(MatProductSymbolic(workC));
241 
242       /* since tarray will be shared by all Mat */
243       PetscCall(MatSeqDenseSetPreallocation(workC,contents->tarray));
244       PetscCall(MatMPIDenseSetPreallocation(workC,contents->tarray));
245     }
246     PetscCall(MatDestroy(&viewB));
247   }
248   PetscCall(MatDenseRestoreArrayRead(B,&barray));
249 
250   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
251   PetscFunctionReturn(0);
252 }
253 
254 /* --------------------------------------------------------- */
255 static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
256 {
257   PetscFunctionBegin;
258   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
259   PetscFunctionReturn(0);
260 }
261 
262 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
263 {
264   Mat_Product    *product = C->product;
265 
266   PetscFunctionBegin;
267   if (product->type == MATPRODUCT_AB) {
268     PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
269   }
270   PetscFunctionReturn(0);
271 }
272 /* --------------------------------------------------------- */
273 
274 static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
275 {
276   Mat_Nest       *bA = (Mat_Nest*)A->data;
277   Vec            *bx = bA->left,*by = bA->right;
278   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
279 
280   PetscFunctionBegin;
281   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(x,bA->isglobal.row[i],&bx[i]));
282   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(y,bA->isglobal.col[i],&by[i]));
283   for (j=0; j<nc; j++) {
284     PetscCall(VecZeroEntries(by[j]));
285     for (i=0; i<nr; i++) {
286       if (!bA->m[i][j]) continue;
287       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
288       PetscCall(MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]));
289     }
290   }
291   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]));
292   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]));
293   PetscFunctionReturn(0);
294 }
295 
296 static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
297 {
298   Mat_Nest       *bA = (Mat_Nest*)A->data;
299   Vec            *bx = bA->left,*bz = bA->right;
300   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
301 
302   PetscFunctionBegin;
303   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(x,bA->isglobal.row[i],&bx[i]));
304   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(z,bA->isglobal.col[i],&bz[i]));
305   for (j=0; j<nc; j++) {
306     if (y != z) {
307       Vec by;
308       PetscCall(VecGetSubVector(y,bA->isglobal.col[j],&by));
309       PetscCall(VecCopy(by,bz[j]));
310       PetscCall(VecRestoreSubVector(y,bA->isglobal.col[j],&by));
311     }
312     for (i=0; i<nr; i++) {
313       if (!bA->m[i][j]) continue;
314       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
315       PetscCall(MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]));
316     }
317   }
318   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]));
319   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]));
320   PetscFunctionReturn(0);
321 }
322 
323 static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
324 {
325   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
326   Mat            C;
327   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
328 
329   PetscFunctionBegin;
330   PetscCheckFalse(reuse == MAT_INPLACE_MATRIX && nr != nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
331 
332   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
333     Mat *subs;
334     IS  *is_row,*is_col;
335 
336     PetscCall(PetscCalloc1(nr * nc,&subs));
337     PetscCall(PetscMalloc2(nr,&is_row,nc,&is_col));
338     PetscCall(MatNestGetISs(A,is_row,is_col));
339     if (reuse == MAT_INPLACE_MATRIX) {
340       for (i=0; i<nr; i++) {
341         for (j=0; j<nc; j++) {
342           subs[i + nr * j] = bA->m[i][j];
343         }
344       }
345     }
346 
347     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C));
348     PetscCall(PetscFree(subs));
349     PetscCall(PetscFree2(is_row,is_col));
350   } else {
351     C = *B;
352   }
353 
354   bC = (Mat_Nest*)C->data;
355   for (i=0; i<nr; i++) {
356     for (j=0; j<nc; j++) {
357       if (bA->m[i][j]) {
358         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
359       } else {
360         bC->m[j][i] = NULL;
361       }
362     }
363   }
364 
365   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
366     *B = C;
367   } else {
368     PetscCall(MatHeaderMerge(A, &C));
369   }
370   PetscFunctionReturn(0);
371 }
372 
373 static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
374 {
375   IS             *lst = *list;
376   PetscInt       i;
377 
378   PetscFunctionBegin;
379   if (!lst) PetscFunctionReturn(0);
380   for (i=0; i<n; i++) if (lst[i]) PetscCall(ISDestroy(&lst[i]));
381   PetscCall(PetscFree(lst));
382   *list = NULL;
383   PetscFunctionReturn(0);
384 }
385 
386 static PetscErrorCode MatReset_Nest(Mat A)
387 {
388   Mat_Nest       *vs = (Mat_Nest*)A->data;
389   PetscInt       i,j;
390 
391   PetscFunctionBegin;
392   /* release the matrices and the place holders */
393   PetscCall(MatNestDestroyISList(vs->nr,&vs->isglobal.row));
394   PetscCall(MatNestDestroyISList(vs->nc,&vs->isglobal.col));
395   PetscCall(MatNestDestroyISList(vs->nr,&vs->islocal.row));
396   PetscCall(MatNestDestroyISList(vs->nc,&vs->islocal.col));
397 
398   PetscCall(PetscFree(vs->row_len));
399   PetscCall(PetscFree(vs->col_len));
400   PetscCall(PetscFree(vs->nnzstate));
401 
402   PetscCall(PetscFree2(vs->left,vs->right));
403 
404   /* release the matrices and the place holders */
405   if (vs->m) {
406     for (i=0; i<vs->nr; i++) {
407       for (j=0; j<vs->nc; j++) {
408         PetscCall(MatDestroy(&vs->m[i][j]));
409       }
410       PetscCall(PetscFree(vs->m[i]));
411     }
412     PetscCall(PetscFree(vs->m));
413   }
414 
415   /* restore defaults */
416   vs->nr = 0;
417   vs->nc = 0;
418   vs->splitassembly = PETSC_FALSE;
419   PetscFunctionReturn(0);
420 }
421 
422 static PetscErrorCode MatDestroy_Nest(Mat A)
423 {
424   PetscFunctionBegin;
425   PetscCall(MatReset_Nest(A));
426   PetscCall(PetscFree(A->data));
427   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",NULL));
428   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",NULL));
429   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",NULL));
430   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",NULL));
431   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",NULL));
432   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",NULL));
433   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",NULL));
434   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",NULL));
435   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",NULL));
436   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",NULL));
437   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",NULL));
438   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",NULL));
439   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpidense_C",NULL));
440   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqdense_C",NULL));
441   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",NULL));
442   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",NULL));
443   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",NULL));
444   PetscFunctionReturn(0);
445 }
446 
447 static PetscErrorCode MatMissingDiagonal_Nest(Mat mat,PetscBool *missing,PetscInt *dd)
448 {
449   Mat_Nest       *vs = (Mat_Nest*)mat->data;
450   PetscInt       i;
451 
452   PetscFunctionBegin;
453   if (dd) *dd = 0;
454   if (!vs->nr) {
455     *missing = PETSC_TRUE;
456     PetscFunctionReturn(0);
457   }
458   *missing = PETSC_FALSE;
459   for (i = 0; i < vs->nr && !(*missing); i++) {
460     *missing = PETSC_TRUE;
461     if (vs->m[i][i]) {
462       PetscCall(MatMissingDiagonal(vs->m[i][i],missing,NULL));
463       PetscCheckFalse(*missing && dd,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"First missing entry not yet implemented");
464     }
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
470 {
471   Mat_Nest       *vs = (Mat_Nest*)A->data;
472   PetscInt       i,j;
473   PetscBool      nnzstate = PETSC_FALSE;
474 
475   PetscFunctionBegin;
476   for (i=0; i<vs->nr; i++) {
477     for (j=0; j<vs->nc; j++) {
478       PetscObjectState subnnzstate = 0;
479       if (vs->m[i][j]) {
480         PetscCall(MatAssemblyBegin(vs->m[i][j],type));
481         if (!vs->splitassembly) {
482           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
483            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
484            * already performing an assembly, but the result would by more complicated and appears to offer less
485            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
486            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
487            */
488           PetscCall(MatAssemblyEnd(vs->m[i][j],type));
489           PetscCall(MatGetNonzeroState(vs->m[i][j],&subnnzstate));
490         }
491       }
492       nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i*vs->nc+j] != subnnzstate);
493       vs->nnzstate[i*vs->nc+j] = subnnzstate;
494     }
495   }
496   if (nnzstate) A->nonzerostate++;
497   PetscFunctionReturn(0);
498 }
499 
500 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
501 {
502   Mat_Nest       *vs = (Mat_Nest*)A->data;
503   PetscInt       i,j;
504 
505   PetscFunctionBegin;
506   for (i=0; i<vs->nr; i++) {
507     for (j=0; j<vs->nc; j++) {
508       if (vs->m[i][j]) {
509         if (vs->splitassembly) {
510           PetscCall(MatAssemblyEnd(vs->m[i][j],type));
511         }
512       }
513     }
514   }
515   PetscFunctionReturn(0);
516 }
517 
518 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
519 {
520   Mat_Nest       *vs = (Mat_Nest*)A->data;
521   PetscInt       j;
522   Mat            sub;
523 
524   PetscFunctionBegin;
525   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
526   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
527   if (sub) PetscCall(MatSetUp(sub));       /* Ensure that the sizes are available */
528   *B = sub;
529   PetscFunctionReturn(0);
530 }
531 
532 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
533 {
534   Mat_Nest       *vs = (Mat_Nest*)A->data;
535   PetscInt       i;
536   Mat            sub;
537 
538   PetscFunctionBegin;
539   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
540   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
541   if (sub) PetscCall(MatSetUp(sub));       /* Ensure that the sizes are available */
542   *B = sub;
543   PetscFunctionReturn(0);
544 }
545 
546 static PetscErrorCode MatNestFindISRange(Mat A,PetscInt n,const IS list[],IS is,PetscInt *begin,PetscInt *end)
547 {
548   PetscInt       i,j,size,m;
549   PetscBool      flg;
550   IS             out,concatenate[2];
551 
552   PetscFunctionBegin;
553   PetscValidPointer(list,3);
554   PetscValidHeaderSpecific(is,IS_CLASSID,4);
555   if (begin) {
556     PetscValidIntPointer(begin,5);
557     *begin = -1;
558   }
559   if (end) {
560     PetscValidIntPointer(end,6);
561     *end = -1;
562   }
563   for (i=0; i<n; i++) {
564     if (!list[i]) continue;
565     PetscCall(ISEqualUnsorted(list[i],is,&flg));
566     if (flg) {
567       if (begin) *begin = i;
568       if (end) *end = i+1;
569       PetscFunctionReturn(0);
570     }
571   }
572   PetscCall(ISGetSize(is,&size));
573   for (i=0; i<n-1; i++) {
574     if (!list[i]) continue;
575     m = 0;
576     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A),2,list+i,&out));
577     PetscCall(ISGetSize(out,&m));
578     for (j=i+2; j<n && m<size; j++) {
579       if (list[j]) {
580         concatenate[0] = out;
581         concatenate[1] = list[j];
582         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A),2,concatenate,&out));
583         PetscCall(ISDestroy(concatenate));
584         PetscCall(ISGetSize(out,&m));
585       }
586     }
587     if (m == size) {
588       PetscCall(ISEqualUnsorted(out,is,&flg));
589       if (flg) {
590         if (begin) *begin = i;
591         if (end) *end = j;
592         PetscCall(ISDestroy(&out));
593         PetscFunctionReturn(0);
594       }
595     }
596     PetscCall(ISDestroy(&out));
597   }
598   PetscFunctionReturn(0);
599 }
600 
601 static PetscErrorCode MatNestFillEmptyMat_Private(Mat A,PetscInt i,PetscInt j,Mat *B)
602 {
603   Mat_Nest       *vs = (Mat_Nest*)A->data;
604   PetscInt       lr,lc;
605 
606   PetscFunctionBegin;
607   PetscCall(MatCreate(PetscObjectComm((PetscObject)A),B));
608   PetscCall(ISGetLocalSize(vs->isglobal.row[i],&lr));
609   PetscCall(ISGetLocalSize(vs->isglobal.col[j],&lc));
610   PetscCall(MatSetSizes(*B,lr,lc,PETSC_DECIDE,PETSC_DECIDE));
611   PetscCall(MatSetType(*B,MATAIJ));
612   PetscCall(MatSeqAIJSetPreallocation(*B,0,NULL));
613   PetscCall(MatMPIAIJSetPreallocation(*B,0,NULL,0,NULL));
614   PetscCall(MatSetUp(*B));
615   PetscCall(MatSetOption(*B,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE));
616   PetscCall(MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY));
617   PetscCall(MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY));
618   PetscFunctionReturn(0);
619 }
620 
621 static PetscErrorCode MatNestGetBlock_Private(Mat A,PetscInt rbegin,PetscInt rend,PetscInt cbegin,PetscInt cend,Mat *B)
622 {
623   Mat_Nest       *vs = (Mat_Nest*)A->data;
624   Mat            *a;
625   PetscInt       i,j,k,l,nr=rend-rbegin,nc=cend-cbegin;
626   char           keyname[256];
627   PetscBool      *b;
628   PetscBool      flg;
629 
630   PetscFunctionBegin;
631   *B   = NULL;
632   PetscCall(PetscSNPrintf(keyname,sizeof(keyname),"NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT,rbegin,rend,cbegin,cend));
633   PetscCall(PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B));
634   if (*B) PetscFunctionReturn(0);
635 
636   PetscCall(PetscMalloc2(nr*nc,&a,nr*nc,&b));
637   for (i=0; i<nr; i++) {
638     for (j=0; j<nc; j++) {
639       a[i*nc + j] = vs->m[rbegin+i][cbegin+j];
640       b[i*nc + j] = PETSC_FALSE;
641     }
642   }
643   if (nc!=vs->nc&&nr!=vs->nr) {
644     for (i=0; i<nr; i++) {
645       for (j=0; j<nc; j++) {
646         flg = PETSC_FALSE;
647         for (k=0; (k<nr&&!flg); k++) {
648           if (a[j + k*nc]) flg = PETSC_TRUE;
649         }
650         if (flg) {
651           flg = PETSC_FALSE;
652           for (l=0; (l<nc&&!flg); l++) {
653             if (a[i*nc + l]) flg = PETSC_TRUE;
654           }
655         }
656         if (!flg) {
657           b[i*nc + j] = PETSC_TRUE;
658           PetscCall(MatNestFillEmptyMat_Private(A,rbegin+i,cbegin+j,a + i*nc + j));
659         }
660       }
661     }
662   }
663   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nr,nr!=vs->nr?NULL:vs->isglobal.row,nc,nc!=vs->nc?NULL:vs->isglobal.col,a,B));
664   for (i=0; i<nr; i++) {
665     for (j=0; j<nc; j++) {
666       if (b[i*nc + j]) {
667         PetscCall(MatDestroy(a + i*nc + j));
668       }
669     }
670   }
671   PetscCall(PetscFree2(a,b));
672   (*B)->assembled = A->assembled;
673   PetscCall(PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B));
674   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
675   PetscFunctionReturn(0);
676 }
677 
678 static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
679 {
680   Mat_Nest       *vs = (Mat_Nest*)A->data;
681   PetscInt       rbegin,rend,cbegin,cend;
682 
683   PetscFunctionBegin;
684   PetscCall(MatNestFindISRange(A,vs->nr,is->row,isrow,&rbegin,&rend));
685   PetscCall(MatNestFindISRange(A,vs->nc,is->col,iscol,&cbegin,&cend));
686   if (rend == rbegin + 1 && cend == cbegin + 1) {
687     if (!vs->m[rbegin][cbegin]) {
688       PetscCall(MatNestFillEmptyMat_Private(A,rbegin,cbegin,vs->m[rbegin] + cbegin));
689     }
690     *B = vs->m[rbegin][cbegin];
691   } else if (rbegin != -1 && cbegin != -1) {
692     PetscCall(MatNestGetBlock_Private(A,rbegin,rend,cbegin,cend,B));
693   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
694   PetscFunctionReturn(0);
695 }
696 
697 /*
698    TODO: This does not actually returns a submatrix we can modify
699 */
700 static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
701 {
702   Mat_Nest       *vs = (Mat_Nest*)A->data;
703   Mat            sub;
704 
705   PetscFunctionBegin;
706   PetscCall(MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub));
707   switch (reuse) {
708   case MAT_INITIAL_MATRIX:
709     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
710     *B = sub;
711     break;
712   case MAT_REUSE_MATRIX:
713     PetscCheckFalse(sub != *B,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
714     break;
715   case MAT_IGNORE_MATRIX:       /* Nothing to do */
716     break;
717   case MAT_INPLACE_MATRIX:       /* Nothing to do */
718     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
719   }
720   PetscFunctionReturn(0);
721 }
722 
723 PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
724 {
725   Mat_Nest       *vs = (Mat_Nest*)A->data;
726   Mat            sub;
727 
728   PetscFunctionBegin;
729   PetscCall(MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub));
730   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
731   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
732   *B = sub;
733   PetscFunctionReturn(0);
734 }
735 
736 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
737 {
738   Mat_Nest       *vs = (Mat_Nest*)A->data;
739   Mat            sub;
740 
741   PetscFunctionBegin;
742   PetscCall(MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub));
743   PetscCheckFalse(*B != sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
744   if (sub) {
745     PetscCheckFalse(((PetscObject)sub)->refct <= 1,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
746     PetscCall(MatDestroy(B));
747   }
748   PetscFunctionReturn(0);
749 }
750 
751 static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
752 {
753   Mat_Nest       *bA = (Mat_Nest*)A->data;
754   PetscInt       i;
755 
756   PetscFunctionBegin;
757   for (i=0; i<bA->nr; i++) {
758     Vec bv;
759     PetscCall(VecGetSubVector(v,bA->isglobal.row[i],&bv));
760     if (bA->m[i][i]) {
761       PetscCall(MatGetDiagonal(bA->m[i][i],bv));
762     } else {
763       PetscCall(VecSet(bv,0.0));
764     }
765     PetscCall(VecRestoreSubVector(v,bA->isglobal.row[i],&bv));
766   }
767   PetscFunctionReturn(0);
768 }
769 
770 static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
771 {
772   Mat_Nest       *bA = (Mat_Nest*)A->data;
773   Vec            bl,*br;
774   PetscInt       i,j;
775 
776   PetscFunctionBegin;
777   PetscCall(PetscCalloc1(bA->nc,&br));
778   if (r) {
779     for (j=0; j<bA->nc; j++) PetscCall(VecGetSubVector(r,bA->isglobal.col[j],&br[j]));
780   }
781   bl = NULL;
782   for (i=0; i<bA->nr; i++) {
783     if (l) {
784       PetscCall(VecGetSubVector(l,bA->isglobal.row[i],&bl));
785     }
786     for (j=0; j<bA->nc; j++) {
787       if (bA->m[i][j]) {
788         PetscCall(MatDiagonalScale(bA->m[i][j],bl,br[j]));
789       }
790     }
791     if (l) {
792       PetscCall(VecRestoreSubVector(l,bA->isglobal.row[i],&bl));
793     }
794   }
795   if (r) {
796     for (j=0; j<bA->nc; j++) PetscCall(VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]));
797   }
798   PetscCall(PetscFree(br));
799   PetscFunctionReturn(0);
800 }
801 
802 static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
803 {
804   Mat_Nest       *bA = (Mat_Nest*)A->data;
805   PetscInt       i,j;
806 
807   PetscFunctionBegin;
808   for (i=0; i<bA->nr; i++) {
809     for (j=0; j<bA->nc; j++) {
810       if (bA->m[i][j]) {
811         PetscCall(MatScale(bA->m[i][j],a));
812       }
813     }
814   }
815   PetscFunctionReturn(0);
816 }
817 
818 static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
819 {
820   Mat_Nest       *bA = (Mat_Nest*)A->data;
821   PetscInt       i;
822   PetscBool      nnzstate = PETSC_FALSE;
823 
824   PetscFunctionBegin;
825   for (i=0; i<bA->nr; i++) {
826     PetscObjectState subnnzstate = 0;
827     PetscCheckFalse(!bA->m[i][i],PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%" PetscInt_FMT ",%" PetscInt_FMT ")",i,i);
828     PetscCall(MatShift(bA->m[i][i],a));
829     PetscCall(MatGetNonzeroState(bA->m[i][i],&subnnzstate));
830     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
831     bA->nnzstate[i*bA->nc+i] = subnnzstate;
832   }
833   if (nnzstate) A->nonzerostate++;
834   PetscFunctionReturn(0);
835 }
836 
837 static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
838 {
839   Mat_Nest       *bA = (Mat_Nest*)A->data;
840   PetscInt       i;
841   PetscBool      nnzstate = PETSC_FALSE;
842 
843   PetscFunctionBegin;
844   for (i=0; i<bA->nr; i++) {
845     PetscObjectState subnnzstate = 0;
846     Vec              bv;
847     PetscCall(VecGetSubVector(D,bA->isglobal.row[i],&bv));
848     if (bA->m[i][i]) {
849       PetscCall(MatDiagonalSet(bA->m[i][i],bv,is));
850       PetscCall(MatGetNonzeroState(bA->m[i][i],&subnnzstate));
851     }
852     PetscCall(VecRestoreSubVector(D,bA->isglobal.row[i],&bv));
853     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
854     bA->nnzstate[i*bA->nc+i] = subnnzstate;
855   }
856   if (nnzstate) A->nonzerostate++;
857   PetscFunctionReturn(0);
858 }
859 
860 static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
861 {
862   Mat_Nest       *bA = (Mat_Nest*)A->data;
863   PetscInt       i,j;
864 
865   PetscFunctionBegin;
866   for (i=0; i<bA->nr; i++) {
867     for (j=0; j<bA->nc; j++) {
868       if (bA->m[i][j]) {
869         PetscCall(MatSetRandom(bA->m[i][j],rctx));
870       }
871     }
872   }
873   PetscFunctionReturn(0);
874 }
875 
876 static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
877 {
878   Mat_Nest       *bA = (Mat_Nest*)A->data;
879   Vec            *L,*R;
880   MPI_Comm       comm;
881   PetscInt       i,j;
882 
883   PetscFunctionBegin;
884   PetscCall(PetscObjectGetComm((PetscObject)A,&comm));
885   if (right) {
886     /* allocate R */
887     PetscCall(PetscMalloc1(bA->nc, &R));
888     /* Create the right vectors */
889     for (j=0; j<bA->nc; j++) {
890       for (i=0; i<bA->nr; i++) {
891         if (bA->m[i][j]) {
892           PetscCall(MatCreateVecs(bA->m[i][j],&R[j],NULL));
893           break;
894         }
895       }
896       PetscCheckFalse(i==bA->nr,PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
897     }
898     PetscCall(VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right));
899     /* hand back control to the nest vector */
900     for (j=0; j<bA->nc; j++) {
901       PetscCall(VecDestroy(&R[j]));
902     }
903     PetscCall(PetscFree(R));
904   }
905 
906   if (left) {
907     /* allocate L */
908     PetscCall(PetscMalloc1(bA->nr, &L));
909     /* Create the left vectors */
910     for (i=0; i<bA->nr; i++) {
911       for (j=0; j<bA->nc; j++) {
912         if (bA->m[i][j]) {
913           PetscCall(MatCreateVecs(bA->m[i][j],NULL,&L[i]));
914           break;
915         }
916       }
917       PetscCheckFalse(j==bA->nc,PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
918     }
919 
920     PetscCall(VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left));
921     for (i=0; i<bA->nr; i++) {
922       PetscCall(VecDestroy(&L[i]));
923     }
924 
925     PetscCall(PetscFree(L));
926   }
927   PetscFunctionReturn(0);
928 }
929 
930 static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
931 {
932   Mat_Nest       *bA = (Mat_Nest*)A->data;
933   PetscBool      isascii,viewSub = PETSC_FALSE;
934   PetscInt       i,j;
935 
936   PetscFunctionBegin;
937   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
938   if (isascii) {
939 
940     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL));
941     PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix object: \n"));
942     PetscCall(PetscViewerASCIIPushTab(viewer));
943     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n",bA->nr,bA->nc));
944 
945     PetscCall(PetscViewerASCIIPrintf(viewer,"MatNest structure: \n"));
946     for (i=0; i<bA->nr; i++) {
947       for (j=0; j<bA->nc; j++) {
948         MatType   type;
949         char      name[256] = "",prefix[256] = "";
950         PetscInt  NR,NC;
951         PetscBool isNest = PETSC_FALSE;
952 
953         if (!bA->m[i][j]) {
954           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n",i,j));
955           continue;
956         }
957         PetscCall(MatGetSize(bA->m[i][j],&NR,&NC));
958         PetscCall(MatGetType(bA->m[i][j], &type));
959         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name));
960         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix));
961         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest));
962 
963         PetscCall(PetscViewerASCIIPrintf(viewer,"(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n",i,j,name,prefix,type,NR,NC));
964 
965         if (isNest || viewSub) {
966           PetscCall(PetscViewerASCIIPushTab(viewer));  /* push1 */
967           PetscCall(MatView(bA->m[i][j],viewer));
968           PetscCall(PetscViewerASCIIPopTab(viewer));    /* pop1 */
969         }
970       }
971     }
972     PetscCall(PetscViewerASCIIPopTab(viewer));    /* pop0 */
973   }
974   PetscFunctionReturn(0);
975 }
976 
977 static PetscErrorCode MatZeroEntries_Nest(Mat A)
978 {
979   Mat_Nest       *bA = (Mat_Nest*)A->data;
980   PetscInt       i,j;
981 
982   PetscFunctionBegin;
983   for (i=0; i<bA->nr; i++) {
984     for (j=0; j<bA->nc; j++) {
985       if (!bA->m[i][j]) continue;
986       PetscCall(MatZeroEntries(bA->m[i][j]));
987     }
988   }
989   PetscFunctionReturn(0);
990 }
991 
992 static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
993 {
994   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
995   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
996   PetscBool      nnzstate = PETSC_FALSE;
997 
998   PetscFunctionBegin;
999   PetscCheckFalse(nr != bB->nr || nc != bB->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot copy a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") to a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")",bB->nr,bB->nc,nr,nc);
1000   for (i=0; i<nr; i++) {
1001     for (j=0; j<nc; j++) {
1002       PetscObjectState subnnzstate = 0;
1003       if (bA->m[i][j] && bB->m[i][j]) {
1004         PetscCall(MatCopy(bA->m[i][j],bB->m[i][j],str));
1005       } else PetscCheckFalse(bA->m[i][j] || bB->m[i][j],PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT,i,j);
1006       PetscCall(MatGetNonzeroState(bB->m[i][j],&subnnzstate));
1007       nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i*nc+j] != subnnzstate);
1008       bB->nnzstate[i*nc+j] = subnnzstate;
1009     }
1010   }
1011   if (nnzstate) B->nonzerostate++;
1012   PetscFunctionReturn(0);
1013 }
1014 
1015 static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
1016 {
1017   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
1018   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
1019   PetscBool      nnzstate = PETSC_FALSE;
1020 
1021   PetscFunctionBegin;
1022   PetscCheckFalse(nr != bX->nr || nc != bX->nc,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Cannot AXPY a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") with a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")",bX->nr,bX->nc,nr,nc);
1023   for (i=0; i<nr; i++) {
1024     for (j=0; j<nc; j++) {
1025       PetscObjectState subnnzstate = 0;
1026       if (bY->m[i][j] && bX->m[i][j]) {
1027         PetscCall(MatAXPY(bY->m[i][j],a,bX->m[i][j],str));
1028       } else if (bX->m[i][j]) {
1029         Mat M;
1030 
1031         PetscCheckFalse(str != DIFFERENT_NONZERO_PATTERN,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN",i,j);
1032         PetscCall(MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M));
1033         PetscCall(MatNestSetSubMat(Y,i,j,M));
1034         PetscCall(MatDestroy(&M));
1035       }
1036       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j],&subnnzstate));
1037       nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i*nc+j] != subnnzstate);
1038       bY->nnzstate[i*nc+j] = subnnzstate;
1039     }
1040   }
1041   if (nnzstate) Y->nonzerostate++;
1042   PetscFunctionReturn(0);
1043 }
1044 
1045 static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
1046 {
1047   Mat_Nest       *bA = (Mat_Nest*)A->data;
1048   Mat            *b;
1049   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
1050 
1051   PetscFunctionBegin;
1052   PetscCall(PetscMalloc1(nr*nc,&b));
1053   for (i=0; i<nr; i++) {
1054     for (j=0; j<nc; j++) {
1055       if (bA->m[i][j]) {
1056         PetscCall(MatDuplicate(bA->m[i][j],op,&b[i*nc+j]));
1057       } else {
1058         b[i*nc+j] = NULL;
1059       }
1060     }
1061   }
1062   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B));
1063   /* Give the new MatNest exclusive ownership */
1064   for (i=0; i<nr*nc; i++) {
1065     PetscCall(MatDestroy(&b[i]));
1066   }
1067   PetscCall(PetscFree(b));
1068 
1069   PetscCall(MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY));
1070   PetscCall(MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY));
1071   PetscFunctionReturn(0);
1072 }
1073 
1074 /* nest api */
1075 PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
1076 {
1077   Mat_Nest *bA = (Mat_Nest*)A->data;
1078 
1079   PetscFunctionBegin;
1080   PetscCheckFalse(idxm >= bA->nr,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT,idxm,bA->nr-1);
1081   PetscCheckFalse(jdxm >= bA->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT,jdxm,bA->nc-1);
1082   *mat = bA->m[idxm][jdxm];
1083   PetscFunctionReturn(0);
1084 }
1085 
1086 /*@
1087  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
1088 
1089  Not collective
1090 
1091  Input Parameters:
1092 +   A  - nest matrix
1093 .   idxm - index of the matrix within the nest matrix
1094 -   jdxm - index of the matrix within the nest matrix
1095 
1096  Output Parameter:
1097 .   sub - matrix at index idxm,jdxm within the nest matrix
1098 
1099  Level: developer
1100 
1101 .seealso: MatNestGetSize(), MatNestGetSubMats(), MatCreateNest(), MATNEST, MatNestSetSubMat(),
1102           MatNestGetLocalISs(), MatNestGetISs()
1103 @*/
1104 PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
1105 {
1106   PetscFunctionBegin;
1107   PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));
1108   PetscFunctionReturn(0);
1109 }
1110 
1111 PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
1112 {
1113   Mat_Nest       *bA = (Mat_Nest*)A->data;
1114   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
1115 
1116   PetscFunctionBegin;
1117   PetscCheckFalse(idxm >= bA->nr,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT,idxm,bA->nr-1);
1118   PetscCheckFalse(jdxm >= bA->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT,jdxm,bA->nc-1);
1119   PetscCall(MatGetLocalSize(mat,&m,&n));
1120   PetscCall(MatGetSize(mat,&M,&N));
1121   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm],&mi));
1122   PetscCall(ISGetSize(bA->isglobal.row[idxm],&Mi));
1123   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm],&ni));
1124   PetscCall(ISGetSize(bA->isglobal.col[jdxm],&Ni));
1125   PetscCheckFalse(M != Mi || N != Ni,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")",M,N,Mi,Ni);
1126   PetscCheckFalse(m != mi || n != ni,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")",m,n,mi,ni);
1127 
1128   /* do not increase object state */
1129   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
1130 
1131   PetscCall(PetscObjectReference((PetscObject)mat));
1132   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
1133   bA->m[idxm][jdxm] = mat;
1134   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1135   PetscCall(MatGetNonzeroState(mat,&bA->nnzstate[idxm*bA->nc+jdxm]));
1136   A->nonzerostate++;
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 /*@
1141  MatNestSetSubMat - Set a single submatrix in the nest matrix.
1142 
1143  Logically collective on the submatrix communicator
1144 
1145  Input Parameters:
1146 +   A  - nest matrix
1147 .   idxm - index of the matrix within the nest matrix
1148 .   jdxm - index of the matrix within the nest matrix
1149 -   sub - matrix at index idxm,jdxm within the nest matrix
1150 
1151  Notes:
1152  The new submatrix must have the same size and communicator as that block of the nest.
1153 
1154  This increments the reference count of the submatrix.
1155 
1156  Level: developer
1157 
1158 .seealso: MatNestSetSubMats(), MatNestGetSubMats(), MatNestGetLocalISs(), MATNEST, MatCreateNest(),
1159           MatNestGetSubMat(), MatNestGetISs(), MatNestGetSize()
1160 @*/
1161 PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
1162 {
1163   PetscFunctionBegin;
1164   PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));
1165   PetscFunctionReturn(0);
1166 }
1167 
1168 PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1169 {
1170   Mat_Nest *bA = (Mat_Nest*)A->data;
1171 
1172   PetscFunctionBegin;
1173   if (M)   *M   = bA->nr;
1174   if (N)   *N   = bA->nc;
1175   if (mat) *mat = bA->m;
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 /*@C
1180  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
1181 
1182  Not collective
1183 
1184  Input Parameter:
1185 .   A  - nest matrix
1186 
1187  Output Parameters:
1188 +   M - number of rows in the nest matrix
1189 .   N - number of cols in the nest matrix
1190 -   mat - 2d array of matrices
1191 
1192  Notes:
1193 
1194  The user should not free the array mat.
1195 
1196  In Fortran, this routine has a calling sequence
1197 $   call MatNestGetSubMats(A, M, N, mat, ierr)
1198  where the space allocated for the optional argument mat is assumed large enough (if provided).
1199 
1200  Level: developer
1201 
1202 .seealso: MatNestGetSize(), MatNestGetSubMat(), MatNestGetLocalISs(), MATNEST, MatCreateNest(),
1203           MatNestSetSubMats(), MatNestGetISs(), MatNestSetSubMat()
1204 @*/
1205 PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1206 {
1207   PetscFunctionBegin;
1208   PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));
1209   PetscFunctionReturn(0);
1210 }
1211 
1212 PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
1213 {
1214   Mat_Nest *bA = (Mat_Nest*)A->data;
1215 
1216   PetscFunctionBegin;
1217   if (M) *M = bA->nr;
1218   if (N) *N = bA->nc;
1219   PetscFunctionReturn(0);
1220 }
1221 
1222 /*@
1223  MatNestGetSize - Returns the size of the nest matrix.
1224 
1225  Not collective
1226 
1227  Input Parameter:
1228 .   A  - nest matrix
1229 
1230  Output Parameters:
1231 +   M - number of rows in the nested mat
1232 -   N - number of cols in the nested mat
1233 
1234  Notes:
1235 
1236  Level: developer
1237 
1238 .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MATNEST, MatCreateNest(), MatNestGetLocalISs(),
1239           MatNestGetISs()
1240 @*/
1241 PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1242 {
1243   PetscFunctionBegin;
1244   PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));
1245   PetscFunctionReturn(0);
1246 }
1247 
1248 static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1249 {
1250   Mat_Nest *vs = (Mat_Nest*)A->data;
1251   PetscInt i;
1252 
1253   PetscFunctionBegin;
1254   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1255   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1256   PetscFunctionReturn(0);
1257 }
1258 
1259 /*@C
1260  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1261 
1262  Not collective
1263 
1264  Input Parameter:
1265 .   A  - nest matrix
1266 
1267  Output Parameters:
1268 +   rows - array of row index sets
1269 -   cols - array of column index sets
1270 
1271  Level: advanced
1272 
1273  Notes:
1274  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1275 
1276 .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs(), MATNEST,
1277           MatCreateNest(), MatNestGetSubMats(), MatNestSetSubMats()
1278 @*/
1279 PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1280 {
1281   PetscFunctionBegin;
1282   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1283   PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));
1284   PetscFunctionReturn(0);
1285 }
1286 
1287 static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1288 {
1289   Mat_Nest *vs = (Mat_Nest*)A->data;
1290   PetscInt i;
1291 
1292   PetscFunctionBegin;
1293   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1294   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1295   PetscFunctionReturn(0);
1296 }
1297 
1298 /*@C
1299  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1300 
1301  Not collective
1302 
1303  Input Parameter:
1304 .   A  - nest matrix
1305 
1306  Output Parameters:
1307 +   rows - array of row index sets (or NULL to ignore)
1308 -   cols - array of column index sets (or NULL to ignore)
1309 
1310  Level: advanced
1311 
1312  Notes:
1313  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1314 
1315 .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs(), MatCreateNest(),
1316           MATNEST, MatNestSetSubMats(), MatNestSetSubMat()
1317 @*/
1318 PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1319 {
1320   PetscFunctionBegin;
1321   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1322   PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1327 {
1328   PetscBool      flg;
1329 
1330   PetscFunctionBegin;
1331   PetscCall(PetscStrcmp(vtype,VECNEST,&flg));
1332   /* In reality, this only distinguishes VECNEST and "other" */
1333   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
1334   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1335   PetscFunctionReturn(0);
1336 }
1337 
1338 /*@C
1339  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1340 
1341  Not collective
1342 
1343  Input Parameters:
1344 +  A  - nest matrix
1345 -  vtype - type to use for creating vectors
1346 
1347  Notes:
1348 
1349  Level: developer
1350 
1351 .seealso: MatCreateVecs(), MATNEST, MatCreateNest()
1352 @*/
1353 PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1354 {
1355   PetscFunctionBegin;
1356   PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1361 {
1362   Mat_Nest       *s = (Mat_Nest*)A->data;
1363   PetscInt       i,j,m,n,M,N;
1364   PetscBool      cong,isstd,sametype=PETSC_FALSE;
1365   VecType        vtype,type;
1366 
1367   PetscFunctionBegin;
1368   PetscCall(MatReset_Nest(A));
1369 
1370   s->nr = nr;
1371   s->nc = nc;
1372 
1373   /* Create space for submatrices */
1374   PetscCall(PetscMalloc1(nr,&s->m));
1375   for (i=0; i<nr; i++) {
1376     PetscCall(PetscMalloc1(nc,&s->m[i]));
1377   }
1378   for (i=0; i<nr; i++) {
1379     for (j=0; j<nc; j++) {
1380       s->m[i][j] = a[i*nc+j];
1381       if (a[i*nc+j]) {
1382         PetscCall(PetscObjectReference((PetscObject)a[i*nc+j]));
1383       }
1384     }
1385   }
1386   PetscCall(MatGetVecType(A,&vtype));
1387   PetscCall(PetscStrcmp(vtype,VECSTANDARD,&isstd));
1388   if (isstd) {
1389     /* check if all blocks have the same vectype */
1390     vtype = NULL;
1391     for (i=0; i<nr; i++) {
1392       for (j=0; j<nc; j++) {
1393         if (a[i*nc+j]) {
1394           if (!vtype) {  /* first visited block */
1395             PetscCall(MatGetVecType(a[i*nc+j],&vtype));
1396             sametype = PETSC_TRUE;
1397           } else if (sametype) {
1398             PetscCall(MatGetVecType(a[i*nc+j],&type));
1399             PetscCall(PetscStrcmp(vtype,type,&sametype));
1400           }
1401         }
1402       }
1403     }
1404     if (sametype) {  /* propagate vectype */
1405       PetscCall(MatSetVecType(A,vtype));
1406     }
1407   }
1408 
1409   PetscCall(MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col));
1410 
1411   PetscCall(PetscMalloc1(nr,&s->row_len));
1412   PetscCall(PetscMalloc1(nc,&s->col_len));
1413   for (i=0; i<nr; i++) s->row_len[i]=-1;
1414   for (j=0; j<nc; j++) s->col_len[j]=-1;
1415 
1416   PetscCall(PetscCalloc1(nr*nc,&s->nnzstate));
1417   for (i=0; i<nr; i++) {
1418     for (j=0; j<nc; j++) {
1419       if (s->m[i][j]) {
1420         PetscCall(MatGetNonzeroState(s->m[i][j],&s->nnzstate[i*nc+j]));
1421       }
1422     }
1423   }
1424 
1425   PetscCall(MatNestGetSizes_Private(A,&m,&n,&M,&N));
1426 
1427   PetscCall(PetscLayoutSetSize(A->rmap,M));
1428   PetscCall(PetscLayoutSetLocalSize(A->rmap,m));
1429   PetscCall(PetscLayoutSetSize(A->cmap,N));
1430   PetscCall(PetscLayoutSetLocalSize(A->cmap,n));
1431 
1432   PetscCall(PetscLayoutSetUp(A->rmap));
1433   PetscCall(PetscLayoutSetUp(A->cmap));
1434 
1435   /* disable operations that are not supported for non-square matrices,
1436      or matrices for which is_row != is_col  */
1437   PetscCall(MatHasCongruentLayouts(A,&cong));
1438   if (cong && nr != nc) cong = PETSC_FALSE;
1439   if (cong) {
1440     for (i = 0; cong && i < nr; i++) {
1441       PetscCall(ISEqualUnsorted(s->isglobal.row[i],s->isglobal.col[i],&cong));
1442     }
1443   }
1444   if (!cong) {
1445     A->ops->missingdiagonal = NULL;
1446     A->ops->getdiagonal     = NULL;
1447     A->ops->shift           = NULL;
1448     A->ops->diagonalset     = NULL;
1449   }
1450 
1451   PetscCall(PetscCalloc2(nr,&s->left,nc,&s->right));
1452   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1453   A->nonzerostate++;
1454   PetscFunctionReturn(0);
1455 }
1456 
1457 /*@
1458    MatNestSetSubMats - Sets the nested submatrices
1459 
1460    Collective on Mat
1461 
1462    Input Parameters:
1463 +  A - nested matrix
1464 .  nr - number of nested row blocks
1465 .  is_row - index sets for each nested row block, or NULL to make contiguous
1466 .  nc - number of nested column blocks
1467 .  is_col - index sets for each nested column block, or NULL to make contiguous
1468 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1469 
1470    Notes: this always resets any submatrix information previously set
1471 
1472    Level: advanced
1473 
1474 .seealso: MatCreateNest(), MATNEST, MatNestSetSubMat(), MatNestGetSubMat(), MatNestGetSubMats()
1475 @*/
1476 PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1477 {
1478   PetscInt       i;
1479 
1480   PetscFunctionBegin;
1481   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1482   PetscCheckFalse(nr < 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1483   if (nr && is_row) {
1484     PetscValidPointer(is_row,3);
1485     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1486   }
1487   PetscCheckFalse(nc < 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
1488   if (nc && is_col) {
1489     PetscValidPointer(is_col,5);
1490     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1491   }
1492   if (nr*nc > 0) PetscValidPointer(a,6);
1493   PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));
1494   PetscFunctionReturn(0);
1495 }
1496 
1497 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
1498 {
1499   PetscBool      flg;
1500   PetscInt       i,j,m,mi,*ix;
1501 
1502   PetscFunctionBegin;
1503   *ltog = NULL;
1504   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
1505     if (islocal[i]) {
1506       PetscCall(ISGetLocalSize(islocal[i],&mi));
1507       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
1508     } else {
1509       PetscCall(ISGetLocalSize(isglobal[i],&mi));
1510     }
1511     m += mi;
1512   }
1513   if (!flg) PetscFunctionReturn(0);
1514 
1515   PetscCall(PetscMalloc1(m,&ix));
1516   for (i=0,m=0; i<n; i++) {
1517     ISLocalToGlobalMapping smap = NULL;
1518     Mat                    sub = NULL;
1519     PetscSF                sf;
1520     PetscLayout            map;
1521     const PetscInt         *ix2;
1522 
1523     if (!colflg) {
1524       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
1525     } else {
1526       PetscCall(MatNestFindNonzeroSubMatCol(A,i,&sub));
1527     }
1528     if (sub) {
1529       if (!colflg) {
1530         PetscCall(MatGetLocalToGlobalMapping(sub,&smap,NULL));
1531       } else {
1532         PetscCall(MatGetLocalToGlobalMapping(sub,NULL,&smap));
1533       }
1534     }
1535     /*
1536        Now we need to extract the monolithic global indices that correspond to the given split global indices.
1537        In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1538     */
1539     PetscCall(ISGetIndices(isglobal[i],&ix2));
1540     if (islocal[i]) {
1541       PetscInt *ilocal,*iremote;
1542       PetscInt mil,nleaves;
1543 
1544       PetscCall(ISGetLocalSize(islocal[i],&mi));
1545       PetscCheck(smap,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing local to global map");
1546       for (j=0; j<mi; j++) ix[m+j] = j;
1547       PetscCall(ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m));
1548 
1549       /* PetscSFSetGraphLayout does not like negative indices */
1550       PetscCall(PetscMalloc2(mi,&ilocal,mi,&iremote));
1551       for (j=0, nleaves = 0; j<mi; j++) {
1552         if (ix[m+j] < 0) continue;
1553         ilocal[nleaves]  = j;
1554         iremote[nleaves] = ix[m+j];
1555         nleaves++;
1556       }
1557       PetscCall(ISGetLocalSize(isglobal[i],&mil));
1558       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A),&sf));
1559       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A),&map));
1560       PetscCall(PetscLayoutSetLocalSize(map,mil));
1561       PetscCall(PetscLayoutSetUp(map));
1562       PetscCall(PetscSFSetGraphLayout(sf,map,nleaves,ilocal,PETSC_USE_POINTER,iremote));
1563       PetscCall(PetscLayoutDestroy(&map));
1564       PetscCall(PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m,MPI_REPLACE));
1565       PetscCall(PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m,MPI_REPLACE));
1566       PetscCall(PetscSFDestroy(&sf));
1567       PetscCall(PetscFree2(ilocal,iremote));
1568     } else {
1569       PetscCall(ISGetLocalSize(isglobal[i],&mi));
1570       for (j=0; j<mi; j++) ix[m+j] = ix2[i];
1571     }
1572     PetscCall(ISRestoreIndices(isglobal[i],&ix2));
1573     m   += mi;
1574   }
1575   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog));
1576   PetscFunctionReturn(0);
1577 }
1578 
1579 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1580 /*
1581   nprocessors = NP
1582   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1583        proc 0: => (g_0,h_0,)
1584        proc 1: => (g_1,h_1,)
1585        ...
1586        proc nprocs-1: => (g_NP-1,h_NP-1,)
1587 
1588             proc 0:                      proc 1:                    proc nprocs-1:
1589     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1590 
1591             proc 0:
1592     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1593             proc 1:
1594     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1595 
1596             proc NP-1:
1597     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1598 */
1599 static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1600 {
1601   Mat_Nest       *vs = (Mat_Nest*)A->data;
1602   PetscInt       i,j,offset,n,nsum,bs;
1603   Mat            sub = NULL;
1604 
1605   PetscFunctionBegin;
1606   PetscCall(PetscMalloc1(nr,&vs->isglobal.row));
1607   PetscCall(PetscMalloc1(nc,&vs->isglobal.col));
1608   if (is_row) { /* valid IS is passed in */
1609     /* refs on is[] are incremented */
1610     for (i=0; i<vs->nr; i++) {
1611       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1612 
1613       vs->isglobal.row[i] = is_row[i];
1614     }
1615   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
1616     nsum = 0;
1617     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
1618       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
1619       PetscCheck(sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %" PetscInt_FMT,i);
1620       PetscCall(MatGetLocalSize(sub,&n,NULL));
1621       PetscCheckFalse(n < 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1622       nsum += n;
1623     }
1624     PetscCallMPI(MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A)));
1625     offset -= nsum;
1626     for (i=0; i<vs->nr; i++) {
1627       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
1628       PetscCall(MatGetLocalSize(sub,&n,NULL));
1629       PetscCall(MatGetBlockSizes(sub,&bs,NULL));
1630       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]));
1631       PetscCall(ISSetBlockSize(vs->isglobal.row[i],bs));
1632       offset += n;
1633     }
1634   }
1635 
1636   if (is_col) { /* valid IS is passed in */
1637     /* refs on is[] are incremented */
1638     for (j=0; j<vs->nc; j++) {
1639       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1640 
1641       vs->isglobal.col[j] = is_col[j];
1642     }
1643   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
1644     offset = A->cmap->rstart;
1645     nsum   = 0;
1646     for (j=0; j<vs->nc; j++) {
1647       PetscCall(MatNestFindNonzeroSubMatCol(A,j,&sub));
1648       PetscCheck(sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %" PetscInt_FMT,i);
1649       PetscCall(MatGetLocalSize(sub,NULL,&n));
1650       PetscCheckFalse(n < 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
1651       nsum += n;
1652     }
1653     PetscCallMPI(MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A)));
1654     offset -= nsum;
1655     for (j=0; j<vs->nc; j++) {
1656       PetscCall(MatNestFindNonzeroSubMatCol(A,j,&sub));
1657       PetscCall(MatGetLocalSize(sub,NULL,&n));
1658       PetscCall(MatGetBlockSizes(sub,NULL,&bs));
1659       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]));
1660       PetscCall(ISSetBlockSize(vs->isglobal.col[j],bs));
1661       offset += n;
1662     }
1663   }
1664 
1665   /* Set up the local ISs */
1666   PetscCall(PetscMalloc1(vs->nr,&vs->islocal.row));
1667   PetscCall(PetscMalloc1(vs->nc,&vs->islocal.col));
1668   for (i=0,offset=0; i<vs->nr; i++) {
1669     IS                     isloc;
1670     ISLocalToGlobalMapping rmap = NULL;
1671     PetscInt               nlocal,bs;
1672     PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
1673     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub,&rmap,NULL));
1674     if (rmap) {
1675       PetscCall(MatGetBlockSizes(sub,&bs,NULL));
1676       PetscCall(ISLocalToGlobalMappingGetSize(rmap,&nlocal));
1677       PetscCall(ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc));
1678       PetscCall(ISSetBlockSize(isloc,bs));
1679     } else {
1680       nlocal = 0;
1681       isloc  = NULL;
1682     }
1683     vs->islocal.row[i] = isloc;
1684     offset            += nlocal;
1685   }
1686   for (i=0,offset=0; i<vs->nc; i++) {
1687     IS                     isloc;
1688     ISLocalToGlobalMapping cmap = NULL;
1689     PetscInt               nlocal,bs;
1690     PetscCall(MatNestFindNonzeroSubMatCol(A,i,&sub));
1691     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub,NULL,&cmap));
1692     if (cmap) {
1693       PetscCall(MatGetBlockSizes(sub,NULL,&bs));
1694       PetscCall(ISLocalToGlobalMappingGetSize(cmap,&nlocal));
1695       PetscCall(ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc));
1696       PetscCall(ISSetBlockSize(isloc,bs));
1697     } else {
1698       nlocal = 0;
1699       isloc  = NULL;
1700     }
1701     vs->islocal.col[i] = isloc;
1702     offset            += nlocal;
1703   }
1704 
1705   /* Set up the aggregate ISLocalToGlobalMapping */
1706   {
1707     ISLocalToGlobalMapping rmap,cmap;
1708     PetscCall(MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap));
1709     PetscCall(MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap));
1710     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A,rmap,cmap));
1711     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
1712     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
1713   }
1714 
1715   if (PetscDefined(USE_DEBUG)) {
1716     for (i=0; i<vs->nr; i++) {
1717       for (j=0; j<vs->nc; j++) {
1718         PetscInt m,n,M,N,mi,ni,Mi,Ni;
1719         Mat      B = vs->m[i][j];
1720         if (!B) continue;
1721         PetscCall(MatGetSize(B,&M,&N));
1722         PetscCall(MatGetLocalSize(B,&m,&n));
1723         PetscCall(ISGetSize(vs->isglobal.row[i],&Mi));
1724         PetscCall(ISGetSize(vs->isglobal.col[j],&Ni));
1725         PetscCall(ISGetLocalSize(vs->isglobal.row[i],&mi));
1726         PetscCall(ISGetLocalSize(vs->isglobal.col[j],&ni));
1727         PetscCheckFalse(M != Mi || N != Ni,PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Global sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")",M,N,i,j,Mi,Ni);
1728         PetscCheckFalse(m != mi || n != ni,PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Local sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")",m,n,i,j,mi,ni);
1729       }
1730     }
1731   }
1732 
1733   /* Set A->assembled if all non-null blocks are currently assembled */
1734   for (i=0; i<vs->nr; i++) {
1735     for (j=0; j<vs->nc; j++) {
1736       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1737     }
1738   }
1739   A->assembled = PETSC_TRUE;
1740   PetscFunctionReturn(0);
1741 }
1742 
1743 /*@C
1744    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1745 
1746    Collective on Mat
1747 
1748    Input Parameters:
1749 +  comm - Communicator for the new Mat
1750 .  nr - number of nested row blocks
1751 .  is_row - index sets for each nested row block, or NULL to make contiguous
1752 .  nc - number of nested column blocks
1753 .  is_col - index sets for each nested column block, or NULL to make contiguous
1754 -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1755 
1756    Output Parameter:
1757 .  B - new matrix
1758 
1759    Level: advanced
1760 
1761 .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST, MatNestSetSubMat(),
1762           MatNestGetSubMat(), MatNestGetLocalISs(), MatNestGetSize(),
1763           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
1764 @*/
1765 PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1766 {
1767   Mat            A;
1768 
1769   PetscFunctionBegin;
1770   *B   = NULL;
1771   PetscCall(MatCreate(comm,&A));
1772   PetscCall(MatSetType(A,MATNEST));
1773   A->preallocated = PETSC_TRUE;
1774   PetscCall(MatNestSetSubMats(A,nr,is_row,nc,is_col,a));
1775   *B   = A;
1776   PetscFunctionReturn(0);
1777 }
1778 
1779 PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1780 {
1781   Mat_Nest       *nest = (Mat_Nest*)A->data;
1782   Mat            *trans;
1783   PetscScalar    **avv;
1784   PetscScalar    *vv;
1785   PetscInt       **aii,**ajj;
1786   PetscInt       *ii,*jj,*ci;
1787   PetscInt       nr,nc,nnz,i,j;
1788   PetscBool      done;
1789 
1790   PetscFunctionBegin;
1791   PetscCall(MatGetSize(A,&nr,&nc));
1792   if (reuse == MAT_REUSE_MATRIX) {
1793     PetscInt rnr;
1794 
1795     PetscCall(MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done));
1796     PetscCheck(done,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1797     PetscCheckFalse(rnr != nr,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1798     PetscCall(MatSeqAIJGetArray(*newmat,&vv));
1799   }
1800   /* extract CSR for nested SeqAIJ matrices */
1801   nnz  = 0;
1802   PetscCall(PetscCalloc4(nest->nr*nest->nc,&aii,nest->nr*nest->nc,&ajj,nest->nr*nest->nc,&avv,nest->nr*nest->nc,&trans));
1803   for (i=0; i<nest->nr; ++i) {
1804     for (j=0; j<nest->nc; ++j) {
1805       Mat B = nest->m[i][j];
1806       if (B) {
1807         PetscScalar *naa;
1808         PetscInt    *nii,*njj,nnr;
1809         PetscBool   istrans;
1810 
1811         PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans));
1812         if (istrans) {
1813           Mat Bt;
1814 
1815           PetscCall(MatTransposeGetMat(B,&Bt));
1816           PetscCall(MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]));
1817           B    = trans[i*nest->nc+j];
1818         }
1819         PetscCall(MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done));
1820         PetscCheck(done,PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1821         PetscCall(MatSeqAIJGetArray(B,&naa));
1822         nnz += nii[nnr];
1823 
1824         aii[i*nest->nc+j] = nii;
1825         ajj[i*nest->nc+j] = njj;
1826         avv[i*nest->nc+j] = naa;
1827       }
1828     }
1829   }
1830   if (reuse != MAT_REUSE_MATRIX) {
1831     PetscCall(PetscMalloc1(nr+1,&ii));
1832     PetscCall(PetscMalloc1(nnz,&jj));
1833     PetscCall(PetscMalloc1(nnz,&vv));
1834   } else {
1835     PetscCheckFalse(nnz != ii[nr],PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1836   }
1837 
1838   /* new row pointer */
1839   PetscCall(PetscArrayzero(ii,nr+1));
1840   for (i=0; i<nest->nr; ++i) {
1841     PetscInt       ncr,rst;
1842 
1843     PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL));
1844     PetscCall(ISGetLocalSize(nest->isglobal.row[i],&ncr));
1845     for (j=0; j<nest->nc; ++j) {
1846       if (aii[i*nest->nc+j]) {
1847         PetscInt    *nii = aii[i*nest->nc+j];
1848         PetscInt    ir;
1849 
1850         for (ir=rst; ir<ncr+rst; ++ir) {
1851           ii[ir+1] += nii[1]-nii[0];
1852           nii++;
1853         }
1854       }
1855     }
1856   }
1857   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1858 
1859   /* construct CSR for the new matrix */
1860   PetscCall(PetscCalloc1(nr,&ci));
1861   for (i=0; i<nest->nr; ++i) {
1862     PetscInt       ncr,rst;
1863 
1864     PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL));
1865     PetscCall(ISGetLocalSize(nest->isglobal.row[i],&ncr));
1866     for (j=0; j<nest->nc; ++j) {
1867       if (aii[i*nest->nc+j]) {
1868         PetscScalar *nvv = avv[i*nest->nc+j];
1869         PetscInt    *nii = aii[i*nest->nc+j];
1870         PetscInt    *njj = ajj[i*nest->nc+j];
1871         PetscInt    ir,cst;
1872 
1873         PetscCall(ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL));
1874         for (ir=rst; ir<ncr+rst; ++ir) {
1875           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1876 
1877           for (ij=0;ij<rsize;ij++) {
1878             jj[ist+ij] = *njj+cst;
1879             vv[ist+ij] = *nvv;
1880             njj++;
1881             nvv++;
1882           }
1883           ci[ir] += rsize;
1884           nii++;
1885         }
1886       }
1887     }
1888   }
1889   PetscCall(PetscFree(ci));
1890 
1891   /* restore info */
1892   for (i=0; i<nest->nr; ++i) {
1893     for (j=0; j<nest->nc; ++j) {
1894       Mat B = nest->m[i][j];
1895       if (B) {
1896         PetscInt nnr = 0, k = i*nest->nc+j;
1897 
1898         B    = (trans[k] ? trans[k] : B);
1899         PetscCall(MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done));
1900         PetscCheck(done,PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1901         PetscCall(MatSeqAIJRestoreArray(B,&avv[k]));
1902         PetscCall(MatDestroy(&trans[k]));
1903       }
1904     }
1905   }
1906   PetscCall(PetscFree4(aii,ajj,avv,trans));
1907 
1908   /* finalize newmat */
1909   if (reuse == MAT_INITIAL_MATRIX) {
1910     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat));
1911   } else if (reuse == MAT_INPLACE_MATRIX) {
1912     Mat B;
1913 
1914     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B));
1915     PetscCall(MatHeaderReplace(A,&B));
1916   }
1917   PetscCall(MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY));
1918   PetscCall(MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY));
1919   {
1920     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1921     a->free_a     = PETSC_TRUE;
1922     a->free_ij    = PETSC_TRUE;
1923   }
1924   PetscFunctionReturn(0);
1925 }
1926 
1927 PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y,PetscScalar a,Mat X)
1928 {
1929   Mat_Nest       *nest = (Mat_Nest*)X->data;
1930   PetscInt       i,j,k,rstart;
1931   PetscBool      flg;
1932 
1933   PetscFunctionBegin;
1934   /* Fill by row */
1935   for (j=0; j<nest->nc; ++j) {
1936     /* Using global column indices and ISAllGather() is not scalable. */
1937     IS             bNis;
1938     PetscInt       bN;
1939     const PetscInt *bNindices;
1940     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
1941     PetscCall(ISGetSize(bNis,&bN));
1942     PetscCall(ISGetIndices(bNis,&bNindices));
1943     for (i=0; i<nest->nr; ++i) {
1944       Mat            B,D=NULL;
1945       PetscInt       bm, br;
1946       const PetscInt *bmindices;
1947       B = nest->m[i][j];
1948       if (!B) continue;
1949       PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&flg));
1950       if (flg) {
1951         PetscTryMethod(B,"MatTransposeGetMat_C",(Mat,Mat*),(B,&D));
1952         PetscTryMethod(B,"MatHermitianTransposeGetMat_C",(Mat,Mat*),(B,&D));
1953         PetscCall(MatConvert(B,((PetscObject)D)->type_name,MAT_INITIAL_MATRIX,&D));
1954         B = D;
1955       }
1956       PetscCall(PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQSBAIJ,MATMPISBAIJ,""));
1957       if (flg) {
1958         if (D) {
1959           PetscCall(MatConvert(D,MATBAIJ,MAT_INPLACE_MATRIX,&D));
1960         } else {
1961           PetscCall(MatConvert(B,MATBAIJ,MAT_INITIAL_MATRIX,&D));
1962         }
1963         B = D;
1964       }
1965       PetscCall(ISGetLocalSize(nest->isglobal.row[i],&bm));
1966       PetscCall(ISGetIndices(nest->isglobal.row[i],&bmindices));
1967       PetscCall(MatGetOwnershipRange(B,&rstart,NULL));
1968       for (br = 0; br < bm; ++br) {
1969         PetscInt          row = bmindices[br], brncols, *cols;
1970         const PetscInt    *brcols;
1971         const PetscScalar *brcoldata;
1972         PetscScalar       *vals = NULL;
1973         PetscCall(MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata));
1974         PetscCall(PetscMalloc1(brncols,&cols));
1975         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
1976         /*
1977           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1978           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1979          */
1980         if (a != 1.0) {
1981           PetscCall(PetscMalloc1(brncols,&vals));
1982           for (k=0; k<brncols; k++) vals[k] = a * brcoldata[k];
1983           PetscCall(MatSetValues(Y,1,&row,brncols,cols,vals,ADD_VALUES));
1984           PetscCall(PetscFree(vals));
1985         } else {
1986           PetscCall(MatSetValues(Y,1,&row,brncols,cols,brcoldata,ADD_VALUES));
1987         }
1988         PetscCall(MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata));
1989         PetscCall(PetscFree(cols));
1990       }
1991       if (D) {
1992         PetscCall(MatDestroy(&D));
1993       }
1994       PetscCall(ISRestoreIndices(nest->isglobal.row[i],&bmindices));
1995     }
1996     PetscCall(ISRestoreIndices(bNis,&bNindices));
1997     PetscCall(ISDestroy(&bNis));
1998   }
1999   PetscCall(MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY));
2000   PetscCall(MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY));
2001   PetscFunctionReturn(0);
2002 }
2003 
2004 PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
2005 {
2006   Mat_Nest       *nest = (Mat_Nest*)A->data;
2007   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart,cstart,cend;
2008   PetscMPIInt    size;
2009   Mat            C;
2010 
2011   PetscFunctionBegin;
2012   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size));
2013   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2014     PetscInt  nf;
2015     PetscBool fast;
2016 
2017     PetscCall(PetscStrcmp(newtype,MATAIJ,&fast));
2018     if (!fast) {
2019       PetscCall(PetscStrcmp(newtype,MATSEQAIJ,&fast));
2020     }
2021     for (i=0; i<nest->nr && fast; ++i) {
2022       for (j=0; j<nest->nc && fast; ++j) {
2023         Mat B = nest->m[i][j];
2024         if (B) {
2025           PetscCall(PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast));
2026           if (!fast) {
2027             PetscBool istrans;
2028 
2029             PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans));
2030             if (istrans) {
2031               Mat Bt;
2032 
2033               PetscCall(MatTransposeGetMat(B,&Bt));
2034               PetscCall(PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast));
2035             }
2036           }
2037         }
2038       }
2039     }
2040     for (i=0, nf=0; i<nest->nr && fast; ++i) {
2041       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast));
2042       if (fast) {
2043         PetscInt f,s;
2044 
2045         PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&f,&s));
2046         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2047         else {
2048           PetscCall(ISGetSize(nest->isglobal.row[i],&f));
2049           nf  += f;
2050         }
2051       }
2052     }
2053     for (i=0, nf=0; i<nest->nc && fast; ++i) {
2054       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast));
2055       if (fast) {
2056         PetscInt f,s;
2057 
2058         PetscCall(ISStrideGetInfo(nest->isglobal.col[i],&f,&s));
2059         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2060         else {
2061           PetscCall(ISGetSize(nest->isglobal.col[i],&f));
2062           nf  += f;
2063         }
2064       }
2065     }
2066     if (fast) {
2067       PetscCall(MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat));
2068       PetscFunctionReturn(0);
2069     }
2070   }
2071   PetscCall(MatGetSize(A,&M,&N));
2072   PetscCall(MatGetLocalSize(A,&m,&n));
2073   PetscCall(MatGetOwnershipRangeColumn(A,&cstart,&cend));
2074   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2075   else {
2076     PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C));
2077     PetscCall(MatSetType(C,newtype));
2078     PetscCall(MatSetSizes(C,m,n,M,N));
2079   }
2080   PetscCall(PetscMalloc1(2*m,&dnnz));
2081   onnz = dnnz + m;
2082   for (k=0; k<m; k++) {
2083     dnnz[k] = 0;
2084     onnz[k] = 0;
2085   }
2086   for (j=0; j<nest->nc; ++j) {
2087     IS             bNis;
2088     PetscInt       bN;
2089     const PetscInt *bNindices;
2090     /* Using global column indices and ISAllGather() is not scalable. */
2091     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
2092     PetscCall(ISGetSize(bNis, &bN));
2093     PetscCall(ISGetIndices(bNis,&bNindices));
2094     for (i=0; i<nest->nr; ++i) {
2095       PetscSF        bmsf;
2096       PetscSFNode    *iremote;
2097       Mat            B;
2098       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
2099       const PetscInt *bmindices;
2100       B = nest->m[i][j];
2101       if (!B) continue;
2102       PetscCall(ISGetLocalSize(nest->isglobal.row[i],&bm));
2103       PetscCall(ISGetIndices(nest->isglobal.row[i],&bmindices));
2104       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
2105       PetscCall(PetscMalloc1(bm,&iremote));
2106       PetscCall(PetscMalloc1(bm,&sub_dnnz));
2107       PetscCall(PetscMalloc1(bm,&sub_onnz));
2108       for (k = 0; k < bm; ++k) {
2109         sub_dnnz[k] = 0;
2110         sub_onnz[k] = 0;
2111       }
2112       /*
2113        Locate the owners for all of the locally-owned global row indices for this row block.
2114        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2115        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2116        */
2117       PetscCall(MatGetOwnershipRange(B,&rstart,NULL));
2118       for (br = 0; br < bm; ++br) {
2119         PetscInt       row = bmindices[br], brncols, col;
2120         const PetscInt *brcols;
2121         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
2122         PetscMPIInt    rowowner = 0;
2123         PetscCall(PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel));
2124         /* how many roots  */
2125         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
2126         /* get nonzero pattern */
2127         PetscCall(MatGetRow(B,br+rstart,&brncols,&brcols,NULL));
2128         for (k=0; k<brncols; k++) {
2129           col  = bNindices[brcols[k]];
2130           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
2131             sub_dnnz[br]++;
2132           } else {
2133             sub_onnz[br]++;
2134           }
2135         }
2136         PetscCall(MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL));
2137       }
2138       PetscCall(ISRestoreIndices(nest->isglobal.row[i],&bmindices));
2139       /* bsf will have to take care of disposing of bedges. */
2140       PetscCall(PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
2141       PetscCall(PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM));
2142       PetscCall(PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM));
2143       PetscCall(PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM));
2144       PetscCall(PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM));
2145       PetscCall(PetscFree(sub_dnnz));
2146       PetscCall(PetscFree(sub_onnz));
2147       PetscCall(PetscSFDestroy(&bmsf));
2148     }
2149     PetscCall(ISRestoreIndices(bNis,&bNindices));
2150     PetscCall(ISDestroy(&bNis));
2151   }
2152   /* Resize preallocation if overestimated */
2153   for (i=0;i<m;i++) {
2154     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
2155     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
2156   }
2157   PetscCall(MatSeqAIJSetPreallocation(C,0,dnnz));
2158   PetscCall(MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz));
2159   PetscCall(PetscFree(dnnz));
2160   PetscCall(MatAXPY_Dense_Nest(C,1.0,A));
2161   if (reuse == MAT_INPLACE_MATRIX) {
2162     PetscCall(MatHeaderReplace(A,&C));
2163   } else *newmat = C;
2164   PetscFunctionReturn(0);
2165 }
2166 
2167 PetscErrorCode MatConvert_Nest_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
2168 {
2169   Mat            B;
2170   PetscInt       m,n,M,N;
2171 
2172   PetscFunctionBegin;
2173   PetscCall(MatGetSize(A,&M,&N));
2174   PetscCall(MatGetLocalSize(A,&m,&n));
2175   if (reuse == MAT_REUSE_MATRIX) {
2176     B = *newmat;
2177     PetscCall(MatZeroEntries(B));
2178   } else {
2179     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),m,PETSC_DECIDE,M,N,NULL,&B));
2180   }
2181   PetscCall(MatAXPY_Dense_Nest(B,1.0,A));
2182   if (reuse == MAT_INPLACE_MATRIX) {
2183     PetscCall(MatHeaderReplace(A,&B));
2184   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2185   PetscFunctionReturn(0);
2186 }
2187 
2188 PetscErrorCode MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool *has)
2189 {
2190   Mat_Nest       *bA = (Mat_Nest*)mat->data;
2191   MatOperation   opAdd;
2192   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
2193   PetscBool      flg;
2194   PetscFunctionBegin;
2195 
2196   *has = PETSC_FALSE;
2197   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
2198     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
2199     for (j=0; j<nc; j++) {
2200       for (i=0; i<nr; i++) {
2201         if (!bA->m[i][j]) continue;
2202         PetscCall(MatHasOperation(bA->m[i][j],opAdd,&flg));
2203         if (!flg) PetscFunctionReturn(0);
2204       }
2205     }
2206   }
2207   if (((void**)mat->ops)[op]) *has = PETSC_TRUE;
2208   PetscFunctionReturn(0);
2209 }
2210 
2211 /*MC
2212   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2213 
2214   Level: intermediate
2215 
2216   Notes:
2217   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
2218   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2219   It is usually used with DMComposite and DMCreateMatrix()
2220 
2221   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
2222   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
2223   than the nest matrix.
2224 
2225 .seealso: MatCreate(), MatType, MatCreateNest(), MatNestSetSubMat(), MatNestGetSubMat(),
2226           VecCreateNest(), DMCreateMatrix(), DMCOMPOSITE, MatNestSetVecType(), MatNestGetLocalISs(),
2227           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
2228 M*/
2229 PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2230 {
2231   Mat_Nest       *s;
2232 
2233   PetscFunctionBegin;
2234   PetscCall(PetscNewLog(A,&s));
2235   A->data = (void*)s;
2236 
2237   s->nr            = -1;
2238   s->nc            = -1;
2239   s->m             = NULL;
2240   s->splitassembly = PETSC_FALSE;
2241 
2242   PetscCall(PetscMemzero(A->ops,sizeof(*A->ops)));
2243 
2244   A->ops->mult                  = MatMult_Nest;
2245   A->ops->multadd               = MatMultAdd_Nest;
2246   A->ops->multtranspose         = MatMultTranspose_Nest;
2247   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2248   A->ops->transpose             = MatTranspose_Nest;
2249   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2250   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2251   A->ops->zeroentries           = MatZeroEntries_Nest;
2252   A->ops->copy                  = MatCopy_Nest;
2253   A->ops->axpy                  = MatAXPY_Nest;
2254   A->ops->duplicate             = MatDuplicate_Nest;
2255   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2256   A->ops->destroy               = MatDestroy_Nest;
2257   A->ops->view                  = MatView_Nest;
2258   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2259   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2260   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2261   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2262   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2263   A->ops->scale                 = MatScale_Nest;
2264   A->ops->shift                 = MatShift_Nest;
2265   A->ops->diagonalset           = MatDiagonalSet_Nest;
2266   A->ops->setrandom             = MatSetRandom_Nest;
2267   A->ops->hasoperation          = MatHasOperation_Nest;
2268   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2269 
2270   A->spptr        = NULL;
2271   A->assembled    = PETSC_FALSE;
2272 
2273   /* expose Nest api's */
2274   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",        MatNestGetSubMat_Nest));
2275   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",        MatNestSetSubMat_Nest));
2276   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",       MatNestGetSubMats_Nest));
2277   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",          MatNestGetSize_Nest));
2278   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",           MatNestGetISs_Nest));
2279   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",      MatNestGetLocalISs_Nest));
2280   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",       MatNestSetVecType_Nest));
2281   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",       MatNestSetSubMats_Nest));
2282   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",  MatConvert_Nest_AIJ));
2283   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",  MatConvert_Nest_AIJ));
2284   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",     MatConvert_Nest_AIJ));
2285   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",      MatConvert_Nest_IS));
2286   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpidense_C",MatConvert_Nest_Dense));
2287   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqdense_C",MatConvert_Nest_Dense));
2288   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",MatProductSetFromOptions_Nest_Dense));
2289   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",MatProductSetFromOptions_Nest_Dense));
2290   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",MatProductSetFromOptions_Nest_Dense));
2291 
2292   PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATNEST));
2293   PetscFunctionReturn(0);
2294 }
2295