xref: /petsc/src/mat/impls/nest/matnest.c (revision 8068ee9de151f573c8093756d0c3a381e30088ec)
1aaa7dc30SBarry Smith #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
2b68353e5Sstefano_zampini #include <../src/mat/impls/aij/seq/aij.h>
30c312b8eSJed Brown #include <petscsf.h>
4d8588912SDave May 
5c8883902SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat, PetscInt, const IS[], PetscInt, const IS[]);
606a1af2fSStefano Zampini static PetscErrorCode MatCreateVecs_Nest(Mat, Vec *, Vec *);
706a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat);
806a1af2fSStefano Zampini 
95e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat, MatType, MatReuse, Mat *);
10c8883902SJed Brown 
11d8588912SDave May /* private functions */
12d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N)
13d71ae5a4SJacob Faibussowitsch {
14d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
158188e55aSJed Brown   PetscInt  i, j;
16d8588912SDave May 
17d8588912SDave May   PetscFunctionBegin;
188188e55aSJed Brown   *m = *n = *M = *N = 0;
198188e55aSJed Brown   for (i = 0; i < bA->nr; i++) { /* rows */
208188e55aSJed Brown     PetscInt sm, sM;
219566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm));
229566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &sM));
238188e55aSJed Brown     *m += sm;
248188e55aSJed Brown     *M += sM;
25d8588912SDave May   }
268188e55aSJed Brown   for (j = 0; j < bA->nc; j++) { /* cols */
278188e55aSJed Brown     PetscInt sn, sN;
289566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn));
299566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &sN));
308188e55aSJed Brown     *n += sn;
318188e55aSJed Brown     *N += sN;
32d8588912SDave May   }
333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34d8588912SDave May }
35d8588912SDave May 
36d8588912SDave May /* operations */
37d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y)
38d71ae5a4SJacob Faibussowitsch {
39d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
40207556f9SJed Brown   Vec      *bx = bA->right, *by = bA->left;
41207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
42d8588912SDave May 
43d8588912SDave May   PetscFunctionBegin;
449566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i]));
459566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
46207556f9SJed Brown   for (i = 0; i < nr; i++) {
479566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[i]));
48207556f9SJed Brown     for (j = 0; j < nc; j++) {
49207556f9SJed Brown       if (!bA->m[i][j]) continue;
50d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
519566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i]));
52d8588912SDave May     }
53d8588912SDave May   }
549566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i]));
559566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57d8588912SDave May }
58d8588912SDave May 
59d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z)
60d71ae5a4SJacob Faibussowitsch {
619194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
629194d70fSJed Brown   Vec      *bx = bA->right, *bz = bA->left;
639194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
649194d70fSJed Brown 
659194d70fSJed Brown   PetscFunctionBegin;
669566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i]));
679566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
689194d70fSJed Brown   for (i = 0; i < nr; i++) {
699194d70fSJed Brown     if (y != z) {
709194d70fSJed Brown       Vec by;
719566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by));
729566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[i]));
739566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by));
749194d70fSJed Brown     }
759194d70fSJed Brown     for (j = 0; j < nc; j++) {
769194d70fSJed Brown       if (!bA->m[i][j]) continue;
779194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
789566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i]));
799194d70fSJed Brown     }
809194d70fSJed Brown   }
819566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i]));
829566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
849194d70fSJed Brown }
859194d70fSJed Brown 
8652c5f739Sprj- typedef struct {
8752c5f739Sprj-   Mat         *workC;      /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
8852c5f739Sprj-   PetscScalar *tarray;     /* buffer for storing all temporary products A[i][j] B[j] */
8952c5f739Sprj-   PetscInt    *dm, *dn, k; /* displacements and number of submatrices */
9052c5f739Sprj- } Nest_Dense;
9152c5f739Sprj- 
92a678f235SPierre Jolivet static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
93d71ae5a4SJacob Faibussowitsch {
946718818eSStefano Zampini   Mat_Nest          *bA;
9552c5f739Sprj-   Nest_Dense        *contents;
966718818eSStefano Zampini   Mat                viewB, viewC, productB, workC;
9752c5f739Sprj-   const PetscScalar *barray;
9852c5f739Sprj-   PetscScalar       *carray;
996718818eSStefano Zampini   PetscInt           i, j, M, N, nr, nc, ldb, ldc;
1006718818eSStefano Zampini   Mat                A, B;
10152c5f739Sprj- 
10252c5f739Sprj-   PetscFunctionBegin;
1030d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
1046718818eSStefano Zampini   A = C->product->A;
1056718818eSStefano Zampini   B = C->product->B;
1069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
1076718818eSStefano Zampini   if (!N) {
1089566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1099566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1116718818eSStefano Zampini   }
1126718818eSStefano Zampini   contents = (Nest_Dense *)C->product->data;
11328b400f6SJacob Faibussowitsch   PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
1146718818eSStefano Zampini   bA = (Mat_Nest *)A->data;
1156718818eSStefano Zampini   nr = bA->nr;
1166718818eSStefano Zampini   nc = bA->nc;
1179566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
1189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(C, &ldc));
1199566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(C));
1209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
1219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(C, &carray));
12252c5f739Sprj-   for (i = 0; i < nr; i++) {
1239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &M));
1248e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC));
1259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC, ldc));
12652c5f739Sprj-     for (j = 0; j < nc; j++) {
12752c5f739Sprj-       if (!bA->m[i][j]) continue;
1289566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
1298e3a54c0SPierre Jolivet       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
1309566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB, ldb));
1314222ddf1SHong Zhang 
1324222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1334222ddf1SHong Zhang       workC             = contents->workC[i * nc + j];
1344222ddf1SHong Zhang       productB          = workC->product->B;
1354222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1369566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1384222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1394222ddf1SHong Zhang 
14052c5f739Sprj-       /* C[i] <- workC + C[i] */
1419566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
14252c5f739Sprj-     }
1439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14452c5f739Sprj-   }
1459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C, &carray));
1469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
1474222ddf1SHong Zhang 
14867af85e8SPierre Jolivet   PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15252c5f739Sprj- }
15352c5f739Sprj- 
15466976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx)
155d71ae5a4SJacob Faibussowitsch {
15652c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15752c5f739Sprj-   PetscInt    i;
15852c5f739Sprj- 
15952c5f739Sprj-   PetscFunctionBegin;
1609566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16148a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1629566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1639566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
1643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16552c5f739Sprj- }
16652c5f739Sprj- 
167a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
168d71ae5a4SJacob Faibussowitsch {
1696718818eSStefano Zampini   Mat_Nest          *bA;
1706718818eSStefano Zampini   Mat                viewB, workC;
17152c5f739Sprj-   const PetscScalar *barray;
1726718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1734222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1746718818eSStefano Zampini   PetscBool          cisdense;
1756718818eSStefano Zampini   Mat                A, B;
1766718818eSStefano Zampini   PetscReal          fill;
17752c5f739Sprj- 
17852c5f739Sprj-   PetscFunctionBegin;
1790d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
18028b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1816718818eSStefano Zampini   A    = C->product->A;
1826718818eSStefano Zampini   B    = C->product->B;
1836718818eSStefano Zampini   fill = C->product->fill;
1846718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1856718818eSStefano Zampini   nr   = bA->nr;
1866718818eSStefano Zampini   nc   = bA->nc;
1879566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1889566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1890572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1909566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1919566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1939566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1949566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1950572eedcSPierre Jolivet   }
1969566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19748a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1989566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
1996718818eSStefano Zampini   if (!N) {
2006718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2013ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20252c5f739Sprj-   }
20352c5f739Sprj- 
2049566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2056718818eSStefano Zampini   C->product->data    = contents;
2066718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2079566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20852c5f739Sprj-   contents->k = nr * nc;
20952c5f739Sprj-   for (i = 0; i < nr; i++) {
2109566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
21152c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
21252c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
21352c5f739Sprj-   }
21452c5f739Sprj-   for (i = 0; i < nc; i++) {
2159566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
21652c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21752c5f739Sprj-   }
2189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2199566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2209566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
22252c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22352c5f739Sprj-   for (j = 0; j < nc; j++) {
2249566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
2258e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
2269566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22752c5f739Sprj-     for (i = 0; i < nr; i++) {
22852c5f739Sprj-       if (!bA->m[i][j]) continue;
22952c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2304222ddf1SHong Zhang 
2319566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2324222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2339566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2349566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2359566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2379566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2384222ddf1SHong Zhang 
2396718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2409566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2419566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
24252c5f739Sprj-     }
2439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24452c5f739Sprj-   }
2459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
24652c5f739Sprj- 
2476718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24952c5f739Sprj- }
25052c5f739Sprj- 
251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
252d71ae5a4SJacob Faibussowitsch {
2534222ddf1SHong Zhang   PetscFunctionBegin;
2546718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2564222ddf1SHong Zhang }
2574222ddf1SHong Zhang 
258a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
259d71ae5a4SJacob Faibussowitsch {
2604222ddf1SHong Zhang   Mat_Product *product = C->product;
26152c5f739Sprj- 
26252c5f739Sprj-   PetscFunctionBegin;
26348a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26552c5f739Sprj- }
26652c5f739Sprj- 
2670998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm)
268d71ae5a4SJacob Faibussowitsch {
269d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
270207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
271207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
272d8588912SDave May 
273d8588912SDave May   PetscFunctionBegin;
2749566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2759566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
276207556f9SJed Brown   for (j = 0; j < nc; j++) {
2779566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
278609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2796c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2800998551bSBlanca Mellado Pinto       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */
2810998551bSBlanca Mellado Pinto       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));               /* y[j] <- y[j] + (A[i][j])^T * x[i] */
282d8588912SDave May     }
283d8588912SDave May   }
2849566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2859566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
287d8588912SDave May }
288d8588912SDave May 
2890998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
2900998551bSBlanca Mellado Pinto {
2910998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2920998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE));
2930998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
2940998551bSBlanca Mellado Pinto }
2950998551bSBlanca Mellado Pinto 
2960998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y)
2970998551bSBlanca Mellado Pinto {
2980998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2990998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE));
3000998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3010998551bSBlanca Mellado Pinto }
3020998551bSBlanca Mellado Pinto 
3030998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm)
304d71ae5a4SJacob Faibussowitsch {
3059194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
3069194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
3079194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
3089194d70fSJed Brown 
3099194d70fSJed Brown   PetscFunctionBegin;
3109566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
3119566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
3129194d70fSJed Brown   for (j = 0; j < nc; j++) {
3139194d70fSJed Brown     if (y != z) {
3149194d70fSJed Brown       Vec by;
3159566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3169566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3179566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3189194d70fSJed Brown     }
3199194d70fSJed Brown     for (i = 0; i < nr; i++) {
3206c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3210998551bSBlanca Mellado Pinto       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */
3220998551bSBlanca Mellado Pinto       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));               /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3239194d70fSJed Brown     }
3249194d70fSJed Brown   }
3259566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3269566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3289194d70fSJed Brown }
3299194d70fSJed Brown 
3300998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
3310998551bSBlanca Mellado Pinto {
3320998551bSBlanca Mellado Pinto   PetscFunctionBegin;
3330998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE));
3340998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3350998551bSBlanca Mellado Pinto }
3360998551bSBlanca Mellado Pinto 
3370998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
3380998551bSBlanca Mellado Pinto {
3390998551bSBlanca Mellado Pinto   PetscFunctionBegin;
3400998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE));
3410998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3420998551bSBlanca Mellado Pinto }
3430998551bSBlanca Mellado Pinto 
344d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
345d71ae5a4SJacob Faibussowitsch {
346f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
347f8170845SAlex Fikl   Mat       C;
348f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
349f8170845SAlex Fikl 
350f8170845SAlex Fikl   PetscFunctionBegin;
3517fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
352aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
353f8170845SAlex Fikl 
354cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
355f8170845SAlex Fikl     Mat *subs;
356f8170845SAlex Fikl     IS  *is_row, *is_col;
357f8170845SAlex Fikl 
3589566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3609566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
361cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
362ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
363ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
364ddeb9bd8SAlex Fikl       }
365ddeb9bd8SAlex Fikl     }
366ddeb9bd8SAlex Fikl 
3679566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3689566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3699566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
370f8170845SAlex Fikl   } else {
371f8170845SAlex Fikl     C = *B;
372f8170845SAlex Fikl   }
373f8170845SAlex Fikl 
374f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
375f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
376f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
377f8170845SAlex Fikl       if (bA->m[i][j]) {
3789566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
379f8170845SAlex Fikl       } else {
380f8170845SAlex Fikl         bC->m[j][i] = NULL;
381f8170845SAlex Fikl       }
382f8170845SAlex Fikl     }
383f8170845SAlex Fikl   }
384f8170845SAlex Fikl 
385cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
386f8170845SAlex Fikl     *B = C;
387f8170845SAlex Fikl   } else {
3889566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
389f8170845SAlex Fikl   }
3903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
391f8170845SAlex Fikl }
392f8170845SAlex Fikl 
393d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
394d71ae5a4SJacob Faibussowitsch {
395e2d7f03fSJed Brown   IS      *lst = *list;
396e2d7f03fSJed Brown   PetscInt i;
397e2d7f03fSJed Brown 
398e2d7f03fSJed Brown   PetscFunctionBegin;
3993ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
4009371c9d4SSatish Balay   for (i = 0; i < n; i++)
4019371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
4029566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
4030298fd71SBarry Smith   *list = NULL;
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
405e2d7f03fSJed Brown }
406e2d7f03fSJed Brown 
407d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
408d71ae5a4SJacob Faibussowitsch {
409d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
410d8588912SDave May   PetscInt  i, j;
411d8588912SDave May 
412d8588912SDave May   PetscFunctionBegin;
413d8588912SDave May   /* release the matrices and the place holders */
4149566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
4159566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
4169566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
4179566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
418d8588912SDave May 
4199566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
4209566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
4219566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
422d8588912SDave May 
4239566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
424207556f9SJed Brown 
425d8588912SDave May   /* release the matrices and the place holders */
426d8588912SDave May   if (vs->m) {
427d8588912SDave May     for (i = 0; i < vs->nr; i++) {
42848a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
429d8588912SDave May     }
430*8068ee9dSPierre Jolivet     PetscCall(PetscFree(vs->m[0]));
4319566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
432d8588912SDave May   }
43306a1af2fSStefano Zampini 
43406a1af2fSStefano Zampini   /* restore defaults */
43506a1af2fSStefano Zampini   vs->nr            = 0;
43606a1af2fSStefano Zampini   vs->nc            = 0;
43706a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43906a1af2fSStefano Zampini }
44006a1af2fSStefano Zampini 
441d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
442d71ae5a4SJacob Faibussowitsch {
443362febeeSStefano Zampini   PetscFunctionBegin;
4449566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4459566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL));
4633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
464d8588912SDave May }
465d8588912SDave May 
466d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
467d71ae5a4SJacob Faibussowitsch {
468381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
469381b8e50SStefano Zampini   PetscInt  i;
470381b8e50SStefano Zampini 
471381b8e50SStefano Zampini   PetscFunctionBegin;
472381b8e50SStefano Zampini   if (dd) *dd = 0;
473381b8e50SStefano Zampini   if (!vs->nr) {
474381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4753ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
476381b8e50SStefano Zampini   }
477381b8e50SStefano Zampini   *missing = PETSC_FALSE;
478381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
479381b8e50SStefano Zampini     *missing = PETSC_TRUE;
480381b8e50SStefano Zampini     if (vs->m[i][i]) {
4819566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
48208401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
483381b8e50SStefano Zampini     }
484381b8e50SStefano Zampini   }
4853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
486381b8e50SStefano Zampini }
487381b8e50SStefano Zampini 
488d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
489d71ae5a4SJacob Faibussowitsch {
490d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
491d8588912SDave May   PetscInt  i, j;
49206a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
493d8588912SDave May 
494d8588912SDave May   PetscFunctionBegin;
495d8588912SDave May   for (i = 0; i < vs->nr; i++) {
496d8588912SDave May     for (j = 0; j < vs->nc; j++) {
49706a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
498e7c19651SJed Brown       if (vs->m[i][j]) {
4999566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
500e7c19651SJed Brown         if (!vs->splitassembly) {
501e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
502e7c19651SJed Brown            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
503e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
504e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
505e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
506e7c19651SJed Brown            */
5079566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
5089566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
509e7c19651SJed Brown         }
510e7c19651SJed Brown       }
51106a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
51206a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
513d8588912SDave May     }
514d8588912SDave May   }
51506a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
5163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
517d8588912SDave May }
518d8588912SDave May 
519d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
520d71ae5a4SJacob Faibussowitsch {
521d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
522d8588912SDave May   PetscInt  i, j;
523d8588912SDave May 
524d8588912SDave May   PetscFunctionBegin;
525d8588912SDave May   for (i = 0; i < vs->nr; i++) {
526d8588912SDave May     for (j = 0; j < vs->nc; j++) {
527e7c19651SJed Brown       if (vs->m[i][j]) {
52848a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
529e7c19651SJed Brown       }
530d8588912SDave May     }
531d8588912SDave May   }
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
533d8588912SDave May }
534d8588912SDave May 
535d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
536d71ae5a4SJacob Faibussowitsch {
537f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
538f349c1fdSJed Brown   PetscInt  j;
539f349c1fdSJed Brown   Mat       sub;
540d8588912SDave May 
541d8588912SDave May   PetscFunctionBegin;
5420298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
543f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5449566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
545f349c1fdSJed Brown   *B = sub;
5463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
547d8588912SDave May }
548d8588912SDave May 
549d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
550d71ae5a4SJacob Faibussowitsch {
551f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
552f349c1fdSJed Brown   PetscInt  i;
553f349c1fdSJed Brown   Mat       sub;
554f349c1fdSJed Brown 
555f349c1fdSJed Brown   PetscFunctionBegin;
5560298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
557f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5589566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
559f349c1fdSJed Brown   *B = sub;
5603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
561d8588912SDave May }
562d8588912SDave May 
563d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
564d71ae5a4SJacob Faibussowitsch {
56518d228c0SPierre Jolivet   PetscInt  i, j, size, m;
566f349c1fdSJed Brown   PetscBool flg;
56718d228c0SPierre Jolivet   IS        out, concatenate[2];
568f349c1fdSJed Brown 
569f349c1fdSJed Brown   PetscFunctionBegin;
5704f572ea9SToby Isaac   PetscAssertPointer(list, 3);
571f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
57218d228c0SPierre Jolivet   if (begin) {
5734f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
57418d228c0SPierre Jolivet     *begin = -1;
57518d228c0SPierre Jolivet   }
57618d228c0SPierre Jolivet   if (end) {
5774f572ea9SToby Isaac     PetscAssertPointer(end, 6);
57818d228c0SPierre Jolivet     *end = -1;
57918d228c0SPierre Jolivet   }
580f349c1fdSJed Brown   for (i = 0; i < n; i++) {
581207556f9SJed Brown     if (!list[i]) continue;
5829566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
583f349c1fdSJed Brown     if (flg) {
58418d228c0SPierre Jolivet       if (begin) *begin = i;
58518d228c0SPierre Jolivet       if (end) *end = i + 1;
5863ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
587f349c1fdSJed Brown     }
588f349c1fdSJed Brown   }
5899566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
59018d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
59118d228c0SPierre Jolivet     if (!list[i]) continue;
59218d228c0SPierre Jolivet     m = 0;
5939566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5949566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
59518d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
59618d228c0SPierre Jolivet       if (list[j]) {
59718d228c0SPierre Jolivet         concatenate[0] = out;
59818d228c0SPierre Jolivet         concatenate[1] = list[j];
5999566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
6009566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
6019566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
60218d228c0SPierre Jolivet       }
60318d228c0SPierre Jolivet     }
60418d228c0SPierre Jolivet     if (m == size) {
6059566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
60618d228c0SPierre Jolivet       if (flg) {
60718d228c0SPierre Jolivet         if (begin) *begin = i;
60818d228c0SPierre Jolivet         if (end) *end = j;
6099566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
6103ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
61118d228c0SPierre Jolivet       }
61218d228c0SPierre Jolivet     }
6139566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
61418d228c0SPierre Jolivet   }
6153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
616f349c1fdSJed Brown }
617f349c1fdSJed Brown 
618d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
619d71ae5a4SJacob Faibussowitsch {
6208188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
62118d228c0SPierre Jolivet   PetscInt  lr, lc;
62218d228c0SPierre Jolivet 
62318d228c0SPierre Jolivet   PetscFunctionBegin;
6249566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
6259566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
6269566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
6279566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
6289566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6299566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6309566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6319566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6329566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6339566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63618d228c0SPierre Jolivet }
63718d228c0SPierre Jolivet 
638d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
639d71ae5a4SJacob Faibussowitsch {
64018d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
64118d228c0SPierre Jolivet   Mat       *a;
64218d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6438188e55aSJed Brown   char       keyname[256];
64418d228c0SPierre Jolivet   PetscBool *b;
64518d228c0SPierre Jolivet   PetscBool  flg;
6468188e55aSJed Brown 
6478188e55aSJed Brown   PetscFunctionBegin;
6480298fd71SBarry Smith   *B = NULL;
6499566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6509566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6513ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6528188e55aSJed Brown 
6539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
65418d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
65518d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
65618d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
65718d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
65818d228c0SPierre Jolivet     }
65918d228c0SPierre Jolivet   }
66018d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
66118d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
66218d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
66318d228c0SPierre Jolivet         flg = PETSC_FALSE;
66418d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
66518d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
66618d228c0SPierre Jolivet         }
66718d228c0SPierre Jolivet         if (flg) {
66818d228c0SPierre Jolivet           flg = PETSC_FALSE;
66918d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
67018d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
67118d228c0SPierre Jolivet           }
67218d228c0SPierre Jolivet         }
67318d228c0SPierre Jolivet         if (!flg) {
67418d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6759566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
67618d228c0SPierre Jolivet         }
67718d228c0SPierre Jolivet       }
67818d228c0SPierre Jolivet     }
67918d228c0SPierre Jolivet   }
6809566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
68118d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
68218d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
68348a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
68418d228c0SPierre Jolivet     }
68518d228c0SPierre Jolivet   }
6869566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6878188e55aSJed Brown   (*B)->assembled = A->assembled;
6889566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6899566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6918188e55aSJed Brown }
6928188e55aSJed Brown 
693d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
694d71ae5a4SJacob Faibussowitsch {
695f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
69618d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
697f349c1fdSJed Brown 
698f349c1fdSJed Brown   PetscFunctionBegin;
6999566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
7009566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
70118d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
70248a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
70318d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
70418d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
7059566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
70618d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
7073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
708f349c1fdSJed Brown }
709f349c1fdSJed Brown 
71006a1af2fSStefano Zampini /*
71106a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
71206a1af2fSStefano Zampini */
713d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
714d71ae5a4SJacob Faibussowitsch {
715f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
716f349c1fdSJed Brown   Mat       sub;
717f349c1fdSJed Brown 
718f349c1fdSJed Brown   PetscFunctionBegin;
7199566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
720f349c1fdSJed Brown   switch (reuse) {
721f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
7229566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
723f349c1fdSJed Brown     *B = sub;
724f349c1fdSJed Brown     break;
725d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
726d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
727d71ae5a4SJacob Faibussowitsch     break;
728d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
729d71ae5a4SJacob Faibussowitsch     break;
730d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
731d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
732f349c1fdSJed Brown   }
7333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
734f349c1fdSJed Brown }
735f349c1fdSJed Brown 
73666976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
737d71ae5a4SJacob Faibussowitsch {
738f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
739f349c1fdSJed Brown   Mat       sub;
740f349c1fdSJed Brown 
741f349c1fdSJed Brown   PetscFunctionBegin;
7429566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
743f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7449566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
745f349c1fdSJed Brown   *B = sub;
7463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
747d8588912SDave May }
748d8588912SDave May 
749d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
750d71ae5a4SJacob Faibussowitsch {
751f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
752f349c1fdSJed Brown   Mat       sub;
753d8588912SDave May 
754d8588912SDave May   PetscFunctionBegin;
7559566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
75608401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
757f349c1fdSJed Brown   if (sub) {
758aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7599566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
760d8588912SDave May   }
7613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
762d8588912SDave May }
763d8588912SDave May 
764d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
765d71ae5a4SJacob Faibussowitsch {
7667874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7677874fa86SDave May   PetscInt  i;
7687874fa86SDave May 
7697874fa86SDave May   PetscFunctionBegin;
7707874fa86SDave May   for (i = 0; i < bA->nr; i++) {
771429bac76SJed Brown     Vec bv;
7729566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7737874fa86SDave May     if (bA->m[i][i]) {
7749566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7757874fa86SDave May     } else {
7769566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7777874fa86SDave May     }
7789566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7797874fa86SDave May   }
7803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7817874fa86SDave May }
7827874fa86SDave May 
783d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
784d71ae5a4SJacob Faibussowitsch {
7857874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
786429bac76SJed Brown   Vec       bl, *br;
7877874fa86SDave May   PetscInt  i, j;
7887874fa86SDave May 
7897874fa86SDave May   PetscFunctionBegin;
7909566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7912e6472ebSElliott Sales de Andrade   if (r) {
7929566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7932e6472ebSElliott Sales de Andrade   }
7942e6472ebSElliott Sales de Andrade   bl = NULL;
7957874fa86SDave May   for (i = 0; i < bA->nr; i++) {
79648a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7977874fa86SDave May     for (j = 0; j < bA->nc; j++) {
79848a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7997874fa86SDave May     }
80048a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
8012e6472ebSElliott Sales de Andrade   }
8022e6472ebSElliott Sales de Andrade   if (r) {
8039566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
8042e6472ebSElliott Sales de Andrade   }
8059566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
8063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8077874fa86SDave May }
8087874fa86SDave May 
809d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
810d71ae5a4SJacob Faibussowitsch {
811a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
812a061e289SJed Brown   PetscInt  i, j;
813a061e289SJed Brown 
814a061e289SJed Brown   PetscFunctionBegin;
815a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
816a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
81748a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
818a061e289SJed Brown     }
819a061e289SJed Brown   }
8203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
821a061e289SJed Brown }
822a061e289SJed Brown 
823d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
824d71ae5a4SJacob Faibussowitsch {
825a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
826a061e289SJed Brown   PetscInt  i;
82706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
828a061e289SJed Brown 
829a061e289SJed Brown   PetscFunctionBegin;
830a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
83106a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
83208401ef6SPierre Jolivet     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);
8339566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8349566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
83506a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
83606a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
837a061e289SJed Brown   }
83806a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
840a061e289SJed Brown }
841a061e289SJed Brown 
842d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
843d71ae5a4SJacob Faibussowitsch {
84413135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
84513135bc6SAlex Fikl   PetscInt  i;
84606a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
84713135bc6SAlex Fikl 
84813135bc6SAlex Fikl   PetscFunctionBegin;
84913135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
85006a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
85113135bc6SAlex Fikl     Vec              bv;
8529566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
85313135bc6SAlex Fikl     if (bA->m[i][i]) {
8549566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8559566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
85613135bc6SAlex Fikl     }
8579566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
85806a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
85906a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
86013135bc6SAlex Fikl   }
86106a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86313135bc6SAlex Fikl }
86413135bc6SAlex Fikl 
865d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
866d71ae5a4SJacob Faibussowitsch {
867f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
868f8170845SAlex Fikl   PetscInt  i, j;
869f8170845SAlex Fikl 
870f8170845SAlex Fikl   PetscFunctionBegin;
871f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
872f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
87348a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
874f8170845SAlex Fikl     }
875f8170845SAlex Fikl   }
8763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
877f8170845SAlex Fikl }
878f8170845SAlex Fikl 
879d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
880d71ae5a4SJacob Faibussowitsch {
881d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
882d8588912SDave May   Vec      *L, *R;
883d8588912SDave May   MPI_Comm  comm;
884d8588912SDave May   PetscInt  i, j;
885d8588912SDave May 
886d8588912SDave May   PetscFunctionBegin;
8879566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
888d8588912SDave May   if (right) {
889d8588912SDave May     /* allocate R */
8909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
891d8588912SDave May     /* Create the right vectors */
892d8588912SDave May     for (j = 0; j < bA->nc; j++) {
893d8588912SDave May       for (i = 0; i < bA->nr; i++) {
894d8588912SDave May         if (bA->m[i][j]) {
8959566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
896d8588912SDave May           break;
897d8588912SDave May         }
898d8588912SDave May       }
89908401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
900d8588912SDave May     }
9019566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
902d8588912SDave May     /* hand back control to the nest vector */
90348a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
9049566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
905d8588912SDave May   }
906d8588912SDave May 
907d8588912SDave May   if (left) {
908d8588912SDave May     /* allocate L */
9099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
910d8588912SDave May     /* Create the left vectors */
911d8588912SDave May     for (i = 0; i < bA->nr; i++) {
912d8588912SDave May       for (j = 0; j < bA->nc; j++) {
913d8588912SDave May         if (bA->m[i][j]) {
9149566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
915d8588912SDave May           break;
916d8588912SDave May         }
917d8588912SDave May       }
91808401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
919d8588912SDave May     }
920d8588912SDave May 
9219566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
92248a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
923d8588912SDave May 
9249566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
925d8588912SDave May   }
9263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
927d8588912SDave May }
928d8588912SDave May 
929d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
930d71ae5a4SJacob Faibussowitsch {
931d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
93229e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
933d8588912SDave May   PetscInt  i, j;
934d8588912SDave May 
935d8588912SDave May   PetscFunctionBegin;
9369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
937d8588912SDave May   if (isascii) {
9389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
9409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9419566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
942d8588912SDave May 
9439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
944d8588912SDave May     for (i = 0; i < bA->nr; i++) {
945d8588912SDave May       for (j = 0; j < bA->nc; j++) {
94619fd82e9SBarry Smith         MatType   type;
947270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
948d8588912SDave May         PetscInt  NR, NC;
949d8588912SDave May         PetscBool isNest = PETSC_FALSE;
950d8588912SDave May 
951d8588912SDave May         if (!bA->m[i][j]) {
9529566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
953d8588912SDave May           continue;
954d8588912SDave May         }
9559566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9569566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9579566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9589566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9599566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
960d8588912SDave May 
9619566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", i, j, name, prefix, type, NR, NC));
962d8588912SDave May 
96329e60adbSStefano Zampini         if (isNest || viewSub) {
9649566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9659566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9669566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
967d8588912SDave May         }
968d8588912SDave May       }
969d8588912SDave May     }
9709566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
971d8588912SDave May   }
9723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
973d8588912SDave May }
974d8588912SDave May 
975d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
976d71ae5a4SJacob Faibussowitsch {
977d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
978d8588912SDave May   PetscInt  i, j;
979d8588912SDave May 
980d8588912SDave May   PetscFunctionBegin;
981d8588912SDave May   for (i = 0; i < bA->nr; i++) {
982d8588912SDave May     for (j = 0; j < bA->nc; j++) {
983d8588912SDave May       if (!bA->m[i][j]) continue;
9849566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
985d8588912SDave May     }
986d8588912SDave May   }
9873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
988d8588912SDave May }
989d8588912SDave May 
990d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
991d71ae5a4SJacob Faibussowitsch {
992c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
993c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
99406a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
995c222c20dSDavid Ham 
996c222c20dSDavid Ham   PetscFunctionBegin;
997aed4548fSBarry Smith   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);
998c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
999c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
100006a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
100146a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
10029566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
100308401ef6SPierre Jolivet       } else PetscCheck(!bA->m[i][j] && !bB->m[i][j], PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT, i, j);
10049566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
100506a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
100606a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
1007c222c20dSDavid Ham     }
1008c222c20dSDavid Ham   }
100906a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
10103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1011c222c20dSDavid Ham }
1012c222c20dSDavid Ham 
1013d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1014d71ae5a4SJacob Faibussowitsch {
10156e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
10166e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
101706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
10186e76ffeaSPierre Jolivet 
10196e76ffeaSPierre Jolivet   PetscFunctionBegin;
1020aed4548fSBarry Smith   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);
10216e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
10226e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
102306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10246e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10259566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1026c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1027c066aebcSStefano Zampini         Mat M;
1028c066aebcSStefano Zampini 
1029e75569e9SPierre Jolivet         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);
10309566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10319566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10329566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1033c066aebcSStefano Zampini       }
10349566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
103506a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
103606a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10376e76ffeaSPierre Jolivet     }
10386e76ffeaSPierre Jolivet   }
103906a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10416e76ffeaSPierre Jolivet }
10426e76ffeaSPierre Jolivet 
1043d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1044d71ae5a4SJacob Faibussowitsch {
1045d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1046841e96a3SJed Brown   Mat      *b;
1047841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1048d8588912SDave May 
1049d8588912SDave May   PetscFunctionBegin;
10509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1051841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1052841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1053841e96a3SJed Brown       if (bA->m[i][j]) {
10549566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1055841e96a3SJed Brown       } else {
10560298fd71SBarry Smith         b[i * nc + j] = NULL;
1057d8588912SDave May       }
1058d8588912SDave May     }
1059d8588912SDave May   }
10609566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1061841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
106248a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10639566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1064d8588912SDave May 
10659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1068d8588912SDave May }
1069d8588912SDave May 
1070d8588912SDave May /* nest api */
107166976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1072d71ae5a4SJacob Faibussowitsch {
1073d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10745fd66863SKarl Rupp 
1075d8588912SDave May   PetscFunctionBegin;
107608401ef6SPierre Jolivet   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
107708401ef6SPierre Jolivet   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1078d8588912SDave May   *mat = bA->m[idxm][jdxm];
10793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1080d8588912SDave May }
1081d8588912SDave May 
10829ba0d327SJed Brown /*@
108311a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1084d8588912SDave May 
10852ef1f0ffSBarry Smith   Not Collective
1086d8588912SDave May 
1087d8588912SDave May   Input Parameters:
108811a5261eSBarry Smith + A    - `MATNEST` matrix
1089d8588912SDave May . idxm - index of the matrix within the nest matrix
1090629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1091d8588912SDave May 
1092d8588912SDave May   Output Parameter:
10932ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1094d8588912SDave May 
1095d8588912SDave May   Level: developer
1096d8588912SDave May 
1097fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1098db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1099d8588912SDave May @*/
1100d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1101d71ae5a4SJacob Faibussowitsch {
1102d8588912SDave May   PetscFunctionBegin;
1103cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
11043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1105d8588912SDave May }
1106d8588912SDave May 
110766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1108d71ae5a4SJacob Faibussowitsch {
11090782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
11100782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
11110782ca92SJed Brown 
11120782ca92SJed Brown   PetscFunctionBegin;
111308401ef6SPierre Jolivet   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
111408401ef6SPierre Jolivet   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
11159566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
11169566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
11179566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
11189566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
11199566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
11209566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1121aed4548fSBarry Smith   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);
1122aed4548fSBarry Smith   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);
112326fbe8dcSKarl Rupp 
112406a1af2fSStefano Zampini   /* do not increase object state */
11253ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
112606a1af2fSStefano Zampini 
11279566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11290782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11309566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11319566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
113206a1af2fSStefano Zampini   A->nonzerostate++;
11333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11340782ca92SJed Brown }
11350782ca92SJed Brown 
11369ba0d327SJed Brown /*@
113711a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11380782ca92SJed Brown 
11392ef1f0ffSBarry Smith   Logically Collective
11400782ca92SJed Brown 
11410782ca92SJed Brown   Input Parameters:
114211a5261eSBarry Smith + A    - `MATNEST` matrix
11430782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11440782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11452ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11462ef1f0ffSBarry Smith 
11472ef1f0ffSBarry Smith   Level: developer
11480782ca92SJed Brown 
11490782ca92SJed Brown   Notes:
11500782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11510782ca92SJed Brown 
11520782ca92SJed Brown   This increments the reference count of the submatrix.
11530782ca92SJed Brown 
1154fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1155db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11560782ca92SJed Brown @*/
1157d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1158d71ae5a4SJacob Faibussowitsch {
11590782ca92SJed Brown   PetscFunctionBegin;
1160cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11620782ca92SJed Brown }
11630782ca92SJed Brown 
116466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1165d71ae5a4SJacob Faibussowitsch {
1166d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11675fd66863SKarl Rupp 
1168d8588912SDave May   PetscFunctionBegin;
116926fbe8dcSKarl Rupp   if (M) *M = bA->nr;
117026fbe8dcSKarl Rupp   if (N) *N = bA->nc;
117126fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1173d8588912SDave May }
1174d8588912SDave May 
1175d8588912SDave May /*@C
117611a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1177d8588912SDave May 
11782ef1f0ffSBarry Smith   Not Collective
1179d8588912SDave May 
1180f899ff85SJose E. Roman   Input Parameter:
1181629881c0SJed Brown . A - nest matrix
1182d8588912SDave May 
1183d8d19677SJose E. Roman   Output Parameters:
1184629881c0SJed Brown + M   - number of rows in the nest matrix
1185d8588912SDave May . N   - number of cols in the nest matrix
1186e9d3347aSJose E. Roman - mat - array of matrices
1187d8588912SDave May 
11882ef1f0ffSBarry Smith   Level: developer
11892ef1f0ffSBarry Smith 
119011a5261eSBarry Smith   Note:
11912ef1f0ffSBarry Smith   The user should not free the array `mat`.
1192d8588912SDave May 
1193fe59aa6dSJacob Faibussowitsch   Fortran Notes:
119411a5261eSBarry Smith   This routine has a calling sequence
1195351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
119620f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1197e9d3347aSJose E. Roman   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1198351962e3SVincent Le Chenadec 
1199fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1200db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1201d8588912SDave May @*/
1202d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1203d71ae5a4SJacob Faibussowitsch {
1204d8588912SDave May   PetscFunctionBegin;
1205cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
12063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1207d8588912SDave May }
1208d8588912SDave May 
120966976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1210d71ae5a4SJacob Faibussowitsch {
1211d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1212d8588912SDave May 
1213d8588912SDave May   PetscFunctionBegin;
121426fbe8dcSKarl Rupp   if (M) *M = bA->nr;
121526fbe8dcSKarl Rupp   if (N) *N = bA->nc;
12163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1217d8588912SDave May }
1218d8588912SDave May 
12199ba0d327SJed Brown /*@
122011a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1221d8588912SDave May 
12222ef1f0ffSBarry Smith   Not Collective
1223d8588912SDave May 
1224f899ff85SJose E. Roman   Input Parameter:
122511a5261eSBarry Smith . A - `MATNEST` matrix
1226d8588912SDave May 
1227d8d19677SJose E. Roman   Output Parameters:
1228629881c0SJed Brown + M - number of rows in the nested mat
1229629881c0SJed Brown - N - number of cols in the nested mat
1230d8588912SDave May 
1231d8588912SDave May   Level: developer
1232d8588912SDave May 
1233fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1234db781477SPatrick Sanan           `MatNestGetISs()`
1235d8588912SDave May @*/
1236d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1237d71ae5a4SJacob Faibussowitsch {
1238d8588912SDave May   PetscFunctionBegin;
1239cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1241d8588912SDave May }
1242d8588912SDave May 
1243d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1244d71ae5a4SJacob Faibussowitsch {
1245900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1246900e7ff2SJed Brown   PetscInt  i;
1247900e7ff2SJed Brown 
1248900e7ff2SJed Brown   PetscFunctionBegin;
12499371c9d4SSatish Balay   if (rows)
12509371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12519371c9d4SSatish Balay   if (cols)
12529371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1254900e7ff2SJed Brown }
1255900e7ff2SJed Brown 
12563a4d7b9aSSatish Balay /*@C
125711a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1258900e7ff2SJed Brown 
12592ef1f0ffSBarry Smith   Not Collective
1260900e7ff2SJed Brown 
1261f899ff85SJose E. Roman   Input Parameter:
126211a5261eSBarry Smith . A - `MATNEST` matrix
1263900e7ff2SJed Brown 
1264d8d19677SJose E. Roman   Output Parameters:
1265900e7ff2SJed Brown + rows - array of row index sets
1266900e7ff2SJed Brown - cols - array of column index sets
1267900e7ff2SJed Brown 
1268900e7ff2SJed Brown   Level: advanced
1269900e7ff2SJed Brown 
127011a5261eSBarry Smith   Note:
12712ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1272900e7ff2SJed Brown 
1273fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1274fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1275900e7ff2SJed Brown @*/
1276d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1277d71ae5a4SJacob Faibussowitsch {
1278900e7ff2SJed Brown   PetscFunctionBegin;
1279900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1280cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1282900e7ff2SJed Brown }
1283900e7ff2SJed Brown 
1284d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1285d71ae5a4SJacob Faibussowitsch {
1286900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1287900e7ff2SJed Brown   PetscInt  i;
1288900e7ff2SJed Brown 
1289900e7ff2SJed Brown   PetscFunctionBegin;
12909371c9d4SSatish Balay   if (rows)
12919371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12929371c9d4SSatish Balay   if (cols)
12939371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
12943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1295900e7ff2SJed Brown }
1296900e7ff2SJed Brown 
1297900e7ff2SJed Brown /*@C
129811a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1299900e7ff2SJed Brown 
13002ef1f0ffSBarry Smith   Not Collective
1301900e7ff2SJed Brown 
1302f899ff85SJose E. Roman   Input Parameter:
130311a5261eSBarry Smith . A - `MATNEST` matrix
1304900e7ff2SJed Brown 
1305d8d19677SJose E. Roman   Output Parameters:
13062ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore)
13072ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore)
1308900e7ff2SJed Brown 
1309900e7ff2SJed Brown   Level: advanced
1310900e7ff2SJed Brown 
131111a5261eSBarry Smith   Note:
13122ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1313900e7ff2SJed Brown 
13141cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1315fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1316900e7ff2SJed Brown @*/
1317d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1318d71ae5a4SJacob Faibussowitsch {
1319900e7ff2SJed Brown   PetscFunctionBegin;
1320900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1321cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
13223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1323900e7ff2SJed Brown }
1324900e7ff2SJed Brown 
132566976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1326d71ae5a4SJacob Faibussowitsch {
1327207556f9SJed Brown   PetscBool flg;
1328207556f9SJed Brown 
1329207556f9SJed Brown   PetscFunctionBegin;
13309566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1331207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13322a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
133312b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
13343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1335207556f9SJed Brown }
1336207556f9SJed Brown 
1337207556f9SJed Brown /*@C
133811a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1339207556f9SJed Brown 
13402ef1f0ffSBarry Smith   Not Collective
1341207556f9SJed Brown 
1342207556f9SJed Brown   Input Parameters:
134311a5261eSBarry Smith + A     - `MATNEST` matrix
134411a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1345207556f9SJed Brown 
1346207556f9SJed Brown   Level: developer
1347207556f9SJed Brown 
1348fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1349207556f9SJed Brown @*/
1350d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1351d71ae5a4SJacob Faibussowitsch {
1352207556f9SJed Brown   PetscFunctionBegin;
1353cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1355207556f9SJed Brown }
1356207556f9SJed Brown 
135766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1358d71ae5a4SJacob Faibussowitsch {
1359c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1360c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
136188ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
136288ffe2e8SJose E. Roman   VecType   vtype, type;
1363d8588912SDave May 
1364d8588912SDave May   PetscFunctionBegin;
13659566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
136606a1af2fSStefano Zampini 
1367c8883902SJed Brown   s->nr = nr;
1368c8883902SJed Brown   s->nc = nc;
1369d8588912SDave May 
1370c8883902SJed Brown   /* Create space for submatrices */
13719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
1372*8068ee9dSPierre Jolivet   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1373c8883902SJed Brown   for (i = 0; i < nr; i++) {
1374*8068ee9dSPierre Jolivet     s->m[i] = s->m[0] + i * nc;
1375c8883902SJed Brown     for (j = 0; j < nc; j++) {
1376c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
137748a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1378d8588912SDave May     }
1379d8588912SDave May   }
13809566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13819566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
138288ffe2e8SJose E. Roman   if (isstd) {
138388ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
138488ffe2e8SJose E. Roman     vtype = NULL;
138588ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
138688ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
138788ffe2e8SJose E. Roman         if (a[i * nc + j]) {
138888ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13899566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
139088ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
139188ffe2e8SJose E. Roman           } else if (sametype) {
13929566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13939566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
139488ffe2e8SJose E. Roman           }
139588ffe2e8SJose E. Roman         }
139688ffe2e8SJose E. Roman       }
139788ffe2e8SJose E. Roman     }
139888ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13999566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
140088ffe2e8SJose E. Roman     }
140188ffe2e8SJose E. Roman   }
1402d8588912SDave May 
14039566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1404d8588912SDave May 
14059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
14069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1407c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1408c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1409d8588912SDave May 
14109566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
141106a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
141206a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
141348a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
141406a1af2fSStefano Zampini     }
141506a1af2fSStefano Zampini   }
141606a1af2fSStefano Zampini 
14179566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1418d8588912SDave May 
14199566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
14209566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
14219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
14229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1423c8883902SJed Brown 
14249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
14259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1426c8883902SJed Brown 
142706a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
142806a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14299566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
143006a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
143106a1af2fSStefano Zampini   if (cong) {
143248a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
143306a1af2fSStefano Zampini   }
143406a1af2fSStefano Zampini   if (!cong) {
1435381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
143606a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
143706a1af2fSStefano Zampini     A->ops->shift           = NULL;
143806a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
143906a1af2fSStefano Zampini   }
144006a1af2fSStefano Zampini 
14419566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14429566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
144306a1af2fSStefano Zampini   A->nonzerostate++;
14443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1445d8588912SDave May }
1446d8588912SDave May 
1447c8883902SJed Brown /*@
144811a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1449c8883902SJed Brown 
1450c3339decSBarry Smith   Collective
1451c8883902SJed Brown 
1452d8d19677SJose E. Roman   Input Parameters:
145311a5261eSBarry Smith + A      - `MATNEST` matrix
1454c8883902SJed Brown . nr     - number of nested row blocks
14552ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1456c8883902SJed Brown . nc     - number of nested column blocks
14572ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1458e9d3347aSJose E. Roman - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
14592ef1f0ffSBarry Smith 
14602ef1f0ffSBarry Smith   Level: advanced
1461c8883902SJed Brown 
1462e9d3347aSJose E. Roman   Notes:
146311a5261eSBarry Smith   This always resets any submatrix information previously set
146406a1af2fSStefano Zampini 
1465e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array containing the matrices. See
1466e9d3347aSJose E. Roman   `MatCreateNest()` for an example.
1467e9d3347aSJose E. Roman 
14681cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1469c8883902SJed Brown @*/
1470d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1471d71ae5a4SJacob Faibussowitsch {
147206a1af2fSStefano Zampini   PetscInt i;
1473c8883902SJed Brown 
1474c8883902SJed Brown   PetscFunctionBegin;
1475c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
147608401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1477c8883902SJed Brown   if (nr && is_row) {
14784f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
1479c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1480c8883902SJed Brown   }
148108401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14821664e352SJed Brown   if (nc && is_col) {
14834f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
14849b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1485c8883902SJed Brown   }
14864f572ea9SToby Isaac   if (nr * nc > 0) PetscAssertPointer(a, 6);
1487cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1489c8883902SJed Brown }
1490d8588912SDave May 
1491d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1492d71ae5a4SJacob Faibussowitsch {
149377019fcaSJed Brown   PetscBool flg;
149477019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
149577019fcaSJed Brown 
149677019fcaSJed Brown   PetscFunctionBegin;
1497aea6d515SStefano Zampini   *ltog = NULL;
149877019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
149977019fcaSJed Brown     if (islocal[i]) {
15009566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150177019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
150277019fcaSJed Brown     } else {
15039566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
150477019fcaSJed Brown     }
150577019fcaSJed Brown     m += mi;
150677019fcaSJed Brown   }
15073ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1508aea6d515SStefano Zampini 
15099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1510165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
15110298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1512e108cb99SStefano Zampini     Mat                    sub  = NULL;
1513f6d38dbbSStefano Zampini     PetscSF                sf;
1514f6d38dbbSStefano Zampini     PetscLayout            map;
1515aea6d515SStefano Zampini     const PetscInt        *ix2;
151677019fcaSJed Brown 
1517165cd838SBarry Smith     if (!colflg) {
15189566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
151977019fcaSJed Brown     } else {
15209566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
152177019fcaSJed Brown     }
1522191fd14bSBarry Smith     if (sub) {
1523191fd14bSBarry Smith       if (!colflg) {
15249566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1525191fd14bSBarry Smith       } else {
15269566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1527191fd14bSBarry Smith       }
1528191fd14bSBarry Smith     }
152977019fcaSJed Brown     /*
153077019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
153177019fcaSJed Brown        In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
153277019fcaSJed Brown     */
15339566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1534aea6d515SStefano Zampini     if (islocal[i]) {
1535aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1536aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1537aea6d515SStefano Zampini 
15389566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
153928b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1540aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1542aea6d515SStefano Zampini 
1543aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15449566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1545aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1546aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1547aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1548aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1549aea6d515SStefano Zampini         nleaves++;
1550aea6d515SStefano Zampini       }
15519566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15529566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15539566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15549566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15559566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15569566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15579566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15589566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15599566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15609566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15619566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1562aea6d515SStefano Zampini     } else {
15639566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1564aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1565aea6d515SStefano Zampini     }
15669566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
156777019fcaSJed Brown     m += mi;
156877019fcaSJed Brown   }
15699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
157177019fcaSJed Brown }
157277019fcaSJed Brown 
1573d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1574d8588912SDave May /*
1575d8588912SDave May   nprocessors = NP
1576d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1577d8588912SDave May        proc 0: => (g_0,h_0,)
1578d8588912SDave May        proc 1: => (g_1,h_1,)
1579d8588912SDave May        ...
1580d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1581d8588912SDave May 
1582d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1583d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1584d8588912SDave May 
1585d8588912SDave May             proc 0:
1586d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1587d8588912SDave May             proc 1:
1588d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1589d8588912SDave May 
1590d8588912SDave May             proc NP-1:
1591d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1592d8588912SDave May */
1593d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1594d71ae5a4SJacob Faibussowitsch {
1595e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15968188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15970298fd71SBarry Smith   Mat       sub = NULL;
1598d8588912SDave May 
1599d8588912SDave May   PetscFunctionBegin;
16009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
16019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1602d8588912SDave May   if (is_row) { /* valid IS is passed in */
1603a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1604e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16059566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
160626fbe8dcSKarl Rupp 
1607e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1608d8588912SDave May     }
16092ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
16108188e55aSJed Brown     nsum = 0;
16118188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
16129566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
161328b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
16149566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
161508401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16168188e55aSJed Brown       nsum += n;
16178188e55aSJed Brown     }
16189566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
161930bc264bSJed Brown     offset -= nsum;
1620e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16219566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16229566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
16239566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16249566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
16259566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
16262ae74bdbSJed Brown       offset += n;
1627d8588912SDave May     }
1628d8588912SDave May   }
1629d8588912SDave May 
1630d8588912SDave May   if (is_col) { /* valid IS is passed in */
1631a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1632e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16339566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
163426fbe8dcSKarl Rupp 
1635e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1636d8588912SDave May     }
16372ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16382ae74bdbSJed Brown     offset = A->cmap->rstart;
16398188e55aSJed Brown     nsum   = 0;
16408188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16419566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
164228b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16439566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
164408401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16458188e55aSJed Brown       nsum += n;
16468188e55aSJed Brown     }
16479566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
164830bc264bSJed Brown     offset -= nsum;
1649e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16509566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16519566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16529566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16539566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16549566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16552ae74bdbSJed Brown       offset += n;
1656d8588912SDave May     }
1657d8588912SDave May   }
1658e2d7f03fSJed Brown 
1659e2d7f03fSJed Brown   /* Set up the local ISs */
16609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1662e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1663e2d7f03fSJed Brown     IS                     isloc;
16640298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1665e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16669566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16679566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1668207556f9SJed Brown     if (rmap) {
16699566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16709566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16719566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16729566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1673207556f9SJed Brown     } else {
1674207556f9SJed Brown       nlocal = 0;
16750298fd71SBarry Smith       isloc  = NULL;
1676207556f9SJed Brown     }
1677e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1678e2d7f03fSJed Brown     offset += nlocal;
1679e2d7f03fSJed Brown   }
16808188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1681e2d7f03fSJed Brown     IS                     isloc;
16820298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1683e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16849566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16859566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1686207556f9SJed Brown     if (cmap) {
16879566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16889566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16899566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16909566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1691207556f9SJed Brown     } else {
1692207556f9SJed Brown       nlocal = 0;
16930298fd71SBarry Smith       isloc  = NULL;
1694207556f9SJed Brown     }
1695e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1696e2d7f03fSJed Brown     offset += nlocal;
1697e2d7f03fSJed Brown   }
16980189643fSJed Brown 
169977019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
170077019fcaSJed Brown   {
170145b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
17029566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
17039566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
17049566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
17059566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
17069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
170777019fcaSJed Brown   }
170877019fcaSJed Brown 
170976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17100189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
17110189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
17120189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
17130189643fSJed Brown         Mat      B = vs->m[i][j];
17140189643fSJed Brown         if (!B) continue;
17159566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
17169566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
17179566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
17189566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
17199566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
17209566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1721aed4548fSBarry Smith         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);
1722aed4548fSBarry Smith         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);
17230189643fSJed Brown       }
17240189643fSJed Brown     }
172576bd3646SJed Brown   }
1726a061e289SJed Brown 
1727a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1728a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1729a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
17303ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1731a061e289SJed Brown     }
1732a061e289SJed Brown   }
1733a061e289SJed Brown   A->assembled = PETSC_TRUE;
17343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1735d8588912SDave May }
1736d8588912SDave May 
173745c38901SJed Brown /*@C
173811a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1739659c6bb0SJed Brown 
174011a5261eSBarry Smith   Collective
1741659c6bb0SJed Brown 
1742d8d19677SJose E. Roman   Input Parameters:
174311a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1744659c6bb0SJed Brown . nr     - number of nested row blocks
17452ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1746659c6bb0SJed Brown . nc     - number of nested column blocks
17472ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1748e9d3347aSJose E. Roman - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1749659c6bb0SJed Brown 
1750659c6bb0SJed Brown   Output Parameter:
1751659c6bb0SJed Brown . B - new matrix
1752659c6bb0SJed Brown 
1753e9d3347aSJose E. Roman   Note:
1754e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array holding references to the matrices.
1755e9d3347aSJose E. Roman   For instance, to represent the matrix
1756e9d3347aSJose E. Roman   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1757e9d3347aSJose E. Roman   one should use `Mat a[4]={A11,A12,A21,A22}`.
1758e9d3347aSJose E. Roman 
1759659c6bb0SJed Brown   Level: advanced
1760659c6bb0SJed Brown 
17611cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1762db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1763db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1764659c6bb0SJed Brown @*/
1765d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1766d71ae5a4SJacob Faibussowitsch {
1767d8588912SDave May   Mat A;
1768d8588912SDave May 
1769d8588912SDave May   PetscFunctionBegin;
1770f4259b30SLisandro Dalcin   *B = NULL;
17719566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17729566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
177391a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17749566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1775d8588912SDave May   *B = A;
17763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1777d8588912SDave May }
1778659c6bb0SJed Brown 
177966976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1780d71ae5a4SJacob Faibussowitsch {
1781b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
178223875855Sstefano_zampini   Mat          *trans;
1783b68353e5Sstefano_zampini   PetscScalar **avv;
1784b68353e5Sstefano_zampini   PetscScalar  *vv;
1785b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1786b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1787b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1788b68353e5Sstefano_zampini   PetscBool     done;
1789b68353e5Sstefano_zampini 
1790b68353e5Sstefano_zampini   PetscFunctionBegin;
17919566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1792b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1793b68353e5Sstefano_zampini     PetscInt rnr;
1794b68353e5Sstefano_zampini 
17959566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
179628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
179708401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
17989566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1799b68353e5Sstefano_zampini   }
1800b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1801b68353e5Sstefano_zampini   nnz = 0;
18029566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1803b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1804b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1805b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1806b68353e5Sstefano_zampini       if (B) {
1807b68353e5Sstefano_zampini         PetscScalar *naa;
1808b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
180923875855Sstefano_zampini         PetscBool    istrans;
1810b68353e5Sstefano_zampini 
1811013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
181223875855Sstefano_zampini         if (istrans) {
181323875855Sstefano_zampini           Mat Bt;
181423875855Sstefano_zampini 
18159566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
18169566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
181723875855Sstefano_zampini           B = trans[i * nest->nc + j];
1818013e2dc7SBarry Smith         } else {
1819013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1820013e2dc7SBarry Smith           if (istrans) {
1821013e2dc7SBarry Smith             Mat Bt;
1822013e2dc7SBarry Smith 
1823013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1824013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1825013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1826013e2dc7SBarry Smith           }
182723875855Sstefano_zampini         }
18289566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
182928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
18309566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1831b68353e5Sstefano_zampini         nnz += nii[nnr];
1832b68353e5Sstefano_zampini 
1833b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1834b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1835b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1836b68353e5Sstefano_zampini       }
1837b68353e5Sstefano_zampini     }
1838b68353e5Sstefano_zampini   }
1839b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1843b68353e5Sstefano_zampini   } else {
184408401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1845b68353e5Sstefano_zampini   }
1846b68353e5Sstefano_zampini 
1847b68353e5Sstefano_zampini   /* new row pointer */
18489566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1849b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1850b68353e5Sstefano_zampini     PetscInt ncr, rst;
1851b68353e5Sstefano_zampini 
18529566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18539566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1854b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1855b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1856b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1857b68353e5Sstefano_zampini         PetscInt  ir;
1858b68353e5Sstefano_zampini 
1859b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1860b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1861b68353e5Sstefano_zampini           nii++;
1862b68353e5Sstefano_zampini         }
1863b68353e5Sstefano_zampini       }
1864b68353e5Sstefano_zampini     }
1865b68353e5Sstefano_zampini   }
1866b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1867b68353e5Sstefano_zampini 
1868b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18699566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1870b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1871b68353e5Sstefano_zampini     PetscInt ncr, rst;
1872b68353e5Sstefano_zampini 
18739566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1875b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1876b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1877b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1878b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1879b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1880b68353e5Sstefano_zampini         PetscInt     ir, cst;
1881b68353e5Sstefano_zampini 
18829566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1883b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1884b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1885b68353e5Sstefano_zampini 
1886b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1887b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1888b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1889b68353e5Sstefano_zampini             njj++;
1890b68353e5Sstefano_zampini             nvv++;
1891b68353e5Sstefano_zampini           }
1892b68353e5Sstefano_zampini           ci[ir] += rsize;
1893b68353e5Sstefano_zampini           nii++;
1894b68353e5Sstefano_zampini         }
1895b68353e5Sstefano_zampini       }
1896b68353e5Sstefano_zampini     }
1897b68353e5Sstefano_zampini   }
18989566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1899b68353e5Sstefano_zampini 
1900b68353e5Sstefano_zampini   /* restore info */
1901b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1902b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1903b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1904b68353e5Sstefano_zampini       if (B) {
1905b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
190623875855Sstefano_zampini 
190723875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
19089566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
190928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
19109566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
19119566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1912b68353e5Sstefano_zampini       }
1913b68353e5Sstefano_zampini     }
1914b68353e5Sstefano_zampini   }
19159566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1916b68353e5Sstefano_zampini 
1917b68353e5Sstefano_zampini   /* finalize newmat */
1918b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
19199566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1920b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1921b68353e5Sstefano_zampini     Mat B;
1922b68353e5Sstefano_zampini 
19239566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
19249566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1925b68353e5Sstefano_zampini   }
19269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
19279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1928b68353e5Sstefano_zampini   {
1929b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1930b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1931b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1932b68353e5Sstefano_zampini   }
19333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1934b68353e5Sstefano_zampini }
1935b68353e5Sstefano_zampini 
1936d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1937d71ae5a4SJacob Faibussowitsch {
1938be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1939be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1940be705e3aSPierre Jolivet   PetscBool flg;
1941be705e3aSPierre Jolivet 
1942be705e3aSPierre Jolivet   PetscFunctionBegin;
1943be705e3aSPierre Jolivet   /* Fill by row */
1944be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1945be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1946be705e3aSPierre Jolivet     IS              bNis;
1947be705e3aSPierre Jolivet     PetscInt        bN;
1948be705e3aSPierre Jolivet     const PetscInt *bNindices;
19499566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19509566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1952be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1953fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1954be705e3aSPierre Jolivet       PetscInt        bm, br;
1955be705e3aSPierre Jolivet       const PetscInt *bmindices;
1956be705e3aSPierre Jolivet       if (!B) continue;
1957013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1958be705e3aSPierre Jolivet       if (flg) {
1959cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1960cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19619566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1962be705e3aSPierre Jolivet         B = D;
1963be705e3aSPierre Jolivet       }
19649566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1965be705e3aSPierre Jolivet       if (flg) {
1966fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1967fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1968be705e3aSPierre Jolivet         B = D;
1969be705e3aSPierre Jolivet       }
19709566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19719566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19729566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1973be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1974be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1975be705e3aSPierre Jolivet         const PetscInt    *brcols;
1976be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1977be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19789566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19799566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1980be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1981be705e3aSPierre Jolivet         /*
1982be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1983be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1984be705e3aSPierre Jolivet          */
1985be705e3aSPierre Jolivet         if (a != 1.0) {
19869566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1987be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19889566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19899566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1990be705e3aSPierre Jolivet         } else {
19919566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1992be705e3aSPierre Jolivet         }
19939566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19949566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1995be705e3aSPierre Jolivet       }
1996fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19979566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1998be705e3aSPierre Jolivet     }
19999566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
20009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
2001be705e3aSPierre Jolivet   }
20029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
20039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
20043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2005be705e3aSPierre Jolivet }
2006be705e3aSPierre Jolivet 
200766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2008d71ae5a4SJacob Faibussowitsch {
2009629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
2010e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2011b68353e5Sstefano_zampini   PetscMPIInt size;
2012629c3df2SDmitry Karpeev   Mat         C;
2013629c3df2SDmitry Karpeev 
2014629c3df2SDmitry Karpeev   PetscFunctionBegin;
20159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2016b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2017b68353e5Sstefano_zampini     PetscInt  nf;
2018b68353e5Sstefano_zampini     PetscBool fast;
2019b68353e5Sstefano_zampini 
20209566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
202148a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2022b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
2023b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
2024b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
2025b68353e5Sstefano_zampini         if (B) {
20269566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
202723875855Sstefano_zampini           if (!fast) {
202823875855Sstefano_zampini             PetscBool istrans;
202923875855Sstefano_zampini 
2030013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
203123875855Sstefano_zampini             if (istrans) {
203223875855Sstefano_zampini               Mat Bt;
203323875855Sstefano_zampini 
20349566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
20359566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2036013e2dc7SBarry Smith             } else {
2037013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2038013e2dc7SBarry Smith               if (istrans) {
2039013e2dc7SBarry Smith                 Mat Bt;
2040013e2dc7SBarry Smith 
2041013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2042013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2043013e2dc7SBarry Smith               }
204423875855Sstefano_zampini             }
2045b68353e5Sstefano_zampini           }
2046b68353e5Sstefano_zampini         }
2047b68353e5Sstefano_zampini       }
2048b68353e5Sstefano_zampini     }
2049b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20509566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2051b68353e5Sstefano_zampini       if (fast) {
2052b68353e5Sstefano_zampini         PetscInt f, s;
2053b68353e5Sstefano_zampini 
20549566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20559371c9d4SSatish Balay         if (f != nf || s != 1) {
20569371c9d4SSatish Balay           fast = PETSC_FALSE;
20579371c9d4SSatish Balay         } else {
20589566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2059b68353e5Sstefano_zampini           nf += f;
2060b68353e5Sstefano_zampini         }
2061b68353e5Sstefano_zampini       }
2062b68353e5Sstefano_zampini     }
2063b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20649566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2065b68353e5Sstefano_zampini       if (fast) {
2066b68353e5Sstefano_zampini         PetscInt f, s;
2067b68353e5Sstefano_zampini 
20689566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20699371c9d4SSatish Balay         if (f != nf || s != 1) {
20709371c9d4SSatish Balay           fast = PETSC_FALSE;
20719371c9d4SSatish Balay         } else {
20729566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2073b68353e5Sstefano_zampini           nf += f;
2074b68353e5Sstefano_zampini         }
2075b68353e5Sstefano_zampini       }
2076b68353e5Sstefano_zampini     }
2077b68353e5Sstefano_zampini     if (fast) {
20789566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20793ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2080b68353e5Sstefano_zampini     }
2081b68353e5Sstefano_zampini   }
20829566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20839566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20849566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2085d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2086d1487292SPierre Jolivet   else {
20879566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20889566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20899566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2090629c3df2SDmitry Karpeev   }
20919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2092e30678d3SPierre Jolivet   if (m) {
2093629c3df2SDmitry Karpeev     onnz = dnnz + m;
2094629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2095629c3df2SDmitry Karpeev       dnnz[k] = 0;
2096629c3df2SDmitry Karpeev       onnz[k] = 0;
2097629c3df2SDmitry Karpeev     }
2098e30678d3SPierre Jolivet   }
2099629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2100629c3df2SDmitry Karpeev     IS              bNis;
2101629c3df2SDmitry Karpeev     PetscInt        bN;
2102629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2103fd8a7442SPierre Jolivet     PetscBool       flg;
2104629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
21059566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
21069566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
21079566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2108629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2109629c3df2SDmitry Karpeev       PetscSF         bmsf;
2110649b366bSFande Kong       PetscSFNode    *iremote;
2111fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2112649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2113629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2114629c3df2SDmitry Karpeev       if (!B) continue;
21159566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
21169566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
21179566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
21189566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
21199566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
21209566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2121649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2122649b366bSFande Kong         sub_dnnz[k] = 0;
2123649b366bSFande Kong         sub_onnz[k] = 0;
2124649b366bSFande Kong       }
2125dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2126fd8a7442SPierre Jolivet       if (flg) {
2127fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2128fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2129fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2130fd8a7442SPierre Jolivet         B = D;
2131fd8a7442SPierre Jolivet       }
2132fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2133fd8a7442SPierre Jolivet       if (flg) {
2134fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2135fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2136fd8a7442SPierre Jolivet         B = D;
2137fd8a7442SPierre Jolivet       }
2138629c3df2SDmitry Karpeev       /*
2139629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2140629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2141629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2142629c3df2SDmitry Karpeev        */
21439566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2144629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2145131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2146629c3df2SDmitry Karpeev         const PetscInt *brcols;
2147a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2148131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21499566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2150649b366bSFande Kong         /* how many roots  */
21519371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21529371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2153649b366bSFande Kong         /* get nonzero pattern */
21549566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2155629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2156629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2157649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2158649b366bSFande Kong             sub_dnnz[br]++;
2159649b366bSFande Kong           } else {
2160649b366bSFande Kong             sub_onnz[br]++;
2161649b366bSFande Kong           }
2162629c3df2SDmitry Karpeev         }
21639566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2164629c3df2SDmitry Karpeev       }
2165fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21669566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2167629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21689566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21699566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21709566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21719566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21729566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21739566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21749566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21759566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2176629c3df2SDmitry Karpeev     }
21779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
217965a4a0a3Sstefano_zampini   }
218065a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
218165a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
218265a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
218365a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2184629c3df2SDmitry Karpeev   }
21859566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21869566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21879566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21889566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2189d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21909566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2191d1487292SPierre Jolivet   } else *newmat = C;
21923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2193be705e3aSPierre Jolivet }
2194629c3df2SDmitry Karpeev 
219566976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2196d71ae5a4SJacob Faibussowitsch {
2197629c3df2SDmitry Karpeev   Mat      B;
2198be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2199be705e3aSPierre Jolivet 
2200be705e3aSPierre Jolivet   PetscFunctionBegin;
22019566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
22029566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2203be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2204be705e3aSPierre Jolivet     B = *newmat;
22059566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2206be705e3aSPierre Jolivet   } else {
22079566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2208629c3df2SDmitry Karpeev   }
22099566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2210be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
22119566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2212be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
22133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2214629c3df2SDmitry Karpeev }
2215629c3df2SDmitry Karpeev 
221666976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2217d71ae5a4SJacob Faibussowitsch {
22188b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
22193c6db4c4SPierre Jolivet   MatOperation opAdd;
22208b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
22218b7d3b4bSBarry Smith   PetscBool    flg;
222252c5f739Sprj-   PetscFunctionBegin;
22238b7d3b4bSBarry Smith 
222452c5f739Sprj-   *has = PETSC_FALSE;
22253c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
22263c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
22278b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
22288b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
22298b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
22309566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
22313ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
22328b7d3b4bSBarry Smith       }
22338b7d3b4bSBarry Smith     }
22348b7d3b4bSBarry Smith   }
22353c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
22363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22378b7d3b4bSBarry Smith }
22388b7d3b4bSBarry Smith 
2239659c6bb0SJed Brown /*MC
22402ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2241659c6bb0SJed Brown 
2242659c6bb0SJed Brown   Level: intermediate
2243659c6bb0SJed Brown 
2244659c6bb0SJed Brown   Notes:
224511a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2246659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
224711a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2248659c6bb0SJed Brown 
22498b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22508b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22518b7d3b4bSBarry Smith   than the nest matrix.
22528b7d3b4bSBarry Smith 
22531cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2254db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2255db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2256659c6bb0SJed Brown M*/
2257d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2258d71ae5a4SJacob Faibussowitsch {
2259c8883902SJed Brown   Mat_Nest *s;
2260c8883902SJed Brown 
2261c8883902SJed Brown   PetscFunctionBegin;
22624dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2263c8883902SJed Brown   A->data = (void *)s;
2264e7c19651SJed Brown 
2265e7c19651SJed Brown   s->nr            = -1;
2266e7c19651SJed Brown   s->nc            = -1;
22670298fd71SBarry Smith   s->m             = NULL;
2268e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2269c8883902SJed Brown 
22709566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
227126fbe8dcSKarl Rupp 
2272c8883902SJed Brown   A->ops->mult                      = MatMult_Nest;
22739194d70fSJed Brown   A->ops->multadd                   = MatMultAdd_Nest;
2274c8883902SJed Brown   A->ops->multtranspose             = MatMultTranspose_Nest;
22759194d70fSJed Brown   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2276f8170845SAlex Fikl   A->ops->transpose                 = MatTranspose_Nest;
22770998551bSBlanca Mellado Pinto   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
22780998551bSBlanca Mellado Pinto   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2279c8883902SJed Brown   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2280c8883902SJed Brown   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2281c8883902SJed Brown   A->ops->zeroentries               = MatZeroEntries_Nest;
2282c222c20dSDavid Ham   A->ops->copy                      = MatCopy_Nest;
22836e76ffeaSPierre Jolivet   A->ops->axpy                      = MatAXPY_Nest;
2284c8883902SJed Brown   A->ops->duplicate                 = MatDuplicate_Nest;
22857dae84e0SHong Zhang   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2286c8883902SJed Brown   A->ops->destroy                   = MatDestroy_Nest;
2287c8883902SJed Brown   A->ops->view                      = MatView_Nest;
2288f4259b30SLisandro Dalcin   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2289c8883902SJed Brown   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2290c8883902SJed Brown   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2291429bac76SJed Brown   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2292429bac76SJed Brown   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2293a061e289SJed Brown   A->ops->scale                     = MatScale_Nest;
2294a061e289SJed Brown   A->ops->shift                     = MatShift_Nest;
229513135bc6SAlex Fikl   A->ops->diagonalset               = MatDiagonalSet_Nest;
2296f8170845SAlex Fikl   A->ops->setrandom                 = MatSetRandom_Nest;
22978b7d3b4bSBarry Smith   A->ops->hasoperation              = MatHasOperation_Nest;
2298381b8e50SStefano Zampini   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2299c8883902SJed Brown 
2300f4259b30SLisandro Dalcin   A->spptr     = NULL;
2301c8883902SJed Brown   A->assembled = PETSC_FALSE;
2302c8883902SJed Brown 
2303c8883902SJed Brown   /* expose Nest api's */
23049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
23059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
23069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
23079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
23089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
23099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
23109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
23119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
23129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
23139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
23149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
23159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
23169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
23179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
23189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
23199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
23209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense));
2321c8883902SJed Brown 
23229566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
23233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2324c8883902SJed Brown }
2325