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