xref: /petsc/src/mat/impls/nest/matnest.c (revision 80670ca526307b63e5a1d9a5049dfd9d2168c535)
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- 
251a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
252d71ae5a4SJacob Faibussowitsch {
2534222ddf1SHong Zhang   Mat_Product *product = C->product;
25452c5f739Sprj- 
25552c5f739Sprj-   PetscFunctionBegin;
256c57d7d18SPierre Jolivet   if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25852c5f739Sprj- }
25952c5f739Sprj- 
2600998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm)
261d71ae5a4SJacob Faibussowitsch {
262d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
263207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
264207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
265d8588912SDave May 
266d8588912SDave May   PetscFunctionBegin;
2679566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2689566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
269207556f9SJed Brown   for (j = 0; j < nc; j++) {
2709566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
271609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2726c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2730998551bSBlanca 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] */
2740998551bSBlanca 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] */
275d8588912SDave May     }
276d8588912SDave May   }
2779566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2789566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280d8588912SDave May }
281d8588912SDave May 
2820998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
2830998551bSBlanca Mellado Pinto {
2840998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2850998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE));
2860998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
2870998551bSBlanca Mellado Pinto }
2880998551bSBlanca Mellado Pinto 
2890998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y)
2900998551bSBlanca Mellado Pinto {
2910998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2920998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE));
2930998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
2940998551bSBlanca Mellado Pinto }
2950998551bSBlanca Mellado Pinto 
2960998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm)
297d71ae5a4SJacob Faibussowitsch {
2989194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2999194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
3009194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
3019194d70fSJed Brown 
3029194d70fSJed Brown   PetscFunctionBegin;
3039566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
3049566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
3059194d70fSJed Brown   for (j = 0; j < nc; j++) {
3069194d70fSJed Brown     if (y != z) {
3079194d70fSJed Brown       Vec by;
3089566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3099566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3109566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3119194d70fSJed Brown     }
3129194d70fSJed Brown     for (i = 0; i < nr; i++) {
3136c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3140998551bSBlanca 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] */
3150998551bSBlanca 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] */
3169194d70fSJed Brown     }
3179194d70fSJed Brown   }
3189566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3199566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3219194d70fSJed Brown }
3229194d70fSJed Brown 
3230998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
3240998551bSBlanca Mellado Pinto {
3250998551bSBlanca Mellado Pinto   PetscFunctionBegin;
3260998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE));
3270998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3280998551bSBlanca Mellado Pinto }
3290998551bSBlanca Mellado Pinto 
3300998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_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_TRUE));
3340998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3350998551bSBlanca Mellado Pinto }
3360998551bSBlanca Mellado Pinto 
337d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
338d71ae5a4SJacob Faibussowitsch {
339f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
340f8170845SAlex Fikl   Mat       C;
341f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
342f8170845SAlex Fikl 
343f8170845SAlex Fikl   PetscFunctionBegin;
3447fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
345aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
346f8170845SAlex Fikl 
347cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
348f8170845SAlex Fikl     Mat *subs;
349f8170845SAlex Fikl     IS  *is_row, *is_col;
350f8170845SAlex Fikl 
3519566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3539566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
354cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
355ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
356ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
357ddeb9bd8SAlex Fikl       }
358ddeb9bd8SAlex Fikl     }
359ddeb9bd8SAlex Fikl 
3609566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3619566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3629566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
363f8170845SAlex Fikl   } else {
364f8170845SAlex Fikl     C = *B;
365f8170845SAlex Fikl   }
366f8170845SAlex Fikl 
367f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
368f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
369f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
370f8170845SAlex Fikl       if (bA->m[i][j]) {
371f4f49eeaSPierre Jolivet         PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i]));
372f8170845SAlex Fikl       } else {
373f8170845SAlex Fikl         bC->m[j][i] = NULL;
374f8170845SAlex Fikl       }
375f8170845SAlex Fikl     }
376f8170845SAlex Fikl   }
377f8170845SAlex Fikl 
378cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
379f8170845SAlex Fikl     *B = C;
380f8170845SAlex Fikl   } else {
3819566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
382f8170845SAlex Fikl   }
3833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
384f8170845SAlex Fikl }
385f8170845SAlex Fikl 
386d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
387d71ae5a4SJacob Faibussowitsch {
388e2d7f03fSJed Brown   IS      *lst = *list;
389e2d7f03fSJed Brown   PetscInt i;
390e2d7f03fSJed Brown 
391e2d7f03fSJed Brown   PetscFunctionBegin;
3923ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
3939371c9d4SSatish Balay   for (i = 0; i < n; i++)
3949371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3960298fd71SBarry Smith   *list = NULL;
3973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
398e2d7f03fSJed Brown }
399e2d7f03fSJed Brown 
400d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
401d71ae5a4SJacob Faibussowitsch {
402d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
403d8588912SDave May   PetscInt  i, j;
404d8588912SDave May 
405d8588912SDave May   PetscFunctionBegin;
406d8588912SDave May   /* release the matrices and the place holders */
4079566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
4089566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
4099566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
4109566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
411d8588912SDave May 
4129566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
415d8588912SDave May 
4169566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
417207556f9SJed Brown 
418d8588912SDave May   /* release the matrices and the place holders */
419d8588912SDave May   if (vs->m) {
420d8588912SDave May     for (i = 0; i < vs->nr; i++) {
42148a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
422d8588912SDave May     }
4238068ee9dSPierre Jolivet     PetscCall(PetscFree(vs->m[0]));
4249566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
425d8588912SDave May   }
42606a1af2fSStefano Zampini 
42706a1af2fSStefano Zampini   /* restore defaults */
42806a1af2fSStefano Zampini   vs->nr            = 0;
42906a1af2fSStefano Zampini   vs->nc            = 0;
43006a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43206a1af2fSStefano Zampini }
43306a1af2fSStefano Zampini 
434d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
435d71ae5a4SJacob Faibussowitsch {
436362febeeSStefano Zampini   PetscFunctionBegin;
4379566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4389566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
456d8588912SDave May }
457d8588912SDave May 
458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
459d71ae5a4SJacob Faibussowitsch {
460381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
461381b8e50SStefano Zampini   PetscInt  i;
462381b8e50SStefano Zampini 
463381b8e50SStefano Zampini   PetscFunctionBegin;
464381b8e50SStefano Zampini   if (dd) *dd = 0;
465381b8e50SStefano Zampini   if (!vs->nr) {
466381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4673ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
468381b8e50SStefano Zampini   }
469381b8e50SStefano Zampini   *missing = PETSC_FALSE;
470381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
471381b8e50SStefano Zampini     *missing = PETSC_TRUE;
472381b8e50SStefano Zampini     if (vs->m[i][i]) {
4739566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
47408401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
475381b8e50SStefano Zampini     }
476381b8e50SStefano Zampini   }
4773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
478381b8e50SStefano Zampini }
479381b8e50SStefano Zampini 
480d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
481d71ae5a4SJacob Faibussowitsch {
482d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
483d8588912SDave May   PetscInt  i, j;
48406a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
485d8588912SDave May 
486d8588912SDave May   PetscFunctionBegin;
487d8588912SDave May   for (i = 0; i < vs->nr; i++) {
488d8588912SDave May     for (j = 0; j < vs->nc; j++) {
48906a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
490e7c19651SJed Brown       if (vs->m[i][j]) {
4919566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
492e7c19651SJed Brown         if (!vs->splitassembly) {
493e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
494e7c19651SJed 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
495e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
496e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
497e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
498e7c19651SJed Brown            */
4999566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
5009566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
501e7c19651SJed Brown         }
502e7c19651SJed Brown       }
50306a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
50406a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
505d8588912SDave May     }
506d8588912SDave May   }
50706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
5083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
509d8588912SDave May }
510d8588912SDave May 
511d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
512d71ae5a4SJacob Faibussowitsch {
513d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
514d8588912SDave May   PetscInt  i, j;
515d8588912SDave May 
516d8588912SDave May   PetscFunctionBegin;
517d8588912SDave May   for (i = 0; i < vs->nr; i++) {
518d8588912SDave May     for (j = 0; j < vs->nc; j++) {
519e7c19651SJed Brown       if (vs->m[i][j]) {
52048a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
521e7c19651SJed Brown       }
522d8588912SDave May     }
523d8588912SDave May   }
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
525d8588912SDave May }
526d8588912SDave May 
527d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
528d71ae5a4SJacob Faibussowitsch {
529f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
530f349c1fdSJed Brown   PetscInt  j;
531f349c1fdSJed Brown   Mat       sub;
532d8588912SDave May 
533d8588912SDave May   PetscFunctionBegin;
5340298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
535f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5369566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
537f349c1fdSJed Brown   *B = sub;
5383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
539d8588912SDave May }
540d8588912SDave May 
541d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
542d71ae5a4SJacob Faibussowitsch {
543f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
544f349c1fdSJed Brown   PetscInt  i;
545f349c1fdSJed Brown   Mat       sub;
546f349c1fdSJed Brown 
547f349c1fdSJed Brown   PetscFunctionBegin;
5480298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
549f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5509566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
551f349c1fdSJed Brown   *B = sub;
5523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
553d8588912SDave May }
554d8588912SDave May 
555d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
556d71ae5a4SJacob Faibussowitsch {
55718d228c0SPierre Jolivet   PetscInt  i, j, size, m;
558f349c1fdSJed Brown   PetscBool flg;
55918d228c0SPierre Jolivet   IS        out, concatenate[2];
560f349c1fdSJed Brown 
561f349c1fdSJed Brown   PetscFunctionBegin;
5624f572ea9SToby Isaac   PetscAssertPointer(list, 3);
563f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
56418d228c0SPierre Jolivet   if (begin) {
5654f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
56618d228c0SPierre Jolivet     *begin = -1;
56718d228c0SPierre Jolivet   }
56818d228c0SPierre Jolivet   if (end) {
5694f572ea9SToby Isaac     PetscAssertPointer(end, 6);
57018d228c0SPierre Jolivet     *end = -1;
57118d228c0SPierre Jolivet   }
572f349c1fdSJed Brown   for (i = 0; i < n; i++) {
573207556f9SJed Brown     if (!list[i]) continue;
5749566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
575f349c1fdSJed Brown     if (flg) {
57618d228c0SPierre Jolivet       if (begin) *begin = i;
57718d228c0SPierre Jolivet       if (end) *end = i + 1;
5783ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
579f349c1fdSJed Brown     }
580f349c1fdSJed Brown   }
5819566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
58218d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
58318d228c0SPierre Jolivet     if (!list[i]) continue;
58418d228c0SPierre Jolivet     m = 0;
5859566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5869566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
58718d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
58818d228c0SPierre Jolivet       if (list[j]) {
58918d228c0SPierre Jolivet         concatenate[0] = out;
59018d228c0SPierre Jolivet         concatenate[1] = list[j];
5919566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5929566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5939566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
59418d228c0SPierre Jolivet       }
59518d228c0SPierre Jolivet     }
59618d228c0SPierre Jolivet     if (m == size) {
5979566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
59818d228c0SPierre Jolivet       if (flg) {
59918d228c0SPierre Jolivet         if (begin) *begin = i;
60018d228c0SPierre Jolivet         if (end) *end = j;
6019566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
6023ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
60318d228c0SPierre Jolivet       }
60418d228c0SPierre Jolivet     }
6059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
60618d228c0SPierre Jolivet   }
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
608f349c1fdSJed Brown }
609f349c1fdSJed Brown 
610d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
611d71ae5a4SJacob Faibussowitsch {
6128188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
61318d228c0SPierre Jolivet   PetscInt  lr, lc;
61418d228c0SPierre Jolivet 
61518d228c0SPierre Jolivet   PetscFunctionBegin;
6169566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
6179566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
6189566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
6199566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
6209566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6219566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6229566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6239566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6249566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6259566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62818d228c0SPierre Jolivet }
62918d228c0SPierre Jolivet 
630d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
631d71ae5a4SJacob Faibussowitsch {
63218d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
63318d228c0SPierre Jolivet   Mat       *a;
63418d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6358188e55aSJed Brown   char       keyname[256];
63618d228c0SPierre Jolivet   PetscBool *b;
63718d228c0SPierre Jolivet   PetscBool  flg;
6388188e55aSJed Brown 
6398188e55aSJed Brown   PetscFunctionBegin;
6400298fd71SBarry Smith   *B = NULL;
6419566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6429566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6433ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6448188e55aSJed Brown 
6459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
64618d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
64718d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
64818d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
64918d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
65018d228c0SPierre Jolivet     }
65118d228c0SPierre Jolivet   }
65218d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
65318d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
65418d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
65518d228c0SPierre Jolivet         flg = PETSC_FALSE;
65618d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
65718d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
65818d228c0SPierre Jolivet         }
65918d228c0SPierre Jolivet         if (flg) {
66018d228c0SPierre Jolivet           flg = PETSC_FALSE;
66118d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
66218d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
66318d228c0SPierre Jolivet           }
66418d228c0SPierre Jolivet         }
66518d228c0SPierre Jolivet         if (!flg) {
66618d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6679566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
66818d228c0SPierre Jolivet         }
66918d228c0SPierre Jolivet       }
67018d228c0SPierre Jolivet     }
67118d228c0SPierre Jolivet   }
6729566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
67318d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
67418d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
67548a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
67618d228c0SPierre Jolivet     }
67718d228c0SPierre Jolivet   }
6789566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6798188e55aSJed Brown   (*B)->assembled = A->assembled;
6809566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6819566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6838188e55aSJed Brown }
6848188e55aSJed Brown 
685d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
686d71ae5a4SJacob Faibussowitsch {
687f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
68818d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
689f349c1fdSJed Brown 
690f349c1fdSJed Brown   PetscFunctionBegin;
6919566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6929566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
69318d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
69448a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
69518d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
69618d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6979566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
69818d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
6993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
700f349c1fdSJed Brown }
701f349c1fdSJed Brown 
70206a1af2fSStefano Zampini /*
70306a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
70406a1af2fSStefano Zampini */
705d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
706d71ae5a4SJacob Faibussowitsch {
707f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
708f349c1fdSJed Brown   Mat       sub;
709f349c1fdSJed Brown 
710f349c1fdSJed Brown   PetscFunctionBegin;
7119566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
712f349c1fdSJed Brown   switch (reuse) {
713f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
7149566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
715f349c1fdSJed Brown     *B = sub;
716f349c1fdSJed Brown     break;
717d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
718d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
719d71ae5a4SJacob Faibussowitsch     break;
720d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
721d71ae5a4SJacob Faibussowitsch     break;
722d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
723d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
724f349c1fdSJed Brown   }
7253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
726f349c1fdSJed Brown }
727f349c1fdSJed Brown 
72866976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
729d71ae5a4SJacob Faibussowitsch {
730f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
731f349c1fdSJed Brown   Mat       sub;
732f349c1fdSJed Brown 
733f349c1fdSJed Brown   PetscFunctionBegin;
7349566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
735f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7369566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
737f349c1fdSJed Brown   *B = sub;
7383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
739d8588912SDave May }
740d8588912SDave May 
741d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
742d71ae5a4SJacob Faibussowitsch {
743f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
744f349c1fdSJed Brown   Mat       sub;
745d8588912SDave May 
746d8588912SDave May   PetscFunctionBegin;
7479566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
74808401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
749f349c1fdSJed Brown   if (sub) {
750aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
752d8588912SDave May   }
7533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
754d8588912SDave May }
755d8588912SDave May 
756d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
757d71ae5a4SJacob Faibussowitsch {
7587874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7597874fa86SDave May   PetscInt  i;
7607874fa86SDave May 
7617874fa86SDave May   PetscFunctionBegin;
7627874fa86SDave May   for (i = 0; i < bA->nr; i++) {
763429bac76SJed Brown     Vec bv;
7649566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7657874fa86SDave May     if (bA->m[i][i]) {
7669566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7677874fa86SDave May     } else {
7689566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7697874fa86SDave May     }
7709566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7717874fa86SDave May   }
7723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7737874fa86SDave May }
7747874fa86SDave May 
775d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
776d71ae5a4SJacob Faibussowitsch {
7777874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
778429bac76SJed Brown   Vec       bl, *br;
7797874fa86SDave May   PetscInt  i, j;
7807874fa86SDave May 
7817874fa86SDave May   PetscFunctionBegin;
7829566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7832e6472ebSElliott Sales de Andrade   if (r) {
7849566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7852e6472ebSElliott Sales de Andrade   }
7862e6472ebSElliott Sales de Andrade   bl = NULL;
7877874fa86SDave May   for (i = 0; i < bA->nr; i++) {
78848a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7897874fa86SDave May     for (j = 0; j < bA->nc; j++) {
79048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7917874fa86SDave May     }
79248a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7932e6472ebSElliott Sales de Andrade   }
7942e6472ebSElliott Sales de Andrade   if (r) {
7959566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7962e6472ebSElliott Sales de Andrade   }
7979566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7997874fa86SDave May }
8007874fa86SDave May 
801d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
802d71ae5a4SJacob Faibussowitsch {
803a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
804a061e289SJed Brown   PetscInt  i, j;
805a061e289SJed Brown 
806a061e289SJed Brown   PetscFunctionBegin;
807a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
808a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
80948a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
810a061e289SJed Brown     }
811a061e289SJed Brown   }
8123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
813a061e289SJed Brown }
814a061e289SJed Brown 
815d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
816d71ae5a4SJacob Faibussowitsch {
817a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
818a061e289SJed Brown   PetscInt  i;
81906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
820a061e289SJed Brown 
821a061e289SJed Brown   PetscFunctionBegin;
822a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
82306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82408401ef6SPierre 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);
8259566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8269566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82706a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
82806a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
829a061e289SJed Brown   }
83006a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
832a061e289SJed Brown }
833a061e289SJed Brown 
834d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
835d71ae5a4SJacob Faibussowitsch {
83613135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
83713135bc6SAlex Fikl   PetscInt  i;
83806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
83913135bc6SAlex Fikl 
84013135bc6SAlex Fikl   PetscFunctionBegin;
84113135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
84206a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
84313135bc6SAlex Fikl     Vec              bv;
8449566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
84513135bc6SAlex Fikl     if (bA->m[i][i]) {
8469566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8479566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
84813135bc6SAlex Fikl     }
8499566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
85006a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
85106a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
85213135bc6SAlex Fikl   }
85306a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85513135bc6SAlex Fikl }
85613135bc6SAlex Fikl 
857d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
858d71ae5a4SJacob Faibussowitsch {
859f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
860f8170845SAlex Fikl   PetscInt  i, j;
861f8170845SAlex Fikl 
862f8170845SAlex Fikl   PetscFunctionBegin;
863f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
864f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
86548a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
866f8170845SAlex Fikl     }
867f8170845SAlex Fikl   }
8683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
869f8170845SAlex Fikl }
870f8170845SAlex Fikl 
871d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
872d71ae5a4SJacob Faibussowitsch {
873d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
874d8588912SDave May   Vec      *L, *R;
875d8588912SDave May   MPI_Comm  comm;
876d8588912SDave May   PetscInt  i, j;
877d8588912SDave May 
878d8588912SDave May   PetscFunctionBegin;
8799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
880d8588912SDave May   if (right) {
881d8588912SDave May     /* allocate R */
8829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
883d8588912SDave May     /* Create the right vectors */
884d8588912SDave May     for (j = 0; j < bA->nc; j++) {
885d8588912SDave May       for (i = 0; i < bA->nr; i++) {
886d8588912SDave May         if (bA->m[i][j]) {
8879566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
888d8588912SDave May           break;
889d8588912SDave May         }
890d8588912SDave May       }
89108401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
892d8588912SDave May     }
8939566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
894d8588912SDave May     /* hand back control to the nest vector */
89548a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8969566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
897d8588912SDave May   }
898d8588912SDave May 
899d8588912SDave May   if (left) {
900d8588912SDave May     /* allocate L */
9019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
902d8588912SDave May     /* Create the left vectors */
903d8588912SDave May     for (i = 0; i < bA->nr; i++) {
904d8588912SDave May       for (j = 0; j < bA->nc; j++) {
905d8588912SDave May         if (bA->m[i][j]) {
9069566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
907d8588912SDave May           break;
908d8588912SDave May         }
909d8588912SDave May       }
91008401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
911d8588912SDave May     }
912d8588912SDave May 
9139566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
91448a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
915d8588912SDave May 
9169566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
917d8588912SDave May   }
9183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
919d8588912SDave May }
920d8588912SDave May 
921d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
922d71ae5a4SJacob Faibussowitsch {
923d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
92429e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
925d8588912SDave May   PetscInt  i, j;
926d8588912SDave May 
927d8588912SDave May   PetscFunctionBegin;
9289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
929d8588912SDave May   if (isascii) {
9309566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
9329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9339566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
934d8588912SDave May 
9359566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
936d8588912SDave May     for (i = 0; i < bA->nr; i++) {
937d8588912SDave May       for (j = 0; j < bA->nc; j++) {
93819fd82e9SBarry Smith         MatType   type;
939270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
940d8588912SDave May         PetscInt  NR, NC;
941d8588912SDave May         PetscBool isNest = PETSC_FALSE;
942d8588912SDave May 
943d8588912SDave May         if (!bA->m[i][j]) {
9449566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
945d8588912SDave May           continue;
946d8588912SDave May         }
9479566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9489566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9499566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9509566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9519566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
952d8588912SDave May 
9539566063dSJacob 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));
954d8588912SDave May 
95529e60adbSStefano Zampini         if (isNest || viewSub) {
9569566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9579566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9589566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
959d8588912SDave May         }
960d8588912SDave May       }
961d8588912SDave May     }
9629566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
963d8588912SDave May   }
9643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
965d8588912SDave May }
966d8588912SDave May 
967d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
968d71ae5a4SJacob Faibussowitsch {
969d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
970d8588912SDave May   PetscInt  i, j;
971d8588912SDave May 
972d8588912SDave May   PetscFunctionBegin;
973d8588912SDave May   for (i = 0; i < bA->nr; i++) {
974d8588912SDave May     for (j = 0; j < bA->nc; j++) {
975d8588912SDave May       if (!bA->m[i][j]) continue;
9769566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
977d8588912SDave May     }
978d8588912SDave May   }
9793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
980d8588912SDave May }
981d8588912SDave May 
982d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
983d71ae5a4SJacob Faibussowitsch {
984c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
985c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
98606a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
987c222c20dSDavid Ham 
988c222c20dSDavid Ham   PetscFunctionBegin;
989aed4548fSBarry 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);
990c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
991c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
99206a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
99346a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9949566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
99508401ef6SPierre 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);
9969566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
99706a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
99806a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
999c222c20dSDavid Ham     }
1000c222c20dSDavid Ham   }
100106a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
10023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1003c222c20dSDavid Ham }
1004c222c20dSDavid Ham 
1005d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1006d71ae5a4SJacob Faibussowitsch {
10076e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
10086e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
100906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
10106e76ffeaSPierre Jolivet 
10116e76ffeaSPierre Jolivet   PetscFunctionBegin;
1012aed4548fSBarry 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);
10136e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
10146e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
101506a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10166e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10179566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1018c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1019c066aebcSStefano Zampini         Mat M;
1020c066aebcSStefano Zampini 
1021e75569e9SPierre 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);
10229566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10239566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10249566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1025c066aebcSStefano Zampini       }
10269566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
102706a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
102806a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10296e76ffeaSPierre Jolivet     }
10306e76ffeaSPierre Jolivet   }
103106a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10336e76ffeaSPierre Jolivet }
10346e76ffeaSPierre Jolivet 
1035d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1036d71ae5a4SJacob Faibussowitsch {
1037d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1038841e96a3SJed Brown   Mat      *b;
1039841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1040d8588912SDave May 
1041d8588912SDave May   PetscFunctionBegin;
10429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1043841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1044841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1045841e96a3SJed Brown       if (bA->m[i][j]) {
10469566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1047841e96a3SJed Brown       } else {
10480298fd71SBarry Smith         b[i * nc + j] = NULL;
1049d8588912SDave May       }
1050d8588912SDave May     }
1051d8588912SDave May   }
10529566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1053841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
105448a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10559566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1056d8588912SDave May 
10579566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1060d8588912SDave May }
1061d8588912SDave May 
1062d8588912SDave May /* nest api */
106366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1064d71ae5a4SJacob Faibussowitsch {
1065d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10665fd66863SKarl Rupp 
1067d8588912SDave May   PetscFunctionBegin;
106808401ef6SPierre 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);
106908401ef6SPierre 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);
1070d8588912SDave May   *mat = bA->m[idxm][jdxm];
10713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1072d8588912SDave May }
1073d8588912SDave May 
10749ba0d327SJed Brown /*@
107511a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1076d8588912SDave May 
10772ef1f0ffSBarry Smith   Not Collective
1078d8588912SDave May 
1079d8588912SDave May   Input Parameters:
108011a5261eSBarry Smith + A    - `MATNEST` matrix
1081d8588912SDave May . idxm - index of the matrix within the nest matrix
1082629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1083d8588912SDave May 
1084d8588912SDave May   Output Parameter:
10852ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1086d8588912SDave May 
1087d8588912SDave May   Level: developer
1088d8588912SDave May 
1089fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1090db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1091d8588912SDave May @*/
1092d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1093d71ae5a4SJacob Faibussowitsch {
1094d8588912SDave May   PetscFunctionBegin;
10953536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
10963536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
10973536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
10983536838dSStefano Zampini   PetscAssertPointer(sub, 4);
1099cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
11003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1101d8588912SDave May }
1102d8588912SDave May 
110366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1104d71ae5a4SJacob Faibussowitsch {
11050782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
11060782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
11070782ca92SJed Brown 
11080782ca92SJed Brown   PetscFunctionBegin;
110908401ef6SPierre 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);
111008401ef6SPierre 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);
11113536838dSStefano Zampini   if (mat) {
11129566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mat, &m, &n));
11139566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &M, &N));
11149566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
11159566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
11169566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
11179566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1118aed4548fSBarry 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);
1119aed4548fSBarry 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);
11203536838dSStefano Zampini   }
112126fbe8dcSKarl Rupp 
112206a1af2fSStefano Zampini   /* do not increase object state */
11233ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
112406a1af2fSStefano Zampini 
11259566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11270782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11289566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11293536838dSStefano Zampini   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
11303536838dSStefano Zampini   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
113106a1af2fSStefano Zampini   A->nonzerostate++;
11323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11330782ca92SJed Brown }
11340782ca92SJed Brown 
11359ba0d327SJed Brown /*@
113611a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11370782ca92SJed Brown 
11382ef1f0ffSBarry Smith   Logically Collective
11390782ca92SJed Brown 
11400782ca92SJed Brown   Input Parameters:
114111a5261eSBarry Smith + A    - `MATNEST` matrix
11420782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11430782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11442ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11452ef1f0ffSBarry Smith 
11462ef1f0ffSBarry Smith   Level: developer
11470782ca92SJed Brown 
11480782ca92SJed Brown   Notes:
11490782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11500782ca92SJed Brown 
11510782ca92SJed Brown   This increments the reference count of the submatrix.
11520782ca92SJed Brown 
1153fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1154db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11550782ca92SJed Brown @*/
1156d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1157d71ae5a4SJacob Faibussowitsch {
11580782ca92SJed Brown   PetscFunctionBegin;
11593536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11603536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
11613536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
11623536838dSStefano Zampini   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
11633536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11650782ca92SJed Brown }
11660782ca92SJed Brown 
116766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1168d71ae5a4SJacob Faibussowitsch {
1169d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11705fd66863SKarl Rupp 
1171d8588912SDave May   PetscFunctionBegin;
117226fbe8dcSKarl Rupp   if (M) *M = bA->nr;
117326fbe8dcSKarl Rupp   if (N) *N = bA->nc;
117426fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1176d8588912SDave May }
1177d8588912SDave May 
1178d8588912SDave May /*@C
117911a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1180d8588912SDave May 
11812ef1f0ffSBarry Smith   Not Collective
1182d8588912SDave May 
1183f899ff85SJose E. Roman   Input Parameter:
1184629881c0SJed Brown . A - nest matrix
1185d8588912SDave May 
1186d8d19677SJose E. Roman   Output Parameters:
1187629881c0SJed Brown + M   - number of rows in the nest matrix
1188d8588912SDave May . N   - number of cols in the nest matrix
1189e9d3347aSJose E. Roman - mat - array of matrices
1190d8588912SDave May 
11912ef1f0ffSBarry Smith   Level: developer
11922ef1f0ffSBarry Smith 
119311a5261eSBarry Smith   Note:
11942ef1f0ffSBarry Smith   The user should not free the array `mat`.
1195d8588912SDave May 
1196fe59aa6dSJacob Faibussowitsch   Fortran Notes:
119711a5261eSBarry Smith   This routine has a calling sequence
1198351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
119920f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1200e9d3347aSJose E. Roman   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1201351962e3SVincent Le Chenadec 
1202fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1203db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1204d8588912SDave May @*/
1205d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1206d71ae5a4SJacob Faibussowitsch {
1207d8588912SDave May   PetscFunctionBegin;
12083536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1209cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
12103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1211d8588912SDave May }
1212d8588912SDave May 
121366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1214d71ae5a4SJacob Faibussowitsch {
1215d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1216d8588912SDave May 
1217d8588912SDave May   PetscFunctionBegin;
121826fbe8dcSKarl Rupp   if (M) *M = bA->nr;
121926fbe8dcSKarl Rupp   if (N) *N = bA->nc;
12203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1221d8588912SDave May }
1222d8588912SDave May 
12239ba0d327SJed Brown /*@
122411a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1225d8588912SDave May 
12262ef1f0ffSBarry Smith   Not Collective
1227d8588912SDave May 
1228f899ff85SJose E. Roman   Input Parameter:
122911a5261eSBarry Smith . A - `MATNEST` matrix
1230d8588912SDave May 
1231d8d19677SJose E. Roman   Output Parameters:
1232629881c0SJed Brown + M - number of rows in the nested mat
1233629881c0SJed Brown - N - number of cols in the nested mat
1234d8588912SDave May 
1235d8588912SDave May   Level: developer
1236d8588912SDave May 
1237*80670ca5SBarry Smith   Note:
1238*80670ca5SBarry Smith   `size` refers to the number of submatrices in the row and column directions of the nested matrix
1239*80670ca5SBarry Smith 
1240fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1241db781477SPatrick Sanan           `MatNestGetISs()`
1242d8588912SDave May @*/
1243d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1244d71ae5a4SJacob Faibussowitsch {
1245d8588912SDave May   PetscFunctionBegin;
12463536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1247cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1249d8588912SDave May }
1250d8588912SDave May 
1251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1252d71ae5a4SJacob Faibussowitsch {
1253900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1254900e7ff2SJed Brown   PetscInt  i;
1255900e7ff2SJed Brown 
1256900e7ff2SJed Brown   PetscFunctionBegin;
12579371c9d4SSatish Balay   if (rows)
12589371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12599371c9d4SSatish Balay   if (cols)
12609371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1262900e7ff2SJed Brown }
1263900e7ff2SJed Brown 
12643a4d7b9aSSatish Balay /*@C
126511a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1266900e7ff2SJed Brown 
12672ef1f0ffSBarry Smith   Not Collective
1268900e7ff2SJed Brown 
1269f899ff85SJose E. Roman   Input Parameter:
127011a5261eSBarry Smith . A - `MATNEST` matrix
1271900e7ff2SJed Brown 
1272d8d19677SJose E. Roman   Output Parameters:
1273900e7ff2SJed Brown + rows - array of row index sets
1274900e7ff2SJed Brown - cols - array of column index sets
1275900e7ff2SJed Brown 
1276900e7ff2SJed Brown   Level: advanced
1277900e7ff2SJed Brown 
127811a5261eSBarry Smith   Note:
12792ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1280900e7ff2SJed Brown 
1281fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1282fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1283900e7ff2SJed Brown @*/
1284d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1285d71ae5a4SJacob Faibussowitsch {
1286900e7ff2SJed Brown   PetscFunctionBegin;
1287900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1288cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1290900e7ff2SJed Brown }
1291900e7ff2SJed Brown 
1292d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1293d71ae5a4SJacob Faibussowitsch {
1294900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1295900e7ff2SJed Brown   PetscInt  i;
1296900e7ff2SJed Brown 
1297900e7ff2SJed Brown   PetscFunctionBegin;
12989371c9d4SSatish Balay   if (rows)
12999371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
13009371c9d4SSatish Balay   if (cols)
13019371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
13023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1303900e7ff2SJed Brown }
1304900e7ff2SJed Brown 
1305900e7ff2SJed Brown /*@C
130611a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1307900e7ff2SJed Brown 
13082ef1f0ffSBarry Smith   Not Collective
1309900e7ff2SJed Brown 
1310f899ff85SJose E. Roman   Input Parameter:
131111a5261eSBarry Smith . A - `MATNEST` matrix
1312900e7ff2SJed Brown 
1313d8d19677SJose E. Roman   Output Parameters:
13142ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore)
13152ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore)
1316900e7ff2SJed Brown 
1317900e7ff2SJed Brown   Level: advanced
1318900e7ff2SJed Brown 
131911a5261eSBarry Smith   Note:
13202ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1321900e7ff2SJed Brown 
13221cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1323fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1324900e7ff2SJed Brown @*/
1325d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1326d71ae5a4SJacob Faibussowitsch {
1327900e7ff2SJed Brown   PetscFunctionBegin;
1328900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1329cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
13303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1331900e7ff2SJed Brown }
1332900e7ff2SJed Brown 
133366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1334d71ae5a4SJacob Faibussowitsch {
1335207556f9SJed Brown   PetscBool flg;
1336207556f9SJed Brown 
1337207556f9SJed Brown   PetscFunctionBegin;
13389566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1339207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13402a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
134112b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
13423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1343207556f9SJed Brown }
1344207556f9SJed Brown 
1345207556f9SJed Brown /*@C
134611a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1347207556f9SJed Brown 
13482ef1f0ffSBarry Smith   Not Collective
1349207556f9SJed Brown 
1350207556f9SJed Brown   Input Parameters:
135111a5261eSBarry Smith + A     - `MATNEST` matrix
135211a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1353207556f9SJed Brown 
1354207556f9SJed Brown   Level: developer
1355207556f9SJed Brown 
1356fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1357207556f9SJed Brown @*/
1358d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1359d71ae5a4SJacob Faibussowitsch {
1360207556f9SJed Brown   PetscFunctionBegin;
13613536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1362cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1364207556f9SJed Brown }
1365207556f9SJed Brown 
136666976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1367d71ae5a4SJacob Faibussowitsch {
1368c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1369c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
137088ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
137188ffe2e8SJose E. Roman   VecType   vtype, type;
1372d8588912SDave May 
1373d8588912SDave May   PetscFunctionBegin;
13749566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
137506a1af2fSStefano Zampini 
1376c8883902SJed Brown   s->nr = nr;
1377c8883902SJed Brown   s->nc = nc;
1378d8588912SDave May 
1379c8883902SJed Brown   /* Create space for submatrices */
13809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
13818068ee9dSPierre Jolivet   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1382c8883902SJed Brown   for (i = 0; i < nr; i++) {
13838068ee9dSPierre Jolivet     s->m[i] = s->m[0] + i * nc;
1384c8883902SJed Brown     for (j = 0; j < nc; j++) {
13853536838dSStefano Zampini       s->m[i][j] = a ? a[i * nc + j] : NULL;
13863536838dSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1387d8588912SDave May     }
1388d8588912SDave May   }
13899566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13909566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
139188ffe2e8SJose E. Roman   if (isstd) {
139288ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
139388ffe2e8SJose E. Roman     vtype = NULL;
139488ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
139588ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
13963536838dSStefano Zampini         if (s->m[i][j]) {
139788ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13983536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &vtype));
139988ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
140088ffe2e8SJose E. Roman           } else if (sametype) {
14013536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &type));
14029566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
140388ffe2e8SJose E. Roman           }
140488ffe2e8SJose E. Roman         }
140588ffe2e8SJose E. Roman       }
140688ffe2e8SJose E. Roman     }
140788ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
14089566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
140988ffe2e8SJose E. Roman     }
141088ffe2e8SJose E. Roman   }
1411d8588912SDave May 
14129566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1413d8588912SDave May 
14149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
14159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1416c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1417c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1418d8588912SDave May 
14199566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
142006a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
142106a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
142248a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
142306a1af2fSStefano Zampini     }
142406a1af2fSStefano Zampini   }
142506a1af2fSStefano Zampini 
14269566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1427d8588912SDave May 
14289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
14299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
14309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
14319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1432c8883902SJed Brown 
14339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
14349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1435c8883902SJed Brown 
143606a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
143706a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14389566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
143906a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
144006a1af2fSStefano Zampini   if (cong) {
144148a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
144206a1af2fSStefano Zampini   }
144306a1af2fSStefano Zampini   if (!cong) {
1444381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
144506a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
144606a1af2fSStefano Zampini     A->ops->shift           = NULL;
144706a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
144806a1af2fSStefano Zampini   }
144906a1af2fSStefano Zampini 
14509566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14519566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
145206a1af2fSStefano Zampini   A->nonzerostate++;
14533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1454d8588912SDave May }
1455d8588912SDave May 
1456c8883902SJed Brown /*@
145711a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1458c8883902SJed Brown 
1459c3339decSBarry Smith   Collective
1460c8883902SJed Brown 
1461d8d19677SJose E. Roman   Input Parameters:
146211a5261eSBarry Smith + A      - `MATNEST` matrix
1463c8883902SJed Brown . nr     - number of nested row blocks
14642ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1465c8883902SJed Brown . nc     - number of nested column blocks
14662ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
14673536838dSStefano Zampini - a      - array of nr*nc submatrices, or `NULL`
14682ef1f0ffSBarry Smith 
14692ef1f0ffSBarry Smith   Level: advanced
1470c8883902SJed Brown 
1471e9d3347aSJose E. Roman   Notes:
14723536838dSStefano Zampini   This always resets any block matrix information previously set.
1473d8b4a066SPierre Jolivet   Pass `NULL` in the corresponding entry of `a` for an empty block.
147406a1af2fSStefano Zampini 
1475e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array containing the matrices. See
1476e9d3347aSJose E. Roman   `MatCreateNest()` for an example.
1477e9d3347aSJose E. Roman 
14781cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1479c8883902SJed Brown @*/
1480d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1481d71ae5a4SJacob Faibussowitsch {
1482c8883902SJed Brown   PetscFunctionBegin;
1483c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
14843536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nr, 2);
148508401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1486c8883902SJed Brown   if (nr && is_row) {
14874f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
14883536838dSStefano Zampini     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1489c8883902SJed Brown   }
14903536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nc, 4);
149108401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14921664e352SJed Brown   if (nc && is_col) {
14934f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
14943536838dSStefano Zampini     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1495c8883902SJed Brown   }
14963536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1498c8883902SJed Brown }
1499d8588912SDave May 
1500d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1501d71ae5a4SJacob Faibussowitsch {
150277019fcaSJed Brown   PetscBool flg;
150377019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
150477019fcaSJed Brown 
150577019fcaSJed Brown   PetscFunctionBegin;
1506aea6d515SStefano Zampini   *ltog = NULL;
150777019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
150877019fcaSJed Brown     if (islocal[i]) {
15099566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
151077019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
151177019fcaSJed Brown     } else {
15129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
151377019fcaSJed Brown     }
151477019fcaSJed Brown     m += mi;
151577019fcaSJed Brown   }
15163ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1517aea6d515SStefano Zampini 
15189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1519165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
15200298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1521e108cb99SStefano Zampini     Mat                    sub  = NULL;
1522f6d38dbbSStefano Zampini     PetscSF                sf;
1523f6d38dbbSStefano Zampini     PetscLayout            map;
1524aea6d515SStefano Zampini     const PetscInt        *ix2;
152577019fcaSJed Brown 
1526165cd838SBarry Smith     if (!colflg) {
15279566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
152877019fcaSJed Brown     } else {
15299566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
153077019fcaSJed Brown     }
1531191fd14bSBarry Smith     if (sub) {
1532191fd14bSBarry Smith       if (!colflg) {
15339566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1534191fd14bSBarry Smith       } else {
15359566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1536191fd14bSBarry Smith       }
1537191fd14bSBarry Smith     }
153877019fcaSJed Brown     /*
153977019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
154077019fcaSJed 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.
154177019fcaSJed Brown     */
15429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1543aea6d515SStefano Zampini     if (islocal[i]) {
1544aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1545aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1546aea6d515SStefano Zampini 
15479566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
154828b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1549aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1551aea6d515SStefano Zampini 
1552aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1554aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1555aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1556aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1557aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1558aea6d515SStefano Zampini         nleaves++;
1559aea6d515SStefano Zampini       }
15609566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15619566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15629566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15639566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15649566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15659566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15669566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15679566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15689566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15699566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15709566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1571aea6d515SStefano Zampini     } else {
15729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1573aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1574aea6d515SStefano Zampini     }
15759566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
157677019fcaSJed Brown     m += mi;
157777019fcaSJed Brown   }
15789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
158077019fcaSJed Brown }
158177019fcaSJed Brown 
1582d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1583d8588912SDave May /*
1584d8588912SDave May   nprocessors = NP
1585d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1586d8588912SDave May        proc 0: => (g_0,h_0,)
1587d8588912SDave May        proc 1: => (g_1,h_1,)
1588d8588912SDave May        ...
1589d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1590d8588912SDave May 
1591d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1592d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1593d8588912SDave May 
1594d8588912SDave May             proc 0:
1595d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1596d8588912SDave May             proc 1:
1597d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1598d8588912SDave May 
1599d8588912SDave May             proc NP-1:
1600d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1601d8588912SDave May */
1602d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1603d71ae5a4SJacob Faibussowitsch {
1604e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
16058188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
16060298fd71SBarry Smith   Mat       sub = NULL;
1607d8588912SDave May 
1608d8588912SDave May   PetscFunctionBegin;
16099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
16109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1611d8588912SDave May   if (is_row) { /* valid IS is passed in */
1612a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1613e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16149566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
161526fbe8dcSKarl Rupp 
1616e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1617d8588912SDave May     }
16182ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
16198188e55aSJed Brown     nsum = 0;
16208188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
16219566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
162228b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
16239566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
162408401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16258188e55aSJed Brown       nsum += n;
16268188e55aSJed Brown     }
16279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
162830bc264bSJed Brown     offset -= nsum;
1629e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16309566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16319566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
16329566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16339566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
16349566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
16352ae74bdbSJed Brown       offset += n;
1636d8588912SDave May     }
1637d8588912SDave May   }
1638d8588912SDave May 
1639d8588912SDave May   if (is_col) { /* valid IS is passed in */
1640a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1641e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16429566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
164326fbe8dcSKarl Rupp 
1644e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1645d8588912SDave May     }
16462ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16472ae74bdbSJed Brown     offset = A->cmap->rstart;
16488188e55aSJed Brown     nsum   = 0;
16498188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16509566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
165128b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16529566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
165308401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16548188e55aSJed Brown       nsum += n;
16558188e55aSJed Brown     }
16569566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
165730bc264bSJed Brown     offset -= nsum;
1658e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16599566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16609566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16619566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16629566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16639566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16642ae74bdbSJed Brown       offset += n;
1665d8588912SDave May     }
1666d8588912SDave May   }
1667e2d7f03fSJed Brown 
1668e2d7f03fSJed Brown   /* Set up the local ISs */
16699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1671e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1672e2d7f03fSJed Brown     IS                     isloc;
16730298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1674e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16759566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16769566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1677207556f9SJed Brown     if (rmap) {
16789566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16799566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16809566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16819566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1682207556f9SJed Brown     } else {
1683207556f9SJed Brown       nlocal = 0;
16840298fd71SBarry Smith       isloc  = NULL;
1685207556f9SJed Brown     }
1686e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1687e2d7f03fSJed Brown     offset += nlocal;
1688e2d7f03fSJed Brown   }
16898188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1690e2d7f03fSJed Brown     IS                     isloc;
16910298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1692e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16939566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16949566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1695207556f9SJed Brown     if (cmap) {
16969566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16989566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16999566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1700207556f9SJed Brown     } else {
1701207556f9SJed Brown       nlocal = 0;
17020298fd71SBarry Smith       isloc  = NULL;
1703207556f9SJed Brown     }
1704e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1705e2d7f03fSJed Brown     offset += nlocal;
1706e2d7f03fSJed Brown   }
17070189643fSJed Brown 
170877019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
170977019fcaSJed Brown   {
171045b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
17119566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
17129566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
17139566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
17149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
17159566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
171677019fcaSJed Brown   }
171777019fcaSJed Brown 
171876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17190189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
17200189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
17210189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
17220189643fSJed Brown         Mat      B = vs->m[i][j];
17230189643fSJed Brown         if (!B) continue;
17249566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
17259566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
17269566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
17279566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
17289566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
17299566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1730aed4548fSBarry 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);
1731aed4548fSBarry 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);
17320189643fSJed Brown       }
17330189643fSJed Brown     }
173476bd3646SJed Brown   }
1735a061e289SJed Brown 
1736a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1737a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1738a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
17393ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1740a061e289SJed Brown     }
1741a061e289SJed Brown   }
1742a061e289SJed Brown   A->assembled = PETSC_TRUE;
17433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1744d8588912SDave May }
1745d8588912SDave May 
174645c38901SJed Brown /*@C
174711a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1748659c6bb0SJed Brown 
174911a5261eSBarry Smith   Collective
1750659c6bb0SJed Brown 
1751d8d19677SJose E. Roman   Input Parameters:
175211a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1753659c6bb0SJed Brown . nr     - number of nested row blocks
17542ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1755659c6bb0SJed Brown . nc     - number of nested column blocks
17562ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1757e9d3347aSJose E. Roman - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1758659c6bb0SJed Brown 
1759659c6bb0SJed Brown   Output Parameter:
1760659c6bb0SJed Brown . B - new matrix
1761659c6bb0SJed Brown 
1762e9d3347aSJose E. Roman   Note:
1763e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array holding references to the matrices.
1764e9d3347aSJose E. Roman   For instance, to represent the matrix
1765e9d3347aSJose E. Roman   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1766e9d3347aSJose E. Roman   one should use `Mat a[4]={A11,A12,A21,A22}`.
1767e9d3347aSJose E. Roman 
1768659c6bb0SJed Brown   Level: advanced
1769659c6bb0SJed Brown 
17701cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1771db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1772db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1773659c6bb0SJed Brown @*/
1774d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1775d71ae5a4SJacob Faibussowitsch {
1776d8588912SDave May   PetscFunctionBegin;
17773536838dSStefano Zampini   PetscCall(MatCreate(comm, B));
17783536838dSStefano Zampini   PetscCall(MatSetType(*B, MATNEST));
17793536838dSStefano Zampini   (*B)->preallocated = PETSC_TRUE;
17803536838dSStefano Zampini   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
17813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1782d8588912SDave May }
1783659c6bb0SJed Brown 
178466976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1785d71ae5a4SJacob Faibussowitsch {
1786b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
178723875855Sstefano_zampini   Mat          *trans;
1788b68353e5Sstefano_zampini   PetscScalar **avv;
1789b68353e5Sstefano_zampini   PetscScalar  *vv;
1790b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1791b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1792b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1793b68353e5Sstefano_zampini   PetscBool     done;
1794b68353e5Sstefano_zampini 
1795b68353e5Sstefano_zampini   PetscFunctionBegin;
17969566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1797b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1798b68353e5Sstefano_zampini     PetscInt rnr;
1799b68353e5Sstefano_zampini 
18009566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
180128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
180208401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
18039566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1804b68353e5Sstefano_zampini   }
1805b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1806b68353e5Sstefano_zampini   nnz = 0;
18079566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1808b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1809b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1810b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1811b68353e5Sstefano_zampini       if (B) {
1812b68353e5Sstefano_zampini         PetscScalar *naa;
1813b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
181423875855Sstefano_zampini         PetscBool    istrans;
1815b68353e5Sstefano_zampini 
1816013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
181723875855Sstefano_zampini         if (istrans) {
181823875855Sstefano_zampini           Mat Bt;
181923875855Sstefano_zampini 
18209566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
18219566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
182223875855Sstefano_zampini           B = trans[i * nest->nc + j];
1823013e2dc7SBarry Smith         } else {
1824013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1825013e2dc7SBarry Smith           if (istrans) {
1826013e2dc7SBarry Smith             Mat Bt;
1827013e2dc7SBarry Smith 
1828013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1829013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1830013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1831013e2dc7SBarry Smith           }
183223875855Sstefano_zampini         }
18339566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
183428b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
18359566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1836b68353e5Sstefano_zampini         nnz += nii[nnr];
1837b68353e5Sstefano_zampini 
1838b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1839b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1840b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1841b68353e5Sstefano_zampini       }
1842b68353e5Sstefano_zampini     }
1843b68353e5Sstefano_zampini   }
1844b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1848b68353e5Sstefano_zampini   } else {
184908401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1850b68353e5Sstefano_zampini   }
1851b68353e5Sstefano_zampini 
1852b68353e5Sstefano_zampini   /* new row pointer */
18539566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1854b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1855b68353e5Sstefano_zampini     PetscInt ncr, rst;
1856b68353e5Sstefano_zampini 
18579566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18589566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1859b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1860b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1861b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1862b68353e5Sstefano_zampini         PetscInt  ir;
1863b68353e5Sstefano_zampini 
1864b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1865b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1866b68353e5Sstefano_zampini           nii++;
1867b68353e5Sstefano_zampini         }
1868b68353e5Sstefano_zampini       }
1869b68353e5Sstefano_zampini     }
1870b68353e5Sstefano_zampini   }
1871b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1872b68353e5Sstefano_zampini 
1873b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18749566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1875b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1876b68353e5Sstefano_zampini     PetscInt ncr, rst;
1877b68353e5Sstefano_zampini 
18789566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18799566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1880b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1881b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1882b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1883b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1884b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1885b68353e5Sstefano_zampini         PetscInt     ir, cst;
1886b68353e5Sstefano_zampini 
18879566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1888b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1889b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1890b68353e5Sstefano_zampini 
1891b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1892b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1893b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1894b68353e5Sstefano_zampini             njj++;
1895b68353e5Sstefano_zampini             nvv++;
1896b68353e5Sstefano_zampini           }
1897b68353e5Sstefano_zampini           ci[ir] += rsize;
1898b68353e5Sstefano_zampini           nii++;
1899b68353e5Sstefano_zampini         }
1900b68353e5Sstefano_zampini       }
1901b68353e5Sstefano_zampini     }
1902b68353e5Sstefano_zampini   }
19039566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1904b68353e5Sstefano_zampini 
1905b68353e5Sstefano_zampini   /* restore info */
1906b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1907b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1908b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1909b68353e5Sstefano_zampini       if (B) {
1910b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
191123875855Sstefano_zampini 
191223875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
19139566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
191428b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
19159566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
19169566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1917b68353e5Sstefano_zampini       }
1918b68353e5Sstefano_zampini     }
1919b68353e5Sstefano_zampini   }
19209566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1921b68353e5Sstefano_zampini 
1922b68353e5Sstefano_zampini   /* finalize newmat */
1923b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
19249566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1925b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1926b68353e5Sstefano_zampini     Mat B;
1927b68353e5Sstefano_zampini 
19289566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
19299566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1930b68353e5Sstefano_zampini   }
19319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
19329566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1933b68353e5Sstefano_zampini   {
1934b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1935b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1936b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1937b68353e5Sstefano_zampini   }
19383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1939b68353e5Sstefano_zampini }
1940b68353e5Sstefano_zampini 
1941d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1942d71ae5a4SJacob Faibussowitsch {
1943be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1944be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1945be705e3aSPierre Jolivet   PetscBool flg;
1946be705e3aSPierre Jolivet 
1947be705e3aSPierre Jolivet   PetscFunctionBegin;
1948be705e3aSPierre Jolivet   /* Fill by row */
1949be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1950be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1951be705e3aSPierre Jolivet     IS              bNis;
1952be705e3aSPierre Jolivet     PetscInt        bN;
1953be705e3aSPierre Jolivet     const PetscInt *bNindices;
19549566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19559566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19569566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1957be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1958fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1959be705e3aSPierre Jolivet       PetscInt        bm, br;
1960be705e3aSPierre Jolivet       const PetscInt *bmindices;
1961be705e3aSPierre Jolivet       if (!B) continue;
1962013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1963be705e3aSPierre Jolivet       if (flg) {
1964cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1965cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19669566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1967be705e3aSPierre Jolivet         B = D;
1968be705e3aSPierre Jolivet       }
19699566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1970be705e3aSPierre Jolivet       if (flg) {
1971fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1972fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1973be705e3aSPierre Jolivet         B = D;
1974be705e3aSPierre Jolivet       }
19759566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19769566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19779566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1978be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1979be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1980be705e3aSPierre Jolivet         const PetscInt    *brcols;
1981be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1982be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19839566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19849566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1985be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1986be705e3aSPierre Jolivet         /*
1987be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1988be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1989be705e3aSPierre Jolivet          */
1990be705e3aSPierre Jolivet         if (a != 1.0) {
19919566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1992be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19939566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19949566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1995be705e3aSPierre Jolivet         } else {
19969566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1997be705e3aSPierre Jolivet         }
19989566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19999566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
2000be705e3aSPierre Jolivet       }
2001fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
20029566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2003be705e3aSPierre Jolivet     }
20049566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
20059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
2006be705e3aSPierre Jolivet   }
20079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
20089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
20093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2010be705e3aSPierre Jolivet }
2011be705e3aSPierre Jolivet 
201266976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2013d71ae5a4SJacob Faibussowitsch {
2014629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
2015e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2016b68353e5Sstefano_zampini   PetscMPIInt size;
2017629c3df2SDmitry Karpeev   Mat         C;
2018629c3df2SDmitry Karpeev 
2019629c3df2SDmitry Karpeev   PetscFunctionBegin;
20209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2021b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2022b68353e5Sstefano_zampini     PetscInt  nf;
2023b68353e5Sstefano_zampini     PetscBool fast;
2024b68353e5Sstefano_zampini 
20259566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
202648a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2027b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
2028b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
2029b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
2030b68353e5Sstefano_zampini         if (B) {
20319566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
203223875855Sstefano_zampini           if (!fast) {
203323875855Sstefano_zampini             PetscBool istrans;
203423875855Sstefano_zampini 
2035013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
203623875855Sstefano_zampini             if (istrans) {
203723875855Sstefano_zampini               Mat Bt;
203823875855Sstefano_zampini 
20399566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
20409566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2041013e2dc7SBarry Smith             } else {
2042013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2043013e2dc7SBarry Smith               if (istrans) {
2044013e2dc7SBarry Smith                 Mat Bt;
2045013e2dc7SBarry Smith 
2046013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2047013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2048013e2dc7SBarry Smith               }
204923875855Sstefano_zampini             }
2050b68353e5Sstefano_zampini           }
2051b68353e5Sstefano_zampini         }
2052b68353e5Sstefano_zampini       }
2053b68353e5Sstefano_zampini     }
2054b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20559566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2056b68353e5Sstefano_zampini       if (fast) {
2057b68353e5Sstefano_zampini         PetscInt f, s;
2058b68353e5Sstefano_zampini 
20599566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20609371c9d4SSatish Balay         if (f != nf || s != 1) {
20619371c9d4SSatish Balay           fast = PETSC_FALSE;
20629371c9d4SSatish Balay         } else {
20639566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2064b68353e5Sstefano_zampini           nf += f;
2065b68353e5Sstefano_zampini         }
2066b68353e5Sstefano_zampini       }
2067b68353e5Sstefano_zampini     }
2068b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20699566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2070b68353e5Sstefano_zampini       if (fast) {
2071b68353e5Sstefano_zampini         PetscInt f, s;
2072b68353e5Sstefano_zampini 
20739566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20749371c9d4SSatish Balay         if (f != nf || s != 1) {
20759371c9d4SSatish Balay           fast = PETSC_FALSE;
20769371c9d4SSatish Balay         } else {
20779566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2078b68353e5Sstefano_zampini           nf += f;
2079b68353e5Sstefano_zampini         }
2080b68353e5Sstefano_zampini       }
2081b68353e5Sstefano_zampini     }
2082b68353e5Sstefano_zampini     if (fast) {
20839566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20843ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2085b68353e5Sstefano_zampini     }
2086b68353e5Sstefano_zampini   }
20879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20899566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2090d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2091d1487292SPierre Jolivet   else {
20929566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20939566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20949566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2095629c3df2SDmitry Karpeev   }
20969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2097e30678d3SPierre Jolivet   if (m) {
2098629c3df2SDmitry Karpeev     onnz = dnnz + m;
2099629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2100629c3df2SDmitry Karpeev       dnnz[k] = 0;
2101629c3df2SDmitry Karpeev       onnz[k] = 0;
2102629c3df2SDmitry Karpeev     }
2103e30678d3SPierre Jolivet   }
2104629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2105629c3df2SDmitry Karpeev     IS              bNis;
2106629c3df2SDmitry Karpeev     PetscInt        bN;
2107629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2108fd8a7442SPierre Jolivet     PetscBool       flg;
2109629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
21109566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
21119566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
21129566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2113629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2114629c3df2SDmitry Karpeev       PetscSF         bmsf;
2115649b366bSFande Kong       PetscSFNode    *iremote;
2116fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2117649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2118629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2119629c3df2SDmitry Karpeev       if (!B) continue;
21209566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
21219566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
21229566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
21239566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
21249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
21259566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2126649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2127649b366bSFande Kong         sub_dnnz[k] = 0;
2128649b366bSFande Kong         sub_onnz[k] = 0;
2129649b366bSFande Kong       }
2130dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2131fd8a7442SPierre Jolivet       if (flg) {
2132fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2133fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2134fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2135fd8a7442SPierre Jolivet         B = D;
2136fd8a7442SPierre Jolivet       }
2137fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2138fd8a7442SPierre Jolivet       if (flg) {
2139fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2140fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2141fd8a7442SPierre Jolivet         B = D;
2142fd8a7442SPierre Jolivet       }
2143629c3df2SDmitry Karpeev       /*
2144629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2145629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2146629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2147629c3df2SDmitry Karpeev        */
21489566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2149629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2150131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2151629c3df2SDmitry Karpeev         const PetscInt *brcols;
2152a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2153131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21549566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2155649b366bSFande Kong         /* how many roots  */
21569371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21579371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2158649b366bSFande Kong         /* get nonzero pattern */
21599566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2160629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2161629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2162649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2163649b366bSFande Kong             sub_dnnz[br]++;
2164649b366bSFande Kong           } else {
2165649b366bSFande Kong             sub_onnz[br]++;
2166649b366bSFande Kong           }
2167629c3df2SDmitry Karpeev         }
21689566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2169629c3df2SDmitry Karpeev       }
2170fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21719566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2172629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21739566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21749566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21759566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21769566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21779566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21789566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21799566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21809566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2181629c3df2SDmitry Karpeev     }
21829566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
218465a4a0a3Sstefano_zampini   }
218565a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
218665a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
218765a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
218865a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2189629c3df2SDmitry Karpeev   }
21909566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21919566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21929566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21939566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2194d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21959566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2196d1487292SPierre Jolivet   } else *newmat = C;
21973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2198be705e3aSPierre Jolivet }
2199629c3df2SDmitry Karpeev 
220066976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2201d71ae5a4SJacob Faibussowitsch {
2202629c3df2SDmitry Karpeev   Mat      B;
2203be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2204be705e3aSPierre Jolivet 
2205be705e3aSPierre Jolivet   PetscFunctionBegin;
22069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
22079566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2208be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2209be705e3aSPierre Jolivet     B = *newmat;
22109566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2211be705e3aSPierre Jolivet   } else {
22129566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2213629c3df2SDmitry Karpeev   }
22149566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2215be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
22169566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2217be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
22183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2219629c3df2SDmitry Karpeev }
2220629c3df2SDmitry Karpeev 
222166976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2222d71ae5a4SJacob Faibussowitsch {
22238b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
22243c6db4c4SPierre Jolivet   MatOperation opAdd;
22258b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
22268b7d3b4bSBarry Smith   PetscBool    flg;
22278b7d3b4bSBarry Smith 
22284d86920dSPierre Jolivet   PetscFunctionBegin;
222952c5f739Sprj-   *has = PETSC_FALSE;
22303c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
22313c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
22328b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
22338b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
22348b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
22359566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
22363ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
22378b7d3b4bSBarry Smith       }
22388b7d3b4bSBarry Smith     }
22398b7d3b4bSBarry Smith   }
22403c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
22413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22428b7d3b4bSBarry Smith }
22438b7d3b4bSBarry Smith 
2244659c6bb0SJed Brown /*MC
22452ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2246659c6bb0SJed Brown 
2247659c6bb0SJed Brown   Level: intermediate
2248659c6bb0SJed Brown 
2249659c6bb0SJed Brown   Notes:
225011a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2251659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
225211a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2253659c6bb0SJed Brown 
22548b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22558b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22568b7d3b4bSBarry Smith   than the nest matrix.
22578b7d3b4bSBarry Smith 
22581cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2259db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2260db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2261659c6bb0SJed Brown M*/
2262d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2263d71ae5a4SJacob Faibussowitsch {
2264c8883902SJed Brown   Mat_Nest *s;
2265c8883902SJed Brown 
2266c8883902SJed Brown   PetscFunctionBegin;
22674dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2268c8883902SJed Brown   A->data = (void *)s;
2269e7c19651SJed Brown 
2270e7c19651SJed Brown   s->nr            = -1;
2271e7c19651SJed Brown   s->nc            = -1;
22720298fd71SBarry Smith   s->m             = NULL;
2273e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2274c8883902SJed Brown 
22759566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
227626fbe8dcSKarl Rupp 
2277c8883902SJed Brown   A->ops->mult                      = MatMult_Nest;
22789194d70fSJed Brown   A->ops->multadd                   = MatMultAdd_Nest;
2279c8883902SJed Brown   A->ops->multtranspose             = MatMultTranspose_Nest;
22809194d70fSJed Brown   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2281f8170845SAlex Fikl   A->ops->transpose                 = MatTranspose_Nest;
22820998551bSBlanca Mellado Pinto   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
22830998551bSBlanca Mellado Pinto   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2284c8883902SJed Brown   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2285c8883902SJed Brown   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2286c8883902SJed Brown   A->ops->zeroentries               = MatZeroEntries_Nest;
2287c222c20dSDavid Ham   A->ops->copy                      = MatCopy_Nest;
22886e76ffeaSPierre Jolivet   A->ops->axpy                      = MatAXPY_Nest;
2289c8883902SJed Brown   A->ops->duplicate                 = MatDuplicate_Nest;
22907dae84e0SHong Zhang   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2291c8883902SJed Brown   A->ops->destroy                   = MatDestroy_Nest;
2292c8883902SJed Brown   A->ops->view                      = MatView_Nest;
2293f4259b30SLisandro Dalcin   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2294c8883902SJed Brown   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2295c8883902SJed Brown   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2296429bac76SJed Brown   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2297429bac76SJed Brown   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2298a061e289SJed Brown   A->ops->scale                     = MatScale_Nest;
2299a061e289SJed Brown   A->ops->shift                     = MatShift_Nest;
230013135bc6SAlex Fikl   A->ops->diagonalset               = MatDiagonalSet_Nest;
2301f8170845SAlex Fikl   A->ops->setrandom                 = MatSetRandom_Nest;
23028b7d3b4bSBarry Smith   A->ops->hasoperation              = MatHasOperation_Nest;
2303381b8e50SStefano Zampini   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2304c8883902SJed Brown 
2305f4259b30SLisandro Dalcin   A->spptr     = NULL;
2306c8883902SJed Brown   A->assembled = PETSC_FALSE;
2307c8883902SJed Brown 
2308c8883902SJed Brown   /* expose Nest api's */
23099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
23109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
23119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
23129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
23139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
23149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
23159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
23169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
23179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
23189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
23199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
23209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
23219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
23229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
23239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
23249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2325c8883902SJed Brown 
23269566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
23273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2328c8883902SJed Brown }
2329