xref: /petsc/src/mat/impls/nest/matnest.c (revision ea6db252e5fd0d35901d80ca34610cae33db92a4)
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         PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
997         nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
998         bB->nnzstate[i * nc + j] = subnnzstate;
999       } else if (bA->m[i][j]) { // bB->m[i][j] is NULL
1000         Mat M;
1001 
1002         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1003         PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M));
1004         PetscCall(MatNestSetSubMat(B, i, j, M));
1005         PetscCall(MatDestroy(&M));
1006       } else if (bB->m[i][j]) { // bA->m[i][j] is NULL
1007         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == SUBSET_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN, SUBSET_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1008         PetscCall(MatNestSetSubMat(B, i, j, NULL));
1009       }
1010     }
1011   }
1012   if (nnzstate) B->nonzerostate++;
1013   PetscFunctionReturn(PETSC_SUCCESS);
1014 }
1015 
1016 static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1017 {
1018   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
1019   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
1020   PetscBool nnzstate = PETSC_FALSE;
1021 
1022   PetscFunctionBegin;
1023   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);
1024   for (i = 0; i < nr; i++) {
1025     for (j = 0; j < nc; j++) {
1026       PetscObjectState subnnzstate = 0;
1027       if (bY->m[i][j] && bX->m[i][j]) {
1028         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1029       } else if (bX->m[i][j]) {
1030         Mat M;
1031 
1032         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);
1033         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
1034         PetscCall(MatNestSetSubMat(Y, i, j, M));
1035         PetscCall(MatDestroy(&M));
1036       }
1037       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
1038       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
1039       bY->nnzstate[i * nc + j] = subnnzstate;
1040     }
1041   }
1042   if (nnzstate) Y->nonzerostate++;
1043   PetscFunctionReturn(PETSC_SUCCESS);
1044 }
1045 
1046 static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1047 {
1048   Mat_Nest *bA = (Mat_Nest *)A->data;
1049   Mat      *b;
1050   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1051 
1052   PetscFunctionBegin;
1053   PetscCall(PetscMalloc1(nr * nc, &b));
1054   for (i = 0; i < nr; i++) {
1055     for (j = 0; j < nc; j++) {
1056       if (bA->m[i][j]) {
1057         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1058       } else {
1059         b[i * nc + j] = NULL;
1060       }
1061     }
1062   }
1063   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1064   /* Give the new MatNest exclusive ownership */
1065   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
1066   PetscCall(PetscFree(b));
1067 
1068   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1069   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1070   PetscFunctionReturn(PETSC_SUCCESS);
1071 }
1072 
1073 /* nest api */
1074 static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1075 {
1076   Mat_Nest *bA = (Mat_Nest *)A->data;
1077 
1078   PetscFunctionBegin;
1079   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1080   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1081   *mat = bA->m[idxm][jdxm];
1082   PetscFunctionReturn(PETSC_SUCCESS);
1083 }
1084 
1085 /*@
1086   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1087 
1088   Not Collective
1089 
1090   Input Parameters:
1091 + A    - `MATNEST` matrix
1092 . idxm - index of the matrix within the nest matrix
1093 - jdxm - index of the matrix within the nest matrix
1094 
1095   Output Parameter:
1096 . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1097 
1098   Level: developer
1099 
1100 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1101           `MatNestGetLocalISs()`, `MatNestGetISs()`
1102 @*/
1103 PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1104 {
1105   PetscFunctionBegin;
1106   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1107   PetscValidLogicalCollectiveInt(A, idxm, 2);
1108   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1109   PetscAssertPointer(sub, 4);
1110   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
1111   PetscFunctionReturn(PETSC_SUCCESS);
1112 }
1113 
1114 static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1115 {
1116   Mat_Nest *bA = (Mat_Nest *)A->data;
1117   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
1118 
1119   PetscFunctionBegin;
1120   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1121   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1122   if (mat) {
1123     PetscCall(MatGetLocalSize(mat, &m, &n));
1124     PetscCall(MatGetSize(mat, &M, &N));
1125     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
1126     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
1127     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
1128     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1129     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);
1130     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);
1131   }
1132 
1133   /* do not increase object state */
1134   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
1135 
1136   PetscCall(PetscObjectReference((PetscObject)mat));
1137   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
1138   bA->m[idxm][jdxm] = mat;
1139   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1140   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
1141   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
1142   A->nonzerostate++;
1143   PetscFunctionReturn(PETSC_SUCCESS);
1144 }
1145 
1146 /*@
1147   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
1148 
1149   Logically Collective
1150 
1151   Input Parameters:
1152 + A    - `MATNEST` matrix
1153 . idxm - index of the matrix within the nest matrix
1154 . jdxm - index of the matrix within the nest matrix
1155 - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
1156 
1157   Level: developer
1158 
1159   Notes:
1160   The new submatrix must have the same size and communicator as that block of the nest.
1161 
1162   This increments the reference count of the submatrix.
1163 
1164 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1165           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
1166 @*/
1167 PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1168 {
1169   PetscFunctionBegin;
1170   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1171   PetscValidLogicalCollectiveInt(A, idxm, 2);
1172   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1173   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
1174   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
1175   PetscFunctionReturn(PETSC_SUCCESS);
1176 }
1177 
1178 static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1179 {
1180   Mat_Nest *bA = (Mat_Nest *)A->data;
1181 
1182   PetscFunctionBegin;
1183   if (M) *M = bA->nr;
1184   if (N) *N = bA->nc;
1185   if (mat) *mat = bA->m;
1186   PetscFunctionReturn(PETSC_SUCCESS);
1187 }
1188 
1189 /*@C
1190   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1191 
1192   Not Collective
1193 
1194   Input Parameter:
1195 . A - nest matrix
1196 
1197   Output Parameters:
1198 + M   - number of submatrix rows in the nest matrix
1199 . N   - number of submatrix columns in the nest matrix
1200 - mat - array of matrices
1201 
1202   Level: developer
1203 
1204   Note:
1205   The user should not free the array `mat`.
1206 
1207   Fortran Notes:
1208   This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)`
1209   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1210   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1211 
1212 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1213           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1214 @*/
1215 PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1216 {
1217   PetscFunctionBegin;
1218   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1219   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
1220   PetscFunctionReturn(PETSC_SUCCESS);
1221 }
1222 
1223 static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1224 {
1225   Mat_Nest *bA = (Mat_Nest *)A->data;
1226 
1227   PetscFunctionBegin;
1228   if (M) *M = bA->nr;
1229   if (N) *N = bA->nc;
1230   PetscFunctionReturn(PETSC_SUCCESS);
1231 }
1232 
1233 /*@
1234   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1235 
1236   Not Collective
1237 
1238   Input Parameter:
1239 . A - `MATNEST` matrix
1240 
1241   Output Parameters:
1242 + M - number of rows in the nested mat
1243 - N - number of cols in the nested mat
1244 
1245   Level: developer
1246 
1247   Note:
1248   `size` refers to the number of submatrices in the row and column directions of the nested matrix
1249 
1250 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1251           `MatNestGetISs()`
1252 @*/
1253 PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1254 {
1255   PetscFunctionBegin;
1256   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1257   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
1258   PetscFunctionReturn(PETSC_SUCCESS);
1259 }
1260 
1261 static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1262 {
1263   Mat_Nest *vs = (Mat_Nest *)A->data;
1264   PetscInt  i;
1265 
1266   PetscFunctionBegin;
1267   if (rows)
1268     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
1269   if (cols)
1270     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 /*@
1275   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1276 
1277   Not Collective
1278 
1279   Input Parameter:
1280 . A - `MATNEST` matrix
1281 
1282   Output Parameters:
1283 + rows - array of row index sets (pass `NULL` to ignore)
1284 - cols - array of column index sets (pass `NULL` to ignore)
1285 
1286   Level: advanced
1287 
1288   Note:
1289   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1290 
1291 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1292           `MatCreateNest()`, `MatNestSetSubMats()`
1293 @*/
1294 PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1295 {
1296   PetscFunctionBegin;
1297   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1298   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1299   PetscFunctionReturn(PETSC_SUCCESS);
1300 }
1301 
1302 static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1303 {
1304   Mat_Nest *vs = (Mat_Nest *)A->data;
1305   PetscInt  i;
1306 
1307   PetscFunctionBegin;
1308   if (rows)
1309     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
1310   if (cols)
1311     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
1312   PetscFunctionReturn(PETSC_SUCCESS);
1313 }
1314 
1315 /*@
1316   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1317 
1318   Not Collective
1319 
1320   Input Parameter:
1321 . A - `MATNEST` matrix
1322 
1323   Output Parameters:
1324 + rows - array of row index sets (pass `NULL` to ignore)
1325 - cols - array of column index sets (pass `NULL` to ignore)
1326 
1327   Level: advanced
1328 
1329   Note:
1330   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1331 
1332 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1333           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1334 @*/
1335 PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1336 {
1337   PetscFunctionBegin;
1338   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1339   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1340   PetscFunctionReturn(PETSC_SUCCESS);
1341 }
1342 
1343 static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1344 {
1345   PetscBool flg;
1346 
1347   PetscFunctionBegin;
1348   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1349   /* In reality, this only distinguishes VECNEST and "other" */
1350   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
1351   else A->ops->getvecs = NULL;
1352   PetscFunctionReturn(PETSC_SUCCESS);
1353 }
1354 
1355 /*@
1356   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1357 
1358   Not Collective
1359 
1360   Input Parameters:
1361 + A     - `MATNEST` matrix
1362 - vtype - `VecType` to use for creating vectors
1363 
1364   Level: developer
1365 
1366 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1367 @*/
1368 PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1369 {
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1372   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
1373   PetscFunctionReturn(PETSC_SUCCESS);
1374 }
1375 
1376 static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1377 {
1378   Mat_Nest *s = (Mat_Nest *)A->data;
1379   PetscInt  i, j, m, n, M, N;
1380   PetscBool cong, isstd, sametype = PETSC_FALSE;
1381   VecType   vtype, type;
1382 
1383   PetscFunctionBegin;
1384   PetscCall(MatReset_Nest(A));
1385 
1386   s->nr = nr;
1387   s->nc = nc;
1388 
1389   /* Create space for submatrices */
1390   PetscCall(PetscMalloc1(nr, &s->m));
1391   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1392   for (i = 0; i < nr; i++) {
1393     s->m[i] = s->m[0] + i * nc;
1394     for (j = 0; j < nc; j++) {
1395       s->m[i][j] = a ? a[i * nc + j] : NULL;
1396       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1397     }
1398   }
1399   PetscCall(MatGetVecType(A, &vtype));
1400   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
1401   if (isstd) {
1402     /* check if all blocks have the same vectype */
1403     vtype = NULL;
1404     for (i = 0; i < nr; i++) {
1405       for (j = 0; j < nc; j++) {
1406         if (s->m[i][j]) {
1407           if (!vtype) { /* first visited block */
1408             PetscCall(MatGetVecType(s->m[i][j], &vtype));
1409             sametype = PETSC_TRUE;
1410           } else if (sametype) {
1411             PetscCall(MatGetVecType(s->m[i][j], &type));
1412             PetscCall(PetscStrcmp(vtype, type, &sametype));
1413           }
1414         }
1415       }
1416     }
1417     if (sametype) { /* propagate vectype */
1418       PetscCall(MatSetVecType(A, vtype));
1419     }
1420   }
1421 
1422   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1423 
1424   PetscCall(PetscMalloc1(nr, &s->row_len));
1425   PetscCall(PetscMalloc1(nc, &s->col_len));
1426   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1427   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1428 
1429   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
1430   for (i = 0; i < nr; i++) {
1431     for (j = 0; j < nc; j++) {
1432       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
1433     }
1434   }
1435 
1436   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1437 
1438   PetscCall(PetscLayoutSetSize(A->rmap, M));
1439   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
1440   PetscCall(PetscLayoutSetSize(A->cmap, N));
1441   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1442 
1443   PetscCall(PetscLayoutSetUp(A->rmap));
1444   PetscCall(PetscLayoutSetUp(A->cmap));
1445 
1446   /* disable operations that are not supported for non-square matrices,
1447      or matrices for which is_row != is_col  */
1448   PetscCall(MatHasCongruentLayouts(A, &cong));
1449   if (cong && nr != nc) cong = PETSC_FALSE;
1450   if (cong) {
1451     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
1452   }
1453   if (!cong) {
1454     A->ops->missingdiagonal = NULL;
1455     A->ops->getdiagonal     = NULL;
1456     A->ops->shift           = NULL;
1457     A->ops->diagonalset     = NULL;
1458   }
1459 
1460   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
1461   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1462   A->nonzerostate++;
1463   PetscFunctionReturn(PETSC_SUCCESS);
1464 }
1465 
1466 /*@
1467   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1468 
1469   Collective
1470 
1471   Input Parameters:
1472 + A      - `MATNEST` matrix
1473 . nr     - number of nested row blocks
1474 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1475 . nc     - number of nested column blocks
1476 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1477 - a      - array of nr*nc submatrices, or `NULL`
1478 
1479   Level: advanced
1480 
1481   Notes:
1482   This always resets any block matrix information previously set.
1483 
1484   Pass `NULL` in the corresponding entry of `a` for an empty block.
1485 
1486   In both C and Fortran, `a` must be a row-major order array containing the matrices. See
1487   `MatCreateNest()` for an example.
1488 
1489 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1490 @*/
1491 PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1492 {
1493   PetscFunctionBegin;
1494   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1495   PetscValidLogicalCollectiveInt(A, nr, 2);
1496   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1497   if (nr && is_row) {
1498     PetscAssertPointer(is_row, 3);
1499     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1500   }
1501   PetscValidLogicalCollectiveInt(A, nc, 4);
1502   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
1503   if (nc && is_col) {
1504     PetscAssertPointer(is_col, 5);
1505     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1506   }
1507   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1512 {
1513   PetscBool flg;
1514   PetscInt  i, j, m, mi, *ix;
1515 
1516   PetscFunctionBegin;
1517   *ltog = NULL;
1518   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
1519     if (islocal[i]) {
1520       PetscCall(ISGetLocalSize(islocal[i], &mi));
1521       flg = PETSC_TRUE; /* We found a non-trivial entry */
1522     } else {
1523       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1524     }
1525     m += mi;
1526   }
1527   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1528 
1529   PetscCall(PetscMalloc1(m, &ix));
1530   for (i = 0, m = 0; i < n; i++) {
1531     ISLocalToGlobalMapping smap = NULL;
1532     Mat                    sub  = NULL;
1533     PetscSF                sf;
1534     PetscLayout            map;
1535     const PetscInt        *ix2;
1536 
1537     if (!colflg) {
1538       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1539     } else {
1540       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1541     }
1542     if (sub) {
1543       if (!colflg) {
1544         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1545       } else {
1546         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1547       }
1548     }
1549     /*
1550        Now we need to extract the monolithic global indices that correspond to the given split global indices.
1551        In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1552     */
1553     PetscCall(ISGetIndices(isglobal[i], &ix2));
1554     if (islocal[i]) {
1555       PetscInt *ilocal, *iremote;
1556       PetscInt  mil, nleaves;
1557 
1558       PetscCall(ISGetLocalSize(islocal[i], &mi));
1559       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1560       for (j = 0; j < mi; j++) ix[m + j] = j;
1561       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1562 
1563       /* PetscSFSetGraphLayout does not like negative indices */
1564       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1565       for (j = 0, nleaves = 0; j < mi; j++) {
1566         if (ix[m + j] < 0) continue;
1567         ilocal[nleaves]  = j;
1568         iremote[nleaves] = ix[m + j];
1569         nleaves++;
1570       }
1571       PetscCall(ISGetLocalSize(isglobal[i], &mil));
1572       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
1573       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
1574       PetscCall(PetscLayoutSetLocalSize(map, mil));
1575       PetscCall(PetscLayoutSetUp(map));
1576       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
1577       PetscCall(PetscLayoutDestroy(&map));
1578       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1579       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1580       PetscCall(PetscSFDestroy(&sf));
1581       PetscCall(PetscFree2(ilocal, iremote));
1582     } else {
1583       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1584       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1585     }
1586     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
1587     m += mi;
1588   }
1589   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
1590   PetscFunctionReturn(PETSC_SUCCESS);
1591 }
1592 
1593 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1594 /*
1595   nprocessors = NP
1596   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1597        proc 0: => (g_0,h_0,)
1598        proc 1: => (g_1,h_1,)
1599        ...
1600        proc nprocs-1: => (g_NP-1,h_NP-1,)
1601 
1602             proc 0:                      proc 1:                    proc nprocs-1:
1603     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1604 
1605             proc 0:
1606     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1607             proc 1:
1608     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1609 
1610             proc NP-1:
1611     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1612 */
1613 static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1614 {
1615   Mat_Nest *vs = (Mat_Nest *)A->data;
1616   PetscInt  i, j, offset, n, nsum, bs;
1617   Mat       sub = NULL;
1618 
1619   PetscFunctionBegin;
1620   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
1621   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1622   if (is_row) { /* valid IS is passed in */
1623     /* refs on is[] are incremented */
1624     for (i = 0; i < vs->nr; i++) {
1625       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1626       vs->isglobal.row[i] = is_row[i];
1627     }
1628   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
1629     nsum = 0;
1630     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
1631       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1632       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
1633       PetscCall(MatGetLocalSize(sub, &n, NULL));
1634       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1635       nsum += n;
1636     }
1637     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1638     offset -= nsum;
1639     for (i = 0; i < vs->nr; i++) {
1640       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1641       PetscCall(MatGetLocalSize(sub, &n, NULL));
1642       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1643       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
1644       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
1645       offset += n;
1646     }
1647   }
1648 
1649   if (is_col) { /* valid IS is passed in */
1650     /* refs on is[] are incremented */
1651     for (j = 0; j < vs->nc; j++) {
1652       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1653       vs->isglobal.col[j] = is_col[j];
1654     }
1655   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
1656     offset = A->cmap->rstart;
1657     nsum   = 0;
1658     for (j = 0; j < vs->nc; j++) {
1659       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1660       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
1661       PetscCall(MatGetLocalSize(sub, NULL, &n));
1662       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1663       nsum += n;
1664     }
1665     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1666     offset -= nsum;
1667     for (j = 0; j < vs->nc; j++) {
1668       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1669       PetscCall(MatGetLocalSize(sub, NULL, &n));
1670       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1671       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
1672       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
1673       offset += n;
1674     }
1675   }
1676 
1677   /* Set up the local ISs */
1678   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
1679   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1680   for (i = 0, offset = 0; i < vs->nr; i++) {
1681     IS                     isloc;
1682     ISLocalToGlobalMapping rmap = NULL;
1683     PetscInt               nlocal, bs;
1684     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1685     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1686     if (rmap) {
1687       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1688       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
1689       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1690       PetscCall(ISSetBlockSize(isloc, bs));
1691     } else {
1692       nlocal = 0;
1693       isloc  = NULL;
1694     }
1695     vs->islocal.row[i] = isloc;
1696     offset += nlocal;
1697   }
1698   for (i = 0, offset = 0; i < vs->nc; i++) {
1699     IS                     isloc;
1700     ISLocalToGlobalMapping cmap = NULL;
1701     PetscInt               nlocal, bs;
1702     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1703     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1704     if (cmap) {
1705       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1706       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
1707       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1708       PetscCall(ISSetBlockSize(isloc, bs));
1709     } else {
1710       nlocal = 0;
1711       isloc  = NULL;
1712     }
1713     vs->islocal.col[i] = isloc;
1714     offset += nlocal;
1715   }
1716 
1717   /* Set up the aggregate ISLocalToGlobalMapping */
1718   {
1719     ISLocalToGlobalMapping rmap, cmap;
1720     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
1721     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
1722     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
1723     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
1724     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
1725   }
1726 
1727   if (PetscDefined(USE_DEBUG)) {
1728     for (i = 0; i < vs->nr; i++) {
1729       for (j = 0; j < vs->nc; j++) {
1730         PetscInt m, n, M, N, mi, ni, Mi, Ni;
1731         Mat      B = vs->m[i][j];
1732         if (!B) continue;
1733         PetscCall(MatGetSize(B, &M, &N));
1734         PetscCall(MatGetLocalSize(B, &m, &n));
1735         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
1736         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
1737         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
1738         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1739         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);
1740         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);
1741       }
1742     }
1743   }
1744 
1745   /* Set A->assembled if all non-null blocks are currently assembled */
1746   for (i = 0; i < vs->nr; i++) {
1747     for (j = 0; j < vs->nc; j++) {
1748       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1749     }
1750   }
1751   A->assembled = PETSC_TRUE;
1752   PetscFunctionReturn(PETSC_SUCCESS);
1753 }
1754 
1755 /*@C
1756   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1757 
1758   Collective
1759 
1760   Input Parameters:
1761 + comm   - Communicator for the new `MATNEST`
1762 . nr     - number of nested row blocks
1763 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1764 . nc     - number of nested column blocks
1765 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1766 - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1767 
1768   Output Parameter:
1769 . B - new matrix
1770 
1771   Note:
1772   In both C and Fortran, `a` must be a row-major order array holding references to the matrices.
1773   For instance, to represent the matrix
1774   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1775   one should use `Mat a[4]={A11,A12,A21,A22}`.
1776 
1777   Level: advanced
1778 
1779 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1780           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1781           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1782 @*/
1783 PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS
1784 {
1785   PetscFunctionBegin;
1786   PetscCall(MatCreate(comm, B));
1787   PetscCall(MatSetType(*B, MATNEST));
1788   (*B)->preallocated = PETSC_TRUE;
1789   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
1790   PetscFunctionReturn(PETSC_SUCCESS);
1791 }
1792 
1793 static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1794 {
1795   Mat_Nest     *nest = (Mat_Nest *)A->data;
1796   Mat          *trans;
1797   PetscScalar **avv;
1798   PetscScalar  *vv;
1799   PetscInt    **aii, **ajj;
1800   PetscInt     *ii, *jj, *ci;
1801   PetscInt      nr, nc, nnz, i, j;
1802   PetscBool     done;
1803 
1804   PetscFunctionBegin;
1805   PetscCall(MatGetSize(A, &nr, &nc));
1806   if (reuse == MAT_REUSE_MATRIX) {
1807     PetscInt rnr;
1808 
1809     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
1810     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
1811     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
1812     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1813   }
1814   /* extract CSR for nested SeqAIJ matrices */
1815   nnz = 0;
1816   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1817   for (i = 0; i < nest->nr; ++i) {
1818     for (j = 0; j < nest->nc; ++j) {
1819       Mat B = nest->m[i][j];
1820       if (B) {
1821         PetscScalar *naa;
1822         PetscInt    *nii, *njj, nnr;
1823         PetscBool    istrans;
1824 
1825         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
1826         if (istrans) {
1827           Mat Bt;
1828 
1829           PetscCall(MatTransposeGetMat(B, &Bt));
1830           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1831           B = trans[i * nest->nc + j];
1832         } else {
1833           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1834           if (istrans) {
1835             Mat Bt;
1836 
1837             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1838             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1839             B = trans[i * nest->nc + j];
1840           }
1841         }
1842         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
1843         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
1844         PetscCall(MatSeqAIJGetArray(B, &naa));
1845         nnz += nii[nnr];
1846 
1847         aii[i * nest->nc + j] = nii;
1848         ajj[i * nest->nc + j] = njj;
1849         avv[i * nest->nc + j] = naa;
1850       }
1851     }
1852   }
1853   if (reuse != MAT_REUSE_MATRIX) {
1854     PetscCall(PetscMalloc1(nr + 1, &ii));
1855     PetscCall(PetscMalloc1(nnz, &jj));
1856     PetscCall(PetscMalloc1(nnz, &vv));
1857   } else {
1858     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1859   }
1860 
1861   /* new row pointer */
1862   PetscCall(PetscArrayzero(ii, nr + 1));
1863   for (i = 0; i < nest->nr; ++i) {
1864     PetscInt ncr, rst;
1865 
1866     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1867     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1868     for (j = 0; j < nest->nc; ++j) {
1869       if (aii[i * nest->nc + j]) {
1870         PetscInt *nii = aii[i * nest->nc + j];
1871         PetscInt  ir;
1872 
1873         for (ir = rst; ir < ncr + rst; ++ir) {
1874           ii[ir + 1] += nii[1] - nii[0];
1875           nii++;
1876         }
1877       }
1878     }
1879   }
1880   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1881 
1882   /* construct CSR for the new matrix */
1883   PetscCall(PetscCalloc1(nr, &ci));
1884   for (i = 0; i < nest->nr; ++i) {
1885     PetscInt ncr, rst;
1886 
1887     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1888     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1889     for (j = 0; j < nest->nc; ++j) {
1890       if (aii[i * nest->nc + j]) {
1891         PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0;
1892         PetscInt    *nii = aii[i * nest->nc + j];
1893         PetscInt    *njj = ajj[i * nest->nc + j];
1894         PetscInt     ir, cst;
1895 
1896         if (trans[i * nest->nc + j]) {
1897           vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale;
1898           vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift;
1899         }
1900         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1901         for (ir = rst; ir < ncr + rst; ++ir) {
1902           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1903 
1904           for (ij = 0; ij < rsize; ij++) {
1905             jj[ist + ij] = *njj + cst;
1906             vv[ist + ij] = vscale * *nvv;
1907             if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift;
1908             njj++;
1909             nvv++;
1910           }
1911           ci[ir] += rsize;
1912           nii++;
1913         }
1914       }
1915     }
1916   }
1917   PetscCall(PetscFree(ci));
1918 
1919   /* restore info */
1920   for (i = 0; i < nest->nr; ++i) {
1921     for (j = 0; j < nest->nc; ++j) {
1922       Mat B = nest->m[i][j];
1923       if (B) {
1924         PetscInt nnr = 0, k = i * nest->nc + j;
1925 
1926         B = (trans[k] ? trans[k] : B);
1927         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
1928         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
1929         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
1930         PetscCall(MatDestroy(&trans[k]));
1931       }
1932     }
1933   }
1934   PetscCall(PetscFree4(aii, ajj, avv, trans));
1935 
1936   /* finalize newmat */
1937   if (reuse == MAT_INITIAL_MATRIX) {
1938     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1939   } else if (reuse == MAT_INPLACE_MATRIX) {
1940     Mat B;
1941 
1942     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
1943     PetscCall(MatHeaderReplace(A, &B));
1944   }
1945   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1946   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1947   {
1948     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1949     a->free_a     = PETSC_TRUE;
1950     a->free_ij    = PETSC_TRUE;
1951   }
1952   PetscFunctionReturn(PETSC_SUCCESS);
1953 }
1954 
1955 PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1956 {
1957   Mat_Nest *nest = (Mat_Nest *)X->data;
1958   PetscInt  i, j, k, rstart;
1959   PetscBool flg;
1960 
1961   PetscFunctionBegin;
1962   /* Fill by row */
1963   for (j = 0; j < nest->nc; ++j) {
1964     /* Using global column indices and ISAllGather() is not scalable. */
1965     IS              bNis;
1966     PetscInt        bN;
1967     const PetscInt *bNindices;
1968     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
1969     PetscCall(ISGetSize(bNis, &bN));
1970     PetscCall(ISGetIndices(bNis, &bNindices));
1971     for (i = 0; i < nest->nr; ++i) {
1972       Mat             B = nest->m[i][j], D = NULL;
1973       PetscInt        bm, br;
1974       const PetscInt *bmindices;
1975       if (!B) continue;
1976       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1977       if (flg) {
1978         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1979         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
1980         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1981         B = D;
1982       }
1983       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1984       if (flg) {
1985         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1986         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1987         B = D;
1988       }
1989       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
1990       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
1991       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1992       for (br = 0; br < bm; ++br) {
1993         PetscInt           row = bmindices[br], brncols, *cols;
1994         const PetscInt    *brcols;
1995         const PetscScalar *brcoldata;
1996         PetscScalar       *vals = NULL;
1997         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
1998         PetscCall(PetscMalloc1(brncols, &cols));
1999         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
2000         /*
2001           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
2002           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
2003          */
2004         if (a != 1.0) {
2005           PetscCall(PetscMalloc1(brncols, &vals));
2006           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
2007           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
2008           PetscCall(PetscFree(vals));
2009         } else {
2010           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
2011         }
2012         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
2013         PetscCall(PetscFree(cols));
2014       }
2015       if (D) PetscCall(MatDestroy(&D));
2016       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2017     }
2018     PetscCall(ISRestoreIndices(bNis, &bNindices));
2019     PetscCall(ISDestroy(&bNis));
2020   }
2021   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2022   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
2023   PetscFunctionReturn(PETSC_SUCCESS);
2024 }
2025 
2026 static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2027 {
2028   Mat_Nest   *nest = (Mat_Nest *)A->data;
2029   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2030   PetscMPIInt size;
2031   Mat         C;
2032 
2033   PetscFunctionBegin;
2034   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2035   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2036     PetscInt  nf;
2037     PetscBool fast;
2038 
2039     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
2040     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2041     for (i = 0; i < nest->nr && fast; ++i) {
2042       for (j = 0; j < nest->nc && fast; ++j) {
2043         Mat B = nest->m[i][j];
2044         if (B) {
2045           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
2046           if (!fast) {
2047             PetscBool istrans;
2048 
2049             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
2050             if (istrans) {
2051               Mat Bt;
2052 
2053               PetscCall(MatTransposeGetMat(B, &Bt));
2054               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2055             } else {
2056               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2057               if (istrans) {
2058                 Mat Bt;
2059 
2060                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2061                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2062               }
2063             }
2064             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);
2065           }
2066         }
2067       }
2068     }
2069     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
2070       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2071       if (fast) {
2072         PetscInt f, s;
2073 
2074         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
2075         if (f != nf || s != 1) {
2076           fast = PETSC_FALSE;
2077         } else {
2078           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2079           nf += f;
2080         }
2081       }
2082     }
2083     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
2084       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2085       if (fast) {
2086         PetscInt f, s;
2087 
2088         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
2089         if (f != nf || s != 1) {
2090           fast = PETSC_FALSE;
2091         } else {
2092           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2093           nf += f;
2094         }
2095       }
2096     }
2097     if (fast) {
2098       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
2099       PetscFunctionReturn(PETSC_SUCCESS);
2100     }
2101   }
2102   PetscCall(MatGetSize(A, &M, &N));
2103   PetscCall(MatGetLocalSize(A, &m, &n));
2104   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2105   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2106   else {
2107     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2108     PetscCall(MatSetType(C, newtype));
2109     PetscCall(MatSetSizes(C, m, n, M, N));
2110   }
2111   PetscCall(PetscMalloc1(2 * m, &dnnz));
2112   if (m) {
2113     onnz = dnnz + m;
2114     for (k = 0; k < m; k++) {
2115       dnnz[k] = 0;
2116       onnz[k] = 0;
2117     }
2118   }
2119   for (j = 0; j < nest->nc; ++j) {
2120     IS              bNis;
2121     PetscInt        bN;
2122     const PetscInt *bNindices;
2123     PetscBool       flg;
2124     /* Using global column indices and ISAllGather() is not scalable. */
2125     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
2126     PetscCall(ISGetSize(bNis, &bN));
2127     PetscCall(ISGetIndices(bNis, &bNindices));
2128     for (i = 0; i < nest->nr; ++i) {
2129       PetscSF         bmsf;
2130       PetscSFNode    *iremote;
2131       Mat             B = nest->m[i][j], D = NULL;
2132       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2133       const PetscInt *bmindices;
2134       if (!B) continue;
2135       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
2136       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
2137       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
2138       PetscCall(PetscMalloc1(bm, &iremote));
2139       PetscCall(PetscMalloc1(bm, &sub_dnnz));
2140       PetscCall(PetscMalloc1(bm, &sub_onnz));
2141       for (k = 0; k < bm; ++k) {
2142         sub_dnnz[k] = 0;
2143         sub_onnz[k] = 0;
2144       }
2145       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2146       if (flg) {
2147         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2148         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2149         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2150         B = D;
2151       }
2152       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2153       if (flg) {
2154         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2155         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2156         B = D;
2157       }
2158       /*
2159        Locate the owners for all of the locally-owned global row indices for this row block.
2160        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2161        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2162        */
2163       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2164       for (br = 0; br < bm; ++br) {
2165         PetscInt        row = bmindices[br], brncols, col;
2166         const PetscInt *brcols;
2167         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2168         PetscMPIInt     rowowner = 0;
2169         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2170         /* how many roots  */
2171         iremote[br].rank  = rowowner;
2172         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2173         /* get nonzero pattern */
2174         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2175         for (k = 0; k < brncols; k++) {
2176           col = bNindices[brcols[k]];
2177           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2178             sub_dnnz[br]++;
2179           } else {
2180             sub_onnz[br]++;
2181           }
2182         }
2183         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2184       }
2185       if (D) PetscCall(MatDestroy(&D));
2186       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2187       /* bsf will have to take care of disposing of bedges. */
2188       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
2189       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2190       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2191       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2192       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2193       PetscCall(PetscFree(sub_dnnz));
2194       PetscCall(PetscFree(sub_onnz));
2195       PetscCall(PetscSFDestroy(&bmsf));
2196     }
2197     PetscCall(ISRestoreIndices(bNis, &bNindices));
2198     PetscCall(ISDestroy(&bNis));
2199   }
2200   /* Resize preallocation if overestimated */
2201   for (i = 0; i < m; i++) {
2202     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
2203     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2204   }
2205   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
2206   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
2207   PetscCall(PetscFree(dnnz));
2208   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2209   if (reuse == MAT_INPLACE_MATRIX) {
2210     PetscCall(MatHeaderReplace(A, &C));
2211   } else *newmat = C;
2212   PetscFunctionReturn(PETSC_SUCCESS);
2213 }
2214 
2215 static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2216 {
2217   Mat      B;
2218   PetscInt m, n, M, N;
2219 
2220   PetscFunctionBegin;
2221   PetscCall(MatGetSize(A, &M, &N));
2222   PetscCall(MatGetLocalSize(A, &m, &n));
2223   if (reuse == MAT_REUSE_MATRIX) {
2224     B = *newmat;
2225     PetscCall(MatZeroEntries(B));
2226   } else {
2227     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2228   }
2229   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2230   if (reuse == MAT_INPLACE_MATRIX) {
2231     PetscCall(MatHeaderReplace(A, &B));
2232   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2233   PetscFunctionReturn(PETSC_SUCCESS);
2234 }
2235 
2236 static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2237 {
2238   Mat_Nest    *bA = (Mat_Nest *)mat->data;
2239   MatOperation opAdd;
2240   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
2241   PetscBool    flg;
2242 
2243   PetscFunctionBegin;
2244   *has = PETSC_FALSE;
2245   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
2246     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
2247     for (j = 0; j < nc; j++) {
2248       for (i = 0; i < nr; i++) {
2249         if (!bA->m[i][j]) continue;
2250         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
2251         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
2252       }
2253     }
2254   }
2255   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
2256   PetscFunctionReturn(PETSC_SUCCESS);
2257 }
2258 
2259 /*MC
2260   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2261 
2262   Level: intermediate
2263 
2264   Notes:
2265   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2266   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2267   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2268 
2269   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
2270   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
2271   than the nest matrix.
2272 
2273 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2274           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2275           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2276 M*/
2277 PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2278 {
2279   Mat_Nest *s;
2280 
2281   PetscFunctionBegin;
2282   PetscCall(PetscNew(&s));
2283   A->data = (void *)s;
2284 
2285   s->nr            = -1;
2286   s->nc            = -1;
2287   s->m             = NULL;
2288   s->splitassembly = PETSC_FALSE;
2289 
2290   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
2291 
2292   A->ops->mult                      = MatMult_Nest;
2293   A->ops->multadd                   = MatMultAdd_Nest;
2294   A->ops->multtranspose             = MatMultTranspose_Nest;
2295   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2296   A->ops->transpose                 = MatTranspose_Nest;
2297   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
2298   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2299   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2300   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2301   A->ops->zeroentries               = MatZeroEntries_Nest;
2302   A->ops->copy                      = MatCopy_Nest;
2303   A->ops->axpy                      = MatAXPY_Nest;
2304   A->ops->duplicate                 = MatDuplicate_Nest;
2305   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2306   A->ops->destroy                   = MatDestroy_Nest;
2307   A->ops->view                      = MatView_Nest;
2308   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2309   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2310   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2311   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2312   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2313   A->ops->scale                     = MatScale_Nest;
2314   A->ops->shift                     = MatShift_Nest;
2315   A->ops->diagonalset               = MatDiagonalSet_Nest;
2316   A->ops->setrandom                 = MatSetRandom_Nest;
2317   A->ops->hasoperation              = MatHasOperation_Nest;
2318   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2319 
2320   A->spptr     = NULL;
2321   A->assembled = PETSC_FALSE;
2322 
2323   /* expose Nest api's */
2324   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
2325   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
2326   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
2327   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
2328   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
2329   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
2330   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
2331   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
2332   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
2333   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
2334   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
2335   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
2336   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
2337   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
2338   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
2339   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2340 
2341   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
2342   PetscFunctionReturn(PETSC_SUCCESS);
2343 }
2344