xref: /petsc/src/mat/impls/nest/matnest.c (revision c57d7d18f4134f5031145dadb69a50f319e30b55)
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));
1249566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, 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));
1299566063dSJacob Faibussowitsch       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (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 
1489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15152c5f739Sprj- }
15252c5f739Sprj- 
15366976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx)
154d71ae5a4SJacob Faibussowitsch {
15552c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15652c5f739Sprj-   PetscInt    i;
15752c5f739Sprj- 
15852c5f739Sprj-   PetscFunctionBegin;
1599566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16048a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1619566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1629566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
1633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16452c5f739Sprj- }
16552c5f739Sprj- 
166a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
167d71ae5a4SJacob Faibussowitsch {
1686718818eSStefano Zampini   Mat_Nest          *bA;
1696718818eSStefano Zampini   Mat                viewB, workC;
17052c5f739Sprj-   const PetscScalar *barray;
1716718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1724222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1736718818eSStefano Zampini   PetscBool          cisdense;
1746718818eSStefano Zampini   Mat                A, B;
1756718818eSStefano Zampini   PetscReal          fill;
17652c5f739Sprj- 
17752c5f739Sprj-   PetscFunctionBegin;
1780d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
17928b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1806718818eSStefano Zampini   A    = C->product->A;
1816718818eSStefano Zampini   B    = C->product->B;
1826718818eSStefano Zampini   fill = C->product->fill;
1836718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1846718818eSStefano Zampini   nr   = bA->nr;
1856718818eSStefano Zampini   nc   = bA->nc;
1869566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1880572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1899566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1909566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1919566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1939566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1940572eedcSPierre Jolivet   }
1959566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19648a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1979566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
1986718818eSStefano Zampini   if (!N) {
1996718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2003ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20152c5f739Sprj-   }
20252c5f739Sprj- 
2039566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2046718818eSStefano Zampini   C->product->data    = contents;
2056718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2069566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20752c5f739Sprj-   contents->k = nr * nc;
20852c5f739Sprj-   for (i = 0; i < nr; i++) {
2099566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
21052c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
21152c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
21252c5f739Sprj-   }
21352c5f739Sprj-   for (i = 0; i < nc; i++) {
2149566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
21552c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21652c5f739Sprj-   }
2179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2199566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
22152c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22252c5f739Sprj-   for (j = 0; j < nc; j++) {
2239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
2249566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB));
2259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22652c5f739Sprj-     for (i = 0; i < nr; i++) {
22752c5f739Sprj-       if (!bA->m[i][j]) continue;
22852c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2294222ddf1SHong Zhang 
2309566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2314222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2329566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2339566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2349566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2359566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2374222ddf1SHong Zhang 
2386718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2399566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2409566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
24152c5f739Sprj-     }
2429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24352c5f739Sprj-   }
2449566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
24552c5f739Sprj- 
2466718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24852c5f739Sprj- }
24952c5f739Sprj- 
250a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
251d71ae5a4SJacob Faibussowitsch {
2524222ddf1SHong Zhang   Mat_Product *product = C->product;
25352c5f739Sprj- 
25452c5f739Sprj-   PetscFunctionBegin;
255*c57d7d18SPierre Jolivet   if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25752c5f739Sprj- }
25852c5f739Sprj- 
259d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
260d71ae5a4SJacob Faibussowitsch {
261d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
262207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
263207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
264d8588912SDave May 
265d8588912SDave May   PetscFunctionBegin;
2669566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2679566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
268207556f9SJed Brown   for (j = 0; j < nc; j++) {
2699566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
270609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2716c75ac25SJed Brown       if (!bA->m[i][j]) continue;
272609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2739566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));
274d8588912SDave May     }
275d8588912SDave May   }
2769566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2779566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
279d8588912SDave May }
280d8588912SDave May 
281d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
282d71ae5a4SJacob Faibussowitsch {
2839194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2849194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
2859194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
2869194d70fSJed Brown 
2879194d70fSJed Brown   PetscFunctionBegin;
2889566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2899566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
2909194d70fSJed Brown   for (j = 0; j < nc; j++) {
2919194d70fSJed Brown     if (y != z) {
2929194d70fSJed Brown       Vec by;
2939566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
2949566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
2959566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
2969194d70fSJed Brown     }
2979194d70fSJed Brown     for (i = 0; i < nr; i++) {
2986c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2999194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3009566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));
3019194d70fSJed Brown     }
3029194d70fSJed Brown   }
3039566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3049566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3069194d70fSJed Brown }
3079194d70fSJed Brown 
308d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
309d71ae5a4SJacob Faibussowitsch {
310f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
311f8170845SAlex Fikl   Mat       C;
312f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
313f8170845SAlex Fikl 
314f8170845SAlex Fikl   PetscFunctionBegin;
3157fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
316aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
317f8170845SAlex Fikl 
318cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
319f8170845SAlex Fikl     Mat *subs;
320f8170845SAlex Fikl     IS  *is_row, *is_col;
321f8170845SAlex Fikl 
3229566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3249566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
325cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
326ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
327ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
328ddeb9bd8SAlex Fikl       }
329ddeb9bd8SAlex Fikl     }
330ddeb9bd8SAlex Fikl 
3319566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3329566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3339566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
334f8170845SAlex Fikl   } else {
335f8170845SAlex Fikl     C = *B;
336f8170845SAlex Fikl   }
337f8170845SAlex Fikl 
338f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
339f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
340f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
341f8170845SAlex Fikl       if (bA->m[i][j]) {
3429566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
343f8170845SAlex Fikl       } else {
344f8170845SAlex Fikl         bC->m[j][i] = NULL;
345f8170845SAlex Fikl       }
346f8170845SAlex Fikl     }
347f8170845SAlex Fikl   }
348f8170845SAlex Fikl 
349cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
350f8170845SAlex Fikl     *B = C;
351f8170845SAlex Fikl   } else {
3529566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
353f8170845SAlex Fikl   }
3543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
355f8170845SAlex Fikl }
356f8170845SAlex Fikl 
357d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
358d71ae5a4SJacob Faibussowitsch {
359e2d7f03fSJed Brown   IS      *lst = *list;
360e2d7f03fSJed Brown   PetscInt i;
361e2d7f03fSJed Brown 
362e2d7f03fSJed Brown   PetscFunctionBegin;
3633ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
3649371c9d4SSatish Balay   for (i = 0; i < n; i++)
3659371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3669566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3670298fd71SBarry Smith   *list = NULL;
3683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
369e2d7f03fSJed Brown }
370e2d7f03fSJed Brown 
371d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
372d71ae5a4SJacob Faibussowitsch {
373d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
374d8588912SDave May   PetscInt  i, j;
375d8588912SDave May 
376d8588912SDave May   PetscFunctionBegin;
377d8588912SDave May   /* release the matrices and the place holders */
3789566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
3799566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
3809566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
3819566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
382d8588912SDave May 
3839566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
3849566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
3859566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
386d8588912SDave May 
3879566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
388207556f9SJed Brown 
389d8588912SDave May   /* release the matrices and the place holders */
390d8588912SDave May   if (vs->m) {
391d8588912SDave May     for (i = 0; i < vs->nr; i++) {
39248a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
3939566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
394d8588912SDave May     }
3959566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
396d8588912SDave May   }
39706a1af2fSStefano Zampini 
39806a1af2fSStefano Zampini   /* restore defaults */
39906a1af2fSStefano Zampini   vs->nr            = 0;
40006a1af2fSStefano Zampini   vs->nc            = 0;
40106a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40306a1af2fSStefano Zampini }
40406a1af2fSStefano Zampini 
405d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
406d71ae5a4SJacob Faibussowitsch {
407362febeeSStefano Zampini   PetscFunctionBegin;
4089566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4099566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
427d8588912SDave May }
428d8588912SDave May 
429d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
430d71ae5a4SJacob Faibussowitsch {
431381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
432381b8e50SStefano Zampini   PetscInt  i;
433381b8e50SStefano Zampini 
434381b8e50SStefano Zampini   PetscFunctionBegin;
435381b8e50SStefano Zampini   if (dd) *dd = 0;
436381b8e50SStefano Zampini   if (!vs->nr) {
437381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4383ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
439381b8e50SStefano Zampini   }
440381b8e50SStefano Zampini   *missing = PETSC_FALSE;
441381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
442381b8e50SStefano Zampini     *missing = PETSC_TRUE;
443381b8e50SStefano Zampini     if (vs->m[i][i]) {
4449566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
44508401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
446381b8e50SStefano Zampini     }
447381b8e50SStefano Zampini   }
4483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
449381b8e50SStefano Zampini }
450381b8e50SStefano Zampini 
451d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
452d71ae5a4SJacob Faibussowitsch {
453d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
454d8588912SDave May   PetscInt  i, j;
45506a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
456d8588912SDave May 
457d8588912SDave May   PetscFunctionBegin;
458d8588912SDave May   for (i = 0; i < vs->nr; i++) {
459d8588912SDave May     for (j = 0; j < vs->nc; j++) {
46006a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
461e7c19651SJed Brown       if (vs->m[i][j]) {
4629566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
463e7c19651SJed Brown         if (!vs->splitassembly) {
464e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
465e7c19651SJed 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
466e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
467e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
468e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
469e7c19651SJed Brown            */
4709566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4719566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
472e7c19651SJed Brown         }
473e7c19651SJed Brown       }
47406a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
47506a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
476d8588912SDave May     }
477d8588912SDave May   }
47806a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
4793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
480d8588912SDave May }
481d8588912SDave May 
482d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
483d71ae5a4SJacob Faibussowitsch {
484d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
485d8588912SDave May   PetscInt  i, j;
486d8588912SDave May 
487d8588912SDave May   PetscFunctionBegin;
488d8588912SDave May   for (i = 0; i < vs->nr; i++) {
489d8588912SDave May     for (j = 0; j < vs->nc; j++) {
490e7c19651SJed Brown       if (vs->m[i][j]) {
49148a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
492e7c19651SJed Brown       }
493d8588912SDave May     }
494d8588912SDave May   }
4953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
496d8588912SDave May }
497d8588912SDave May 
498d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
499d71ae5a4SJacob Faibussowitsch {
500f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
501f349c1fdSJed Brown   PetscInt  j;
502f349c1fdSJed Brown   Mat       sub;
503d8588912SDave May 
504d8588912SDave May   PetscFunctionBegin;
5050298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
506f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5079566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
508f349c1fdSJed Brown   *B = sub;
5093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
510d8588912SDave May }
511d8588912SDave May 
512d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
513d71ae5a4SJacob Faibussowitsch {
514f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
515f349c1fdSJed Brown   PetscInt  i;
516f349c1fdSJed Brown   Mat       sub;
517f349c1fdSJed Brown 
518f349c1fdSJed Brown   PetscFunctionBegin;
5190298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
520f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5219566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
522f349c1fdSJed Brown   *B = sub;
5233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
524d8588912SDave May }
525d8588912SDave May 
526d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
527d71ae5a4SJacob Faibussowitsch {
52818d228c0SPierre Jolivet   PetscInt  i, j, size, m;
529f349c1fdSJed Brown   PetscBool flg;
53018d228c0SPierre Jolivet   IS        out, concatenate[2];
531f349c1fdSJed Brown 
532f349c1fdSJed Brown   PetscFunctionBegin;
5334f572ea9SToby Isaac   PetscAssertPointer(list, 3);
534f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
53518d228c0SPierre Jolivet   if (begin) {
5364f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
53718d228c0SPierre Jolivet     *begin = -1;
53818d228c0SPierre Jolivet   }
53918d228c0SPierre Jolivet   if (end) {
5404f572ea9SToby Isaac     PetscAssertPointer(end, 6);
54118d228c0SPierre Jolivet     *end = -1;
54218d228c0SPierre Jolivet   }
543f349c1fdSJed Brown   for (i = 0; i < n; i++) {
544207556f9SJed Brown     if (!list[i]) continue;
5459566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
546f349c1fdSJed Brown     if (flg) {
54718d228c0SPierre Jolivet       if (begin) *begin = i;
54818d228c0SPierre Jolivet       if (end) *end = i + 1;
5493ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
550f349c1fdSJed Brown     }
551f349c1fdSJed Brown   }
5529566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
55318d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
55418d228c0SPierre Jolivet     if (!list[i]) continue;
55518d228c0SPierre Jolivet     m = 0;
5569566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5579566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
55818d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
55918d228c0SPierre Jolivet       if (list[j]) {
56018d228c0SPierre Jolivet         concatenate[0] = out;
56118d228c0SPierre Jolivet         concatenate[1] = list[j];
5629566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5639566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5649566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
56518d228c0SPierre Jolivet       }
56618d228c0SPierre Jolivet     }
56718d228c0SPierre Jolivet     if (m == size) {
5689566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
56918d228c0SPierre Jolivet       if (flg) {
57018d228c0SPierre Jolivet         if (begin) *begin = i;
57118d228c0SPierre Jolivet         if (end) *end = j;
5729566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
5733ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
57418d228c0SPierre Jolivet       }
57518d228c0SPierre Jolivet     }
5769566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
57718d228c0SPierre Jolivet   }
5783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
579f349c1fdSJed Brown }
580f349c1fdSJed Brown 
581d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
582d71ae5a4SJacob Faibussowitsch {
5838188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
58418d228c0SPierre Jolivet   PetscInt  lr, lc;
58518d228c0SPierre Jolivet 
58618d228c0SPierre Jolivet   PetscFunctionBegin;
5879566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5889566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5899566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
5909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
5919566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
5929566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
5939566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
5949566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
5959566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
5969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
5979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
5983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59918d228c0SPierre Jolivet }
60018d228c0SPierre Jolivet 
601d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
602d71ae5a4SJacob Faibussowitsch {
60318d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
60418d228c0SPierre Jolivet   Mat       *a;
60518d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6068188e55aSJed Brown   char       keyname[256];
60718d228c0SPierre Jolivet   PetscBool *b;
60818d228c0SPierre Jolivet   PetscBool  flg;
6098188e55aSJed Brown 
6108188e55aSJed Brown   PetscFunctionBegin;
6110298fd71SBarry Smith   *B = NULL;
6129566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6139566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6143ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6158188e55aSJed Brown 
6169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
61718d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
61818d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
61918d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
62018d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
62118d228c0SPierre Jolivet     }
62218d228c0SPierre Jolivet   }
62318d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
62418d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
62518d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
62618d228c0SPierre Jolivet         flg = PETSC_FALSE;
62718d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
62818d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
62918d228c0SPierre Jolivet         }
63018d228c0SPierre Jolivet         if (flg) {
63118d228c0SPierre Jolivet           flg = PETSC_FALSE;
63218d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
63318d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
63418d228c0SPierre Jolivet           }
63518d228c0SPierre Jolivet         }
63618d228c0SPierre Jolivet         if (!flg) {
63718d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6389566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
63918d228c0SPierre Jolivet         }
64018d228c0SPierre Jolivet       }
64118d228c0SPierre Jolivet     }
64218d228c0SPierre Jolivet   }
6439566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
64418d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
64518d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
64648a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
64718d228c0SPierre Jolivet     }
64818d228c0SPierre Jolivet   }
6499566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6508188e55aSJed Brown   (*B)->assembled = A->assembled;
6519566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6529566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6548188e55aSJed Brown }
6558188e55aSJed Brown 
656d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
657d71ae5a4SJacob Faibussowitsch {
658f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
65918d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
660f349c1fdSJed Brown 
661f349c1fdSJed Brown   PetscFunctionBegin;
6629566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6639566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
66418d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
66548a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
66618d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
66718d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6689566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
66918d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
6703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
671f349c1fdSJed Brown }
672f349c1fdSJed Brown 
67306a1af2fSStefano Zampini /*
67406a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
67506a1af2fSStefano Zampini */
676d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
677d71ae5a4SJacob Faibussowitsch {
678f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
679f349c1fdSJed Brown   Mat       sub;
680f349c1fdSJed Brown 
681f349c1fdSJed Brown   PetscFunctionBegin;
6829566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
683f349c1fdSJed Brown   switch (reuse) {
684f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6859566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
686f349c1fdSJed Brown     *B = sub;
687f349c1fdSJed Brown     break;
688d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
689d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
690d71ae5a4SJacob Faibussowitsch     break;
691d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
692d71ae5a4SJacob Faibussowitsch     break;
693d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
694d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
695f349c1fdSJed Brown   }
6963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
697f349c1fdSJed Brown }
698f349c1fdSJed Brown 
69966976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
700d71ae5a4SJacob Faibussowitsch {
701f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
702f349c1fdSJed Brown   Mat       sub;
703f349c1fdSJed Brown 
704f349c1fdSJed Brown   PetscFunctionBegin;
7059566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
706f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7079566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
708f349c1fdSJed Brown   *B = sub;
7093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
710d8588912SDave May }
711d8588912SDave May 
712d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
713d71ae5a4SJacob Faibussowitsch {
714f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
715f349c1fdSJed Brown   Mat       sub;
716d8588912SDave May 
717d8588912SDave May   PetscFunctionBegin;
7189566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
71908401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
720f349c1fdSJed Brown   if (sub) {
721aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7229566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
723d8588912SDave May   }
7243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
725d8588912SDave May }
726d8588912SDave May 
727d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
728d71ae5a4SJacob Faibussowitsch {
7297874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7307874fa86SDave May   PetscInt  i;
7317874fa86SDave May 
7327874fa86SDave May   PetscFunctionBegin;
7337874fa86SDave May   for (i = 0; i < bA->nr; i++) {
734429bac76SJed Brown     Vec bv;
7359566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7367874fa86SDave May     if (bA->m[i][i]) {
7379566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7387874fa86SDave May     } else {
7399566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7407874fa86SDave May     }
7419566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7427874fa86SDave May   }
7433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7447874fa86SDave May }
7457874fa86SDave May 
746d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
747d71ae5a4SJacob Faibussowitsch {
7487874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
749429bac76SJed Brown   Vec       bl, *br;
7507874fa86SDave May   PetscInt  i, j;
7517874fa86SDave May 
7527874fa86SDave May   PetscFunctionBegin;
7539566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7542e6472ebSElliott Sales de Andrade   if (r) {
7559566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7562e6472ebSElliott Sales de Andrade   }
7572e6472ebSElliott Sales de Andrade   bl = NULL;
7587874fa86SDave May   for (i = 0; i < bA->nr; i++) {
75948a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7607874fa86SDave May     for (j = 0; j < bA->nc; j++) {
76148a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7627874fa86SDave May     }
76348a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7642e6472ebSElliott Sales de Andrade   }
7652e6472ebSElliott Sales de Andrade   if (r) {
7669566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7672e6472ebSElliott Sales de Andrade   }
7689566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7707874fa86SDave May }
7717874fa86SDave May 
772d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
773d71ae5a4SJacob Faibussowitsch {
774a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
775a061e289SJed Brown   PetscInt  i, j;
776a061e289SJed Brown 
777a061e289SJed Brown   PetscFunctionBegin;
778a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
779a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
78048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
781a061e289SJed Brown     }
782a061e289SJed Brown   }
7833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
784a061e289SJed Brown }
785a061e289SJed Brown 
786d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
787d71ae5a4SJacob Faibussowitsch {
788a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
789a061e289SJed Brown   PetscInt  i;
79006a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
791a061e289SJed Brown 
792a061e289SJed Brown   PetscFunctionBegin;
793a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
79406a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
79508401ef6SPierre 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);
7969566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
7979566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
79806a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
79906a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
800a061e289SJed Brown   }
80106a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
803a061e289SJed Brown }
804a061e289SJed Brown 
805d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
806d71ae5a4SJacob Faibussowitsch {
80713135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
80813135bc6SAlex Fikl   PetscInt  i;
80906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
81013135bc6SAlex Fikl 
81113135bc6SAlex Fikl   PetscFunctionBegin;
81213135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
81306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
81413135bc6SAlex Fikl     Vec              bv;
8159566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
81613135bc6SAlex Fikl     if (bA->m[i][i]) {
8179566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8189566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
81913135bc6SAlex Fikl     }
8209566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
82106a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
82206a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
82313135bc6SAlex Fikl   }
82406a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
82613135bc6SAlex Fikl }
82713135bc6SAlex Fikl 
828d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
829d71ae5a4SJacob Faibussowitsch {
830f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
831f8170845SAlex Fikl   PetscInt  i, j;
832f8170845SAlex Fikl 
833f8170845SAlex Fikl   PetscFunctionBegin;
834f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
835f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
83648a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
837f8170845SAlex Fikl     }
838f8170845SAlex Fikl   }
8393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
840f8170845SAlex Fikl }
841f8170845SAlex Fikl 
842d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
843d71ae5a4SJacob Faibussowitsch {
844d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
845d8588912SDave May   Vec      *L, *R;
846d8588912SDave May   MPI_Comm  comm;
847d8588912SDave May   PetscInt  i, j;
848d8588912SDave May 
849d8588912SDave May   PetscFunctionBegin;
8509566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
851d8588912SDave May   if (right) {
852d8588912SDave May     /* allocate R */
8539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
854d8588912SDave May     /* Create the right vectors */
855d8588912SDave May     for (j = 0; j < bA->nc; j++) {
856d8588912SDave May       for (i = 0; i < bA->nr; i++) {
857d8588912SDave May         if (bA->m[i][j]) {
8589566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
859d8588912SDave May           break;
860d8588912SDave May         }
861d8588912SDave May       }
86208401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
863d8588912SDave May     }
8649566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
865d8588912SDave May     /* hand back control to the nest vector */
86648a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8679566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
868d8588912SDave May   }
869d8588912SDave May 
870d8588912SDave May   if (left) {
871d8588912SDave May     /* allocate L */
8729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
873d8588912SDave May     /* Create the left vectors */
874d8588912SDave May     for (i = 0; i < bA->nr; i++) {
875d8588912SDave May       for (j = 0; j < bA->nc; j++) {
876d8588912SDave May         if (bA->m[i][j]) {
8779566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
878d8588912SDave May           break;
879d8588912SDave May         }
880d8588912SDave May       }
88108401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
882d8588912SDave May     }
883d8588912SDave May 
8849566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
88548a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
886d8588912SDave May 
8879566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
888d8588912SDave May   }
8893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
890d8588912SDave May }
891d8588912SDave May 
892d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
893d71ae5a4SJacob Faibussowitsch {
894d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
89529e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
896d8588912SDave May   PetscInt  i, j;
897d8588912SDave May 
898d8588912SDave May   PetscFunctionBegin;
8999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
900d8588912SDave May   if (isascii) {
9019566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9029566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
9039566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9049566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
905d8588912SDave May 
9069566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
907d8588912SDave May     for (i = 0; i < bA->nr; i++) {
908d8588912SDave May       for (j = 0; j < bA->nc; j++) {
90919fd82e9SBarry Smith         MatType   type;
910270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
911d8588912SDave May         PetscInt  NR, NC;
912d8588912SDave May         PetscBool isNest = PETSC_FALSE;
913d8588912SDave May 
914d8588912SDave May         if (!bA->m[i][j]) {
9159566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
916d8588912SDave May           continue;
917d8588912SDave May         }
9189566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9199566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9209566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9219566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9229566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
923d8588912SDave May 
9249566063dSJacob 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));
925d8588912SDave May 
92629e60adbSStefano Zampini         if (isNest || viewSub) {
9279566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9289566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9299566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
930d8588912SDave May         }
931d8588912SDave May       }
932d8588912SDave May     }
9339566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
934d8588912SDave May   }
9353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
936d8588912SDave May }
937d8588912SDave May 
938d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
939d71ae5a4SJacob Faibussowitsch {
940d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
941d8588912SDave May   PetscInt  i, j;
942d8588912SDave May 
943d8588912SDave May   PetscFunctionBegin;
944d8588912SDave May   for (i = 0; i < bA->nr; i++) {
945d8588912SDave May     for (j = 0; j < bA->nc; j++) {
946d8588912SDave May       if (!bA->m[i][j]) continue;
9479566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
948d8588912SDave May     }
949d8588912SDave May   }
9503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
951d8588912SDave May }
952d8588912SDave May 
953d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
954d71ae5a4SJacob Faibussowitsch {
955c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
956c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
95706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
958c222c20dSDavid Ham 
959c222c20dSDavid Ham   PetscFunctionBegin;
960aed4548fSBarry 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);
961c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
962c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
96306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
96446a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9659566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
96608401ef6SPierre 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);
9679566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
96806a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
96906a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
970c222c20dSDavid Ham     }
971c222c20dSDavid Ham   }
97206a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
9733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
974c222c20dSDavid Ham }
975c222c20dSDavid Ham 
976d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
977d71ae5a4SJacob Faibussowitsch {
9786e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
9796e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
98006a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
9816e76ffeaSPierre Jolivet 
9826e76ffeaSPierre Jolivet   PetscFunctionBegin;
983aed4548fSBarry 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);
9846e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
9856e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
98606a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9876e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9889566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
989c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
990c066aebcSStefano Zampini         Mat M;
991c066aebcSStefano Zampini 
992e75569e9SPierre 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);
9939566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
9949566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
9959566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
996c066aebcSStefano Zampini       }
9979566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
99806a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
99906a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10006e76ffeaSPierre Jolivet     }
10016e76ffeaSPierre Jolivet   }
100206a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10046e76ffeaSPierre Jolivet }
10056e76ffeaSPierre Jolivet 
1006d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1007d71ae5a4SJacob Faibussowitsch {
1008d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1009841e96a3SJed Brown   Mat      *b;
1010841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1011d8588912SDave May 
1012d8588912SDave May   PetscFunctionBegin;
10139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1014841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1015841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1016841e96a3SJed Brown       if (bA->m[i][j]) {
10179566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1018841e96a3SJed Brown       } else {
10190298fd71SBarry Smith         b[i * nc + j] = NULL;
1020d8588912SDave May       }
1021d8588912SDave May     }
1022d8588912SDave May   }
10239566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1024841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
102548a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10269566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1027d8588912SDave May 
10289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1031d8588912SDave May }
1032d8588912SDave May 
1033d8588912SDave May /* nest api */
103466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1035d71ae5a4SJacob Faibussowitsch {
1036d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10375fd66863SKarl Rupp 
1038d8588912SDave May   PetscFunctionBegin;
103908401ef6SPierre 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);
104008401ef6SPierre 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);
1041d8588912SDave May   *mat = bA->m[idxm][jdxm];
10423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043d8588912SDave May }
1044d8588912SDave May 
10459ba0d327SJed Brown /*@
104611a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1047d8588912SDave May 
10482ef1f0ffSBarry Smith   Not Collective
1049d8588912SDave May 
1050d8588912SDave May   Input Parameters:
105111a5261eSBarry Smith + A    - `MATNEST` matrix
1052d8588912SDave May . idxm - index of the matrix within the nest matrix
1053629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1054d8588912SDave May 
1055d8588912SDave May   Output Parameter:
10562ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1057d8588912SDave May 
1058d8588912SDave May   Level: developer
1059d8588912SDave May 
1060fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1061db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1062d8588912SDave May @*/
1063d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1064d71ae5a4SJacob Faibussowitsch {
1065d8588912SDave May   PetscFunctionBegin;
1066cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
10673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1068d8588912SDave May }
1069d8588912SDave May 
107066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1071d71ae5a4SJacob Faibussowitsch {
10720782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
10730782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
10740782ca92SJed Brown 
10750782ca92SJed Brown   PetscFunctionBegin;
107608401ef6SPierre Jolivet   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
107708401ef6SPierre Jolivet   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
10789566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
10799566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
10809566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
10819566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
10829566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
10839566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1084aed4548fSBarry 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);
1085aed4548fSBarry 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);
108626fbe8dcSKarl Rupp 
108706a1af2fSStefano Zampini   /* do not increase object state */
10883ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
108906a1af2fSStefano Zampini 
10909566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
10919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
10920782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
10939566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
10949566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
109506a1af2fSStefano Zampini   A->nonzerostate++;
10963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10970782ca92SJed Brown }
10980782ca92SJed Brown 
10999ba0d327SJed Brown /*@
110011a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11010782ca92SJed Brown 
11022ef1f0ffSBarry Smith   Logically Collective
11030782ca92SJed Brown 
11040782ca92SJed Brown   Input Parameters:
110511a5261eSBarry Smith + A    - `MATNEST` matrix
11060782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11070782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11082ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11092ef1f0ffSBarry Smith 
11102ef1f0ffSBarry Smith   Level: developer
11110782ca92SJed Brown 
11120782ca92SJed Brown   Notes:
11130782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11140782ca92SJed Brown 
11150782ca92SJed Brown   This increments the reference count of the submatrix.
11160782ca92SJed Brown 
1117fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1118db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11190782ca92SJed Brown @*/
1120d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1121d71ae5a4SJacob Faibussowitsch {
11220782ca92SJed Brown   PetscFunctionBegin;
1123cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11250782ca92SJed Brown }
11260782ca92SJed Brown 
112766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1128d71ae5a4SJacob Faibussowitsch {
1129d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11305fd66863SKarl Rupp 
1131d8588912SDave May   PetscFunctionBegin;
113226fbe8dcSKarl Rupp   if (M) *M = bA->nr;
113326fbe8dcSKarl Rupp   if (N) *N = bA->nc;
113426fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1136d8588912SDave May }
1137d8588912SDave May 
1138d8588912SDave May /*@C
113911a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1140d8588912SDave May 
11412ef1f0ffSBarry Smith   Not Collective
1142d8588912SDave May 
1143f899ff85SJose E. Roman   Input Parameter:
1144629881c0SJed Brown . A - nest matrix
1145d8588912SDave May 
1146d8d19677SJose E. Roman   Output Parameters:
1147629881c0SJed Brown + M   - number of rows in the nest matrix
1148d8588912SDave May . N   - number of cols in the nest matrix
1149e9d3347aSJose E. Roman - mat - array of matrices
1150d8588912SDave May 
11512ef1f0ffSBarry Smith   Level: developer
11522ef1f0ffSBarry Smith 
115311a5261eSBarry Smith   Note:
11542ef1f0ffSBarry Smith   The user should not free the array `mat`.
1155d8588912SDave May 
1156fe59aa6dSJacob Faibussowitsch   Fortran Notes:
115711a5261eSBarry Smith   This routine has a calling sequence
1158351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
115920f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1160e9d3347aSJose E. Roman   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1161351962e3SVincent Le Chenadec 
1162fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1163db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1164d8588912SDave May @*/
1165d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1166d71ae5a4SJacob Faibussowitsch {
1167d8588912SDave May   PetscFunctionBegin;
1168cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
11693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1170d8588912SDave May }
1171d8588912SDave May 
117266976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1173d71ae5a4SJacob Faibussowitsch {
1174d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1175d8588912SDave May 
1176d8588912SDave May   PetscFunctionBegin;
117726fbe8dcSKarl Rupp   if (M) *M = bA->nr;
117826fbe8dcSKarl Rupp   if (N) *N = bA->nc;
11793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1180d8588912SDave May }
1181d8588912SDave May 
11829ba0d327SJed Brown /*@
118311a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1184d8588912SDave May 
11852ef1f0ffSBarry Smith   Not Collective
1186d8588912SDave May 
1187f899ff85SJose E. Roman   Input Parameter:
118811a5261eSBarry Smith . A - `MATNEST` matrix
1189d8588912SDave May 
1190d8d19677SJose E. Roman   Output Parameters:
1191629881c0SJed Brown + M - number of rows in the nested mat
1192629881c0SJed Brown - N - number of cols in the nested mat
1193d8588912SDave May 
1194d8588912SDave May   Level: developer
1195d8588912SDave May 
1196fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1197db781477SPatrick Sanan           `MatNestGetISs()`
1198d8588912SDave May @*/
1199d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1200d71ae5a4SJacob Faibussowitsch {
1201d8588912SDave May   PetscFunctionBegin;
1202cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1204d8588912SDave May }
1205d8588912SDave May 
1206d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1207d71ae5a4SJacob Faibussowitsch {
1208900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1209900e7ff2SJed Brown   PetscInt  i;
1210900e7ff2SJed Brown 
1211900e7ff2SJed Brown   PetscFunctionBegin;
12129371c9d4SSatish Balay   if (rows)
12139371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12149371c9d4SSatish Balay   if (cols)
12159371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1217900e7ff2SJed Brown }
1218900e7ff2SJed Brown 
12193a4d7b9aSSatish Balay /*@C
122011a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1221900e7ff2SJed Brown 
12222ef1f0ffSBarry Smith   Not Collective
1223900e7ff2SJed Brown 
1224f899ff85SJose E. Roman   Input Parameter:
122511a5261eSBarry Smith . A - `MATNEST` matrix
1226900e7ff2SJed Brown 
1227d8d19677SJose E. Roman   Output Parameters:
1228900e7ff2SJed Brown + rows - array of row index sets
1229900e7ff2SJed Brown - cols - array of column index sets
1230900e7ff2SJed Brown 
1231900e7ff2SJed Brown   Level: advanced
1232900e7ff2SJed Brown 
123311a5261eSBarry Smith   Note:
12342ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1235900e7ff2SJed Brown 
1236fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1237fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1238900e7ff2SJed Brown @*/
1239d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1240d71ae5a4SJacob Faibussowitsch {
1241900e7ff2SJed Brown   PetscFunctionBegin;
1242900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1243cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1245900e7ff2SJed Brown }
1246900e7ff2SJed Brown 
1247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1248d71ae5a4SJacob Faibussowitsch {
1249900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1250900e7ff2SJed Brown   PetscInt  i;
1251900e7ff2SJed Brown 
1252900e7ff2SJed Brown   PetscFunctionBegin;
12539371c9d4SSatish Balay   if (rows)
12549371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12559371c9d4SSatish Balay   if (cols)
12569371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
12573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1258900e7ff2SJed Brown }
1259900e7ff2SJed Brown 
1260900e7ff2SJed Brown /*@C
126111a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1262900e7ff2SJed Brown 
12632ef1f0ffSBarry Smith   Not Collective
1264900e7ff2SJed Brown 
1265f899ff85SJose E. Roman   Input Parameter:
126611a5261eSBarry Smith . A - `MATNEST` matrix
1267900e7ff2SJed Brown 
1268d8d19677SJose E. Roman   Output Parameters:
12692ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore)
12702ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore)
1271900e7ff2SJed Brown 
1272900e7ff2SJed Brown   Level: advanced
1273900e7ff2SJed Brown 
127411a5261eSBarry Smith   Note:
12752ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1276900e7ff2SJed Brown 
12771cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1278fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1279900e7ff2SJed Brown @*/
1280d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1281d71ae5a4SJacob Faibussowitsch {
1282900e7ff2SJed Brown   PetscFunctionBegin;
1283900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1284cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1286900e7ff2SJed Brown }
1287900e7ff2SJed Brown 
128866976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1289d71ae5a4SJacob Faibussowitsch {
1290207556f9SJed Brown   PetscBool flg;
1291207556f9SJed Brown 
1292207556f9SJed Brown   PetscFunctionBegin;
12939566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1294207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
12952a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
129612b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
12973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1298207556f9SJed Brown }
1299207556f9SJed Brown 
1300207556f9SJed Brown /*@C
130111a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1302207556f9SJed Brown 
13032ef1f0ffSBarry Smith   Not Collective
1304207556f9SJed Brown 
1305207556f9SJed Brown   Input Parameters:
130611a5261eSBarry Smith + A     - `MATNEST` matrix
130711a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1308207556f9SJed Brown 
1309207556f9SJed Brown   Level: developer
1310207556f9SJed Brown 
1311fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1312207556f9SJed Brown @*/
1313d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1314d71ae5a4SJacob Faibussowitsch {
1315207556f9SJed Brown   PetscFunctionBegin;
1316cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1318207556f9SJed Brown }
1319207556f9SJed Brown 
132066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1321d71ae5a4SJacob Faibussowitsch {
1322c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1323c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
132488ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
132588ffe2e8SJose E. Roman   VecType   vtype, type;
1326d8588912SDave May 
1327d8588912SDave May   PetscFunctionBegin;
13289566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
132906a1af2fSStefano Zampini 
1330c8883902SJed Brown   s->nr = nr;
1331c8883902SJed Brown   s->nc = nc;
1332d8588912SDave May 
1333c8883902SJed Brown   /* Create space for submatrices */
13349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
133548a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i]));
1336c8883902SJed Brown   for (i = 0; i < nr; i++) {
1337c8883902SJed Brown     for (j = 0; j < nc; j++) {
1338c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
133948a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1340d8588912SDave May     }
1341d8588912SDave May   }
13429566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13439566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
134488ffe2e8SJose E. Roman   if (isstd) {
134588ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
134688ffe2e8SJose E. Roman     vtype = NULL;
134788ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
134888ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
134988ffe2e8SJose E. Roman         if (a[i * nc + j]) {
135088ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13519566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
135288ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
135388ffe2e8SJose E. Roman           } else if (sametype) {
13549566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13559566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
135688ffe2e8SJose E. Roman           }
135788ffe2e8SJose E. Roman         }
135888ffe2e8SJose E. Roman       }
135988ffe2e8SJose E. Roman     }
136088ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13619566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
136288ffe2e8SJose E. Roman     }
136388ffe2e8SJose E. Roman   }
1364d8588912SDave May 
13659566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1366d8588912SDave May 
13679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
13689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1369c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1370c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1371d8588912SDave May 
13729566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
137306a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
137406a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
137548a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
137606a1af2fSStefano Zampini     }
137706a1af2fSStefano Zampini   }
137806a1af2fSStefano Zampini 
13799566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1380d8588912SDave May 
13819566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
13829566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
13839566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
13849566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1385c8883902SJed Brown 
13869566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
13879566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1388c8883902SJed Brown 
138906a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
139006a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
13919566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
139206a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
139306a1af2fSStefano Zampini   if (cong) {
139448a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
139506a1af2fSStefano Zampini   }
139606a1af2fSStefano Zampini   if (!cong) {
1397381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
139806a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
139906a1af2fSStefano Zampini     A->ops->shift           = NULL;
140006a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
140106a1af2fSStefano Zampini   }
140206a1af2fSStefano Zampini 
14039566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14049566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
140506a1af2fSStefano Zampini   A->nonzerostate++;
14063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1407d8588912SDave May }
1408d8588912SDave May 
1409c8883902SJed Brown /*@
141011a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1411c8883902SJed Brown 
1412c3339decSBarry Smith   Collective
1413c8883902SJed Brown 
1414d8d19677SJose E. Roman   Input Parameters:
141511a5261eSBarry Smith + A      - `MATNEST` matrix
1416c8883902SJed Brown . nr     - number of nested row blocks
14172ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1418c8883902SJed Brown . nc     - number of nested column blocks
14192ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1420e9d3347aSJose E. Roman - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
14212ef1f0ffSBarry Smith 
14222ef1f0ffSBarry Smith   Level: advanced
1423c8883902SJed Brown 
1424e9d3347aSJose E. Roman   Notes:
142511a5261eSBarry Smith   This always resets any submatrix information previously set
142606a1af2fSStefano Zampini 
1427e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array containing the matrices. See
1428e9d3347aSJose E. Roman   `MatCreateNest()` for an example.
1429e9d3347aSJose E. Roman 
14301cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1431c8883902SJed Brown @*/
1432d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1433d71ae5a4SJacob Faibussowitsch {
143406a1af2fSStefano Zampini   PetscInt i;
1435c8883902SJed Brown 
1436c8883902SJed Brown   PetscFunctionBegin;
1437c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
143808401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1439c8883902SJed Brown   if (nr && is_row) {
14404f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
1441c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1442c8883902SJed Brown   }
144308401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14441664e352SJed Brown   if (nc && is_col) {
14454f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
14469b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1447c8883902SJed Brown   }
14484f572ea9SToby Isaac   if (nr * nc > 0) PetscAssertPointer(a, 6);
1449cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1451c8883902SJed Brown }
1452d8588912SDave May 
1453d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1454d71ae5a4SJacob Faibussowitsch {
145577019fcaSJed Brown   PetscBool flg;
145677019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
145777019fcaSJed Brown 
145877019fcaSJed Brown   PetscFunctionBegin;
1459aea6d515SStefano Zampini   *ltog = NULL;
146077019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
146177019fcaSJed Brown     if (islocal[i]) {
14629566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
146377019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
146477019fcaSJed Brown     } else {
14659566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
146677019fcaSJed Brown     }
146777019fcaSJed Brown     m += mi;
146877019fcaSJed Brown   }
14693ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1470aea6d515SStefano Zampini 
14719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1472165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
14730298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1474e108cb99SStefano Zampini     Mat                    sub  = NULL;
1475f6d38dbbSStefano Zampini     PetscSF                sf;
1476f6d38dbbSStefano Zampini     PetscLayout            map;
1477aea6d515SStefano Zampini     const PetscInt        *ix2;
147877019fcaSJed Brown 
1479165cd838SBarry Smith     if (!colflg) {
14809566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
148177019fcaSJed Brown     } else {
14829566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
148377019fcaSJed Brown     }
1484191fd14bSBarry Smith     if (sub) {
1485191fd14bSBarry Smith       if (!colflg) {
14869566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1487191fd14bSBarry Smith       } else {
14889566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1489191fd14bSBarry Smith       }
1490191fd14bSBarry Smith     }
149177019fcaSJed Brown     /*
149277019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
149377019fcaSJed 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.
149477019fcaSJed Brown     */
14959566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1496aea6d515SStefano Zampini     if (islocal[i]) {
1497aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1498aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1499aea6d515SStefano Zampini 
15009566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150128b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1502aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15039566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1504aea6d515SStefano Zampini 
1505aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1507aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1508aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1509aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1510aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1511aea6d515SStefano Zampini         nleaves++;
1512aea6d515SStefano Zampini       }
15139566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15149566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15159566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15169566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15179566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15189566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15199566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15209566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15219566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15229566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15239566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1524aea6d515SStefano Zampini     } else {
15259566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1526aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1527aea6d515SStefano Zampini     }
15289566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
152977019fcaSJed Brown     m += mi;
153077019fcaSJed Brown   }
15319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153377019fcaSJed Brown }
153477019fcaSJed Brown 
1535d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1536d8588912SDave May /*
1537d8588912SDave May   nprocessors = NP
1538d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1539d8588912SDave May        proc 0: => (g_0,h_0,)
1540d8588912SDave May        proc 1: => (g_1,h_1,)
1541d8588912SDave May        ...
1542d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1543d8588912SDave May 
1544d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1545d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1546d8588912SDave May 
1547d8588912SDave May             proc 0:
1548d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1549d8588912SDave May             proc 1:
1550d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1551d8588912SDave May 
1552d8588912SDave May             proc NP-1:
1553d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1554d8588912SDave May */
1555d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1556d71ae5a4SJacob Faibussowitsch {
1557e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15588188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15590298fd71SBarry Smith   Mat       sub = NULL;
1560d8588912SDave May 
1561d8588912SDave May   PetscFunctionBegin;
15629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
15639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1564d8588912SDave May   if (is_row) { /* valid IS is passed in */
1565a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1566e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15679566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
156826fbe8dcSKarl Rupp 
1569e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1570d8588912SDave May     }
15712ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
15728188e55aSJed Brown     nsum = 0;
15738188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
15749566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
157528b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
15769566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
157708401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15788188e55aSJed Brown       nsum += n;
15798188e55aSJed Brown     }
15809566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
158130bc264bSJed Brown     offset -= nsum;
1582e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15839566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15849566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
15859566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15869566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
15879566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
15882ae74bdbSJed Brown       offset += n;
1589d8588912SDave May     }
1590d8588912SDave May   }
1591d8588912SDave May 
1592d8588912SDave May   if (is_col) { /* valid IS is passed in */
1593a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1594e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
15959566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
159626fbe8dcSKarl Rupp 
1597e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1598d8588912SDave May     }
15992ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16002ae74bdbSJed Brown     offset = A->cmap->rstart;
16018188e55aSJed Brown     nsum   = 0;
16028188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16039566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
160428b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16059566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
160608401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16078188e55aSJed Brown       nsum += n;
16088188e55aSJed Brown     }
16099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
161030bc264bSJed Brown     offset -= nsum;
1611e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16129566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16139566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16149566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16159566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16169566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16172ae74bdbSJed Brown       offset += n;
1618d8588912SDave May     }
1619d8588912SDave May   }
1620e2d7f03fSJed Brown 
1621e2d7f03fSJed Brown   /* Set up the local ISs */
16229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1624e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1625e2d7f03fSJed Brown     IS                     isloc;
16260298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1627e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16289566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16299566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1630207556f9SJed Brown     if (rmap) {
16319566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16339566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16349566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1635207556f9SJed Brown     } else {
1636207556f9SJed Brown       nlocal = 0;
16370298fd71SBarry Smith       isloc  = NULL;
1638207556f9SJed Brown     }
1639e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1640e2d7f03fSJed Brown     offset += nlocal;
1641e2d7f03fSJed Brown   }
16428188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1643e2d7f03fSJed Brown     IS                     isloc;
16440298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1645e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16469566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16479566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1648207556f9SJed Brown     if (cmap) {
16499566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16519566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16529566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1653207556f9SJed Brown     } else {
1654207556f9SJed Brown       nlocal = 0;
16550298fd71SBarry Smith       isloc  = NULL;
1656207556f9SJed Brown     }
1657e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1658e2d7f03fSJed Brown     offset += nlocal;
1659e2d7f03fSJed Brown   }
16600189643fSJed Brown 
166177019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
166277019fcaSJed Brown   {
166345b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
16649566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
16659566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
16669566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
16679566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
16689566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
166977019fcaSJed Brown   }
167077019fcaSJed Brown 
167176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
16720189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
16730189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
16740189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
16750189643fSJed Brown         Mat      B = vs->m[i][j];
16760189643fSJed Brown         if (!B) continue;
16779566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
16789566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
16799566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
16809566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
16819566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
16829566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1683aed4548fSBarry 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);
1684aed4548fSBarry 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);
16850189643fSJed Brown       }
16860189643fSJed Brown     }
168776bd3646SJed Brown   }
1688a061e289SJed Brown 
1689a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1690a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1691a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
16923ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1693a061e289SJed Brown     }
1694a061e289SJed Brown   }
1695a061e289SJed Brown   A->assembled = PETSC_TRUE;
16963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1697d8588912SDave May }
1698d8588912SDave May 
169945c38901SJed Brown /*@C
170011a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1701659c6bb0SJed Brown 
170211a5261eSBarry Smith   Collective
1703659c6bb0SJed Brown 
1704d8d19677SJose E. Roman   Input Parameters:
170511a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1706659c6bb0SJed Brown . nr     - number of nested row blocks
17072ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1708659c6bb0SJed Brown . nc     - number of nested column blocks
17092ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1710e9d3347aSJose E. Roman - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1711659c6bb0SJed Brown 
1712659c6bb0SJed Brown   Output Parameter:
1713659c6bb0SJed Brown . B - new matrix
1714659c6bb0SJed Brown 
1715e9d3347aSJose E. Roman   Note:
1716e9d3347aSJose E. Roman   In both C and Fortran, `a` must be a row-major order array holding references to the matrices.
1717e9d3347aSJose E. Roman   For instance, to represent the matrix
1718e9d3347aSJose E. Roman   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1719e9d3347aSJose E. Roman   one should use `Mat a[4]={A11,A12,A21,A22}`.
1720e9d3347aSJose E. Roman 
1721659c6bb0SJed Brown   Level: advanced
1722659c6bb0SJed Brown 
17231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1724db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1725db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1726659c6bb0SJed Brown @*/
1727d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1728d71ae5a4SJacob Faibussowitsch {
1729d8588912SDave May   Mat A;
1730d8588912SDave May 
1731d8588912SDave May   PetscFunctionBegin;
1732f4259b30SLisandro Dalcin   *B = NULL;
17339566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17349566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
173591a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17369566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1737d8588912SDave May   *B = A;
17383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1739d8588912SDave May }
1740659c6bb0SJed Brown 
174166976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1742d71ae5a4SJacob Faibussowitsch {
1743b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
174423875855Sstefano_zampini   Mat          *trans;
1745b68353e5Sstefano_zampini   PetscScalar **avv;
1746b68353e5Sstefano_zampini   PetscScalar  *vv;
1747b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1748b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1749b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1750b68353e5Sstefano_zampini   PetscBool     done;
1751b68353e5Sstefano_zampini 
1752b68353e5Sstefano_zampini   PetscFunctionBegin;
17539566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1754b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1755b68353e5Sstefano_zampini     PetscInt rnr;
1756b68353e5Sstefano_zampini 
17579566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
175828b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
175908401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
17609566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1761b68353e5Sstefano_zampini   }
1762b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1763b68353e5Sstefano_zampini   nnz = 0;
17649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1765b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1766b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1767b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1768b68353e5Sstefano_zampini       if (B) {
1769b68353e5Sstefano_zampini         PetscScalar *naa;
1770b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
177123875855Sstefano_zampini         PetscBool    istrans;
1772b68353e5Sstefano_zampini 
1773013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
177423875855Sstefano_zampini         if (istrans) {
177523875855Sstefano_zampini           Mat Bt;
177623875855Sstefano_zampini 
17779566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
17789566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
177923875855Sstefano_zampini           B = trans[i * nest->nc + j];
1780013e2dc7SBarry Smith         } else {
1781013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1782013e2dc7SBarry Smith           if (istrans) {
1783013e2dc7SBarry Smith             Mat Bt;
1784013e2dc7SBarry Smith 
1785013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1786013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1787013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1788013e2dc7SBarry Smith           }
178923875855Sstefano_zampini         }
17909566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
179128b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
17929566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1793b68353e5Sstefano_zampini         nnz += nii[nnr];
1794b68353e5Sstefano_zampini 
1795b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1796b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1797b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1798b68353e5Sstefano_zampini       }
1799b68353e5Sstefano_zampini     }
1800b68353e5Sstefano_zampini   }
1801b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1805b68353e5Sstefano_zampini   } else {
180608401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1807b68353e5Sstefano_zampini   }
1808b68353e5Sstefano_zampini 
1809b68353e5Sstefano_zampini   /* new row pointer */
18109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1811b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1812b68353e5Sstefano_zampini     PetscInt ncr, rst;
1813b68353e5Sstefano_zampini 
18149566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18159566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1816b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1817b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1818b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1819b68353e5Sstefano_zampini         PetscInt  ir;
1820b68353e5Sstefano_zampini 
1821b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1822b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1823b68353e5Sstefano_zampini           nii++;
1824b68353e5Sstefano_zampini         }
1825b68353e5Sstefano_zampini       }
1826b68353e5Sstefano_zampini     }
1827b68353e5Sstefano_zampini   }
1828b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1829b68353e5Sstefano_zampini 
1830b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1832b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1833b68353e5Sstefano_zampini     PetscInt ncr, rst;
1834b68353e5Sstefano_zampini 
18359566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18369566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1837b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1838b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1839b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1840b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1841b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1842b68353e5Sstefano_zampini         PetscInt     ir, cst;
1843b68353e5Sstefano_zampini 
18449566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1845b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1846b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1847b68353e5Sstefano_zampini 
1848b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1849b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1850b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1851b68353e5Sstefano_zampini             njj++;
1852b68353e5Sstefano_zampini             nvv++;
1853b68353e5Sstefano_zampini           }
1854b68353e5Sstefano_zampini           ci[ir] += rsize;
1855b68353e5Sstefano_zampini           nii++;
1856b68353e5Sstefano_zampini         }
1857b68353e5Sstefano_zampini       }
1858b68353e5Sstefano_zampini     }
1859b68353e5Sstefano_zampini   }
18609566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1861b68353e5Sstefano_zampini 
1862b68353e5Sstefano_zampini   /* restore info */
1863b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1864b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1865b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1866b68353e5Sstefano_zampini       if (B) {
1867b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
186823875855Sstefano_zampini 
186923875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
18709566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
187128b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
18729566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
18739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1874b68353e5Sstefano_zampini       }
1875b68353e5Sstefano_zampini     }
1876b68353e5Sstefano_zampini   }
18779566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1878b68353e5Sstefano_zampini 
1879b68353e5Sstefano_zampini   /* finalize newmat */
1880b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
18819566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1882b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1883b68353e5Sstefano_zampini     Mat B;
1884b68353e5Sstefano_zampini 
18859566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
18869566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1887b68353e5Sstefano_zampini   }
18889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
18899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1890b68353e5Sstefano_zampini   {
1891b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1892b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1893b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1894b68353e5Sstefano_zampini   }
18953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1896b68353e5Sstefano_zampini }
1897b68353e5Sstefano_zampini 
1898d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1899d71ae5a4SJacob Faibussowitsch {
1900be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1901be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1902be705e3aSPierre Jolivet   PetscBool flg;
1903be705e3aSPierre Jolivet 
1904be705e3aSPierre Jolivet   PetscFunctionBegin;
1905be705e3aSPierre Jolivet   /* Fill by row */
1906be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1907be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1908be705e3aSPierre Jolivet     IS              bNis;
1909be705e3aSPierre Jolivet     PetscInt        bN;
1910be705e3aSPierre Jolivet     const PetscInt *bNindices;
19119566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19129566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1914be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1915fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1916be705e3aSPierre Jolivet       PetscInt        bm, br;
1917be705e3aSPierre Jolivet       const PetscInt *bmindices;
1918be705e3aSPierre Jolivet       if (!B) continue;
1919013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1920be705e3aSPierre Jolivet       if (flg) {
1921cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1922cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19239566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1924be705e3aSPierre Jolivet         B = D;
1925be705e3aSPierre Jolivet       }
19269566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1927be705e3aSPierre Jolivet       if (flg) {
1928fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1929fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1930be705e3aSPierre Jolivet         B = D;
1931be705e3aSPierre Jolivet       }
19329566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19339566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19349566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1935be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1936be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1937be705e3aSPierre Jolivet         const PetscInt    *brcols;
1938be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1939be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19409566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19419566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1942be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1943be705e3aSPierre Jolivet         /*
1944be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1945be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1946be705e3aSPierre Jolivet          */
1947be705e3aSPierre Jolivet         if (a != 1.0) {
19489566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1949be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19509566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19519566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1952be705e3aSPierre Jolivet         } else {
19539566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1954be705e3aSPierre Jolivet         }
19559566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19569566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1957be705e3aSPierre Jolivet       }
1958fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19599566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1960be705e3aSPierre Jolivet     }
19619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
19629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1963be705e3aSPierre Jolivet   }
19649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
19659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
19663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1967be705e3aSPierre Jolivet }
1968be705e3aSPierre Jolivet 
196966976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1970d71ae5a4SJacob Faibussowitsch {
1971629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
1972e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
1973b68353e5Sstefano_zampini   PetscMPIInt size;
1974629c3df2SDmitry Karpeev   Mat         C;
1975629c3df2SDmitry Karpeev 
1976629c3df2SDmitry Karpeev   PetscFunctionBegin;
19779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1978b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1979b68353e5Sstefano_zampini     PetscInt  nf;
1980b68353e5Sstefano_zampini     PetscBool fast;
1981b68353e5Sstefano_zampini 
19829566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
198348a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
1984b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
1985b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
1986b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1987b68353e5Sstefano_zampini         if (B) {
19889566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
198923875855Sstefano_zampini           if (!fast) {
199023875855Sstefano_zampini             PetscBool istrans;
199123875855Sstefano_zampini 
1992013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
199323875855Sstefano_zampini             if (istrans) {
199423875855Sstefano_zampini               Mat Bt;
199523875855Sstefano_zampini 
19969566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
19979566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1998013e2dc7SBarry Smith             } else {
1999013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2000013e2dc7SBarry Smith               if (istrans) {
2001013e2dc7SBarry Smith                 Mat Bt;
2002013e2dc7SBarry Smith 
2003013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2004013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2005013e2dc7SBarry Smith               }
200623875855Sstefano_zampini             }
2007b68353e5Sstefano_zampini           }
2008b68353e5Sstefano_zampini         }
2009b68353e5Sstefano_zampini       }
2010b68353e5Sstefano_zampini     }
2011b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20129566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2013b68353e5Sstefano_zampini       if (fast) {
2014b68353e5Sstefano_zampini         PetscInt f, s;
2015b68353e5Sstefano_zampini 
20169566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20179371c9d4SSatish Balay         if (f != nf || s != 1) {
20189371c9d4SSatish Balay           fast = PETSC_FALSE;
20199371c9d4SSatish Balay         } else {
20209566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2021b68353e5Sstefano_zampini           nf += f;
2022b68353e5Sstefano_zampini         }
2023b68353e5Sstefano_zampini       }
2024b68353e5Sstefano_zampini     }
2025b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20269566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2027b68353e5Sstefano_zampini       if (fast) {
2028b68353e5Sstefano_zampini         PetscInt f, s;
2029b68353e5Sstefano_zampini 
20309566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20319371c9d4SSatish Balay         if (f != nf || s != 1) {
20329371c9d4SSatish Balay           fast = PETSC_FALSE;
20339371c9d4SSatish Balay         } else {
20349566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2035b68353e5Sstefano_zampini           nf += f;
2036b68353e5Sstefano_zampini         }
2037b68353e5Sstefano_zampini       }
2038b68353e5Sstefano_zampini     }
2039b68353e5Sstefano_zampini     if (fast) {
20409566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20413ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2042b68353e5Sstefano_zampini     }
2043b68353e5Sstefano_zampini   }
20449566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20459566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20469566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2047d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2048d1487292SPierre Jolivet   else {
20499566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20509566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2052629c3df2SDmitry Karpeev   }
20539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2054e30678d3SPierre Jolivet   if (m) {
2055629c3df2SDmitry Karpeev     onnz = dnnz + m;
2056629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2057629c3df2SDmitry Karpeev       dnnz[k] = 0;
2058629c3df2SDmitry Karpeev       onnz[k] = 0;
2059629c3df2SDmitry Karpeev     }
2060e30678d3SPierre Jolivet   }
2061629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2062629c3df2SDmitry Karpeev     IS              bNis;
2063629c3df2SDmitry Karpeev     PetscInt        bN;
2064629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2065fd8a7442SPierre Jolivet     PetscBool       flg;
2066629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20679566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20689566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20699566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2070629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2071629c3df2SDmitry Karpeev       PetscSF         bmsf;
2072649b366bSFande Kong       PetscSFNode    *iremote;
2073fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2074649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2075629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2076629c3df2SDmitry Karpeev       if (!B) continue;
20779566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20789566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20799566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
20809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
20819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
20829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2083649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2084649b366bSFande Kong         sub_dnnz[k] = 0;
2085649b366bSFande Kong         sub_onnz[k] = 0;
2086649b366bSFande Kong       }
2087dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2088fd8a7442SPierre Jolivet       if (flg) {
2089fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2090fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2091fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2092fd8a7442SPierre Jolivet         B = D;
2093fd8a7442SPierre Jolivet       }
2094fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2095fd8a7442SPierre Jolivet       if (flg) {
2096fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2097fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2098fd8a7442SPierre Jolivet         B = D;
2099fd8a7442SPierre Jolivet       }
2100629c3df2SDmitry Karpeev       /*
2101629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2102629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2103629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2104629c3df2SDmitry Karpeev        */
21059566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2106629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2107131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2108629c3df2SDmitry Karpeev         const PetscInt *brcols;
2109a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2110131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21119566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2112649b366bSFande Kong         /* how many roots  */
21139371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21149371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2115649b366bSFande Kong         /* get nonzero pattern */
21169566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2117629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2118629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2119649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2120649b366bSFande Kong             sub_dnnz[br]++;
2121649b366bSFande Kong           } else {
2122649b366bSFande Kong             sub_onnz[br]++;
2123649b366bSFande Kong           }
2124629c3df2SDmitry Karpeev         }
21259566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2126629c3df2SDmitry Karpeev       }
2127fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21289566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2129629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21309566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21319566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21329566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21339566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21349566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21359566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21369566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21379566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2138629c3df2SDmitry Karpeev     }
21399566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21409566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
214165a4a0a3Sstefano_zampini   }
214265a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
214365a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
214465a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
214565a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2146629c3df2SDmitry Karpeev   }
21479566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21489566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21499566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21509566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2151d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21529566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2153d1487292SPierre Jolivet   } else *newmat = C;
21543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2155be705e3aSPierre Jolivet }
2156629c3df2SDmitry Karpeev 
215766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2158d71ae5a4SJacob Faibussowitsch {
2159629c3df2SDmitry Karpeev   Mat      B;
2160be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2161be705e3aSPierre Jolivet 
2162be705e3aSPierre Jolivet   PetscFunctionBegin;
21639566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
21649566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2165be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2166be705e3aSPierre Jolivet     B = *newmat;
21679566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2168be705e3aSPierre Jolivet   } else {
21699566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2170629c3df2SDmitry Karpeev   }
21719566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2172be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21739566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2174be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
21753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2176629c3df2SDmitry Karpeev }
2177629c3df2SDmitry Karpeev 
217866976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2179d71ae5a4SJacob Faibussowitsch {
21808b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
21813c6db4c4SPierre Jolivet   MatOperation opAdd;
21828b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
21838b7d3b4bSBarry Smith   PetscBool    flg;
218452c5f739Sprj-   PetscFunctionBegin;
21858b7d3b4bSBarry Smith 
218652c5f739Sprj-   *has = PETSC_FALSE;
21873c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21883c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21898b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
21908b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
21918b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21929566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
21933ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
21948b7d3b4bSBarry Smith       }
21958b7d3b4bSBarry Smith     }
21968b7d3b4bSBarry Smith   }
21973c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
21983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21998b7d3b4bSBarry Smith }
22008b7d3b4bSBarry Smith 
2201659c6bb0SJed Brown /*MC
22022ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2203659c6bb0SJed Brown 
2204659c6bb0SJed Brown   Level: intermediate
2205659c6bb0SJed Brown 
2206659c6bb0SJed Brown   Notes:
220711a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2208659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
220911a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2210659c6bb0SJed Brown 
22118b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22128b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22138b7d3b4bSBarry Smith   than the nest matrix.
22148b7d3b4bSBarry Smith 
22151cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2216db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2217db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2218659c6bb0SJed Brown M*/
2219d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2220d71ae5a4SJacob Faibussowitsch {
2221c8883902SJed Brown   Mat_Nest *s;
2222c8883902SJed Brown 
2223c8883902SJed Brown   PetscFunctionBegin;
22244dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2225c8883902SJed Brown   A->data = (void *)s;
2226e7c19651SJed Brown 
2227e7c19651SJed Brown   s->nr            = -1;
2228e7c19651SJed Brown   s->nc            = -1;
22290298fd71SBarry Smith   s->m             = NULL;
2230e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2231c8883902SJed Brown 
22329566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
223326fbe8dcSKarl Rupp 
2234c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22359194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2236c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22379194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2238f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2239c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2240c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2241c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2242c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22436e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2244c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22457dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2246c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2247c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2248f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2249c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2250c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2251429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2252429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2253a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2254a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
225513135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2256f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22578b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2258381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2259c8883902SJed Brown 
2260f4259b30SLisandro Dalcin   A->spptr     = NULL;
2261c8883902SJed Brown   A->assembled = PETSC_FALSE;
2262c8883902SJed Brown 
2263c8883902SJed Brown   /* expose Nest api's */
22649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
22659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
22669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
22679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
22689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
22709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
22719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
22729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
22749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
22759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
22779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
22789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
22799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2280c8883902SJed Brown 
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
22823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2283c8883902SJed Brown }
2284