xref: /petsc/src/mat/impls/nest/matnest.c (revision 8e3a54c0662fee99ad69f33e814fb6a3f3eef16b)
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));
124*8e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC));
1259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC, ldc));
12652c5f739Sprj-     for (j = 0; j < nc; j++) {
12752c5f739Sprj-       if (!bA->m[i][j]) continue;
1289566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
129*8e3a54c0SPierre Jolivet       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
1309566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB, ldb));
1314222ddf1SHong Zhang 
1324222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1334222ddf1SHong Zhang       workC             = contents->workC[i * nc + j];
1344222ddf1SHong Zhang       productB          = workC->product->B;
1354222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1369566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1384222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1394222ddf1SHong Zhang 
14052c5f739Sprj-       /* C[i] <- workC + C[i] */
1419566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
14252c5f739Sprj-     }
1439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14452c5f739Sprj-   }
1459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C, &carray));
1469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
1474222ddf1SHong Zhang 
14867af85e8SPierre Jolivet   PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15252c5f739Sprj- }
15352c5f739Sprj- 
15466976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx)
155d71ae5a4SJacob Faibussowitsch {
15652c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15752c5f739Sprj-   PetscInt    i;
15852c5f739Sprj- 
15952c5f739Sprj-   PetscFunctionBegin;
1609566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16148a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1629566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1639566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
1643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16552c5f739Sprj- }
16652c5f739Sprj- 
167a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
168d71ae5a4SJacob Faibussowitsch {
1696718818eSStefano Zampini   Mat_Nest          *bA;
1706718818eSStefano Zampini   Mat                viewB, workC;
17152c5f739Sprj-   const PetscScalar *barray;
1726718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1734222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1746718818eSStefano Zampini   PetscBool          cisdense;
1756718818eSStefano Zampini   Mat                A, B;
1766718818eSStefano Zampini   PetscReal          fill;
17752c5f739Sprj- 
17852c5f739Sprj-   PetscFunctionBegin;
1790d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
18028b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1816718818eSStefano Zampini   A    = C->product->A;
1826718818eSStefano Zampini   B    = C->product->B;
1836718818eSStefano Zampini   fill = C->product->fill;
1846718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1856718818eSStefano Zampini   nr   = bA->nr;
1866718818eSStefano Zampini   nc   = bA->nc;
1879566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1889566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1890572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1909566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1919566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1939566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1949566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1950572eedcSPierre Jolivet   }
1969566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19748a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1989566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
1996718818eSStefano Zampini   if (!N) {
2006718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2013ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20252c5f739Sprj-   }
20352c5f739Sprj- 
2049566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2056718818eSStefano Zampini   C->product->data    = contents;
2066718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2079566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20852c5f739Sprj-   contents->k = nr * nc;
20952c5f739Sprj-   for (i = 0; i < nr; i++) {
2109566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
21152c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
21252c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
21352c5f739Sprj-   }
21452c5f739Sprj-   for (i = 0; i < nc; i++) {
2159566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
21652c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21752c5f739Sprj-   }
2189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2199566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2209566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
22252c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22352c5f739Sprj-   for (j = 0; j < nc; j++) {
2249566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
225*8e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
2269566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22752c5f739Sprj-     for (i = 0; i < nr; i++) {
22852c5f739Sprj-       if (!bA->m[i][j]) continue;
22952c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2304222ddf1SHong Zhang 
2319566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2324222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2339566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2349566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2359566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2379566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2384222ddf1SHong Zhang 
2396718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2409566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2419566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
24252c5f739Sprj-     }
2439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24452c5f739Sprj-   }
2459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
24652c5f739Sprj- 
2476718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24952c5f739Sprj- }
25052c5f739Sprj- 
251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
252d71ae5a4SJacob Faibussowitsch {
2534222ddf1SHong Zhang   PetscFunctionBegin;
2546718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2564222ddf1SHong Zhang }
2574222ddf1SHong Zhang 
258a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
259d71ae5a4SJacob Faibussowitsch {
2604222ddf1SHong Zhang   Mat_Product *product = C->product;
26152c5f739Sprj- 
26252c5f739Sprj-   PetscFunctionBegin;
26348a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26552c5f739Sprj- }
26652c5f739Sprj- 
267d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
268d71ae5a4SJacob Faibussowitsch {
269d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
270207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
271207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
272d8588912SDave May 
273d8588912SDave May   PetscFunctionBegin;
2749566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2759566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
276207556f9SJed Brown   for (j = 0; j < nc; j++) {
2779566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
278609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2796c75ac25SJed Brown       if (!bA->m[i][j]) continue;
280609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2819566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));
282d8588912SDave May     }
283d8588912SDave May   }
2849566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2859566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
287d8588912SDave May }
288d8588912SDave May 
289d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
290d71ae5a4SJacob Faibussowitsch {
2919194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2929194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
2939194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
2949194d70fSJed Brown 
2959194d70fSJed Brown   PetscFunctionBegin;
2969566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2979566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
2989194d70fSJed Brown   for (j = 0; j < nc; j++) {
2999194d70fSJed Brown     if (y != z) {
3009194d70fSJed Brown       Vec by;
3019566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3029566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3039566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3049194d70fSJed Brown     }
3059194d70fSJed Brown     for (i = 0; i < nr; i++) {
3066c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3079194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3089566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));
3099194d70fSJed Brown     }
3109194d70fSJed Brown   }
3119566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3129566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3149194d70fSJed Brown }
3159194d70fSJed Brown 
316d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
317d71ae5a4SJacob Faibussowitsch {
318f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
319f8170845SAlex Fikl   Mat       C;
320f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
321f8170845SAlex Fikl 
322f8170845SAlex Fikl   PetscFunctionBegin;
3237fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
324aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
325f8170845SAlex Fikl 
326cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
327f8170845SAlex Fikl     Mat *subs;
328f8170845SAlex Fikl     IS  *is_row, *is_col;
329f8170845SAlex Fikl 
3309566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3329566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
333cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
334ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
335ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
336ddeb9bd8SAlex Fikl       }
337ddeb9bd8SAlex Fikl     }
338ddeb9bd8SAlex Fikl 
3399566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3409566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3419566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
342f8170845SAlex Fikl   } else {
343f8170845SAlex Fikl     C = *B;
344f8170845SAlex Fikl   }
345f8170845SAlex Fikl 
346f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
347f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
348f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
349f8170845SAlex Fikl       if (bA->m[i][j]) {
3509566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
351f8170845SAlex Fikl       } else {
352f8170845SAlex Fikl         bC->m[j][i] = NULL;
353f8170845SAlex Fikl       }
354f8170845SAlex Fikl     }
355f8170845SAlex Fikl   }
356f8170845SAlex Fikl 
357cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
358f8170845SAlex Fikl     *B = C;
359f8170845SAlex Fikl   } else {
3609566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
361f8170845SAlex Fikl   }
3623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
363f8170845SAlex Fikl }
364f8170845SAlex Fikl 
365d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
366d71ae5a4SJacob Faibussowitsch {
367e2d7f03fSJed Brown   IS      *lst = *list;
368e2d7f03fSJed Brown   PetscInt i;
369e2d7f03fSJed Brown 
370e2d7f03fSJed Brown   PetscFunctionBegin;
3713ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
3729371c9d4SSatish Balay   for (i = 0; i < n; i++)
3739371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3749566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3750298fd71SBarry Smith   *list = NULL;
3763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
377e2d7f03fSJed Brown }
378e2d7f03fSJed Brown 
379d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
380d71ae5a4SJacob Faibussowitsch {
381d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
382d8588912SDave May   PetscInt  i, j;
383d8588912SDave May 
384d8588912SDave May   PetscFunctionBegin;
385d8588912SDave May   /* release the matrices and the place holders */
3869566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
3879566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
3889566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
3899566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
390d8588912SDave May 
3919566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
3939566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
394d8588912SDave May 
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
396207556f9SJed Brown 
397d8588912SDave May   /* release the matrices and the place holders */
398d8588912SDave May   if (vs->m) {
399d8588912SDave May     for (i = 0; i < vs->nr; i++) {
40048a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
4019566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
402d8588912SDave May     }
4039566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
404d8588912SDave May   }
40506a1af2fSStefano Zampini 
40606a1af2fSStefano Zampini   /* restore defaults */
40706a1af2fSStefano Zampini   vs->nr            = 0;
40806a1af2fSStefano Zampini   vs->nc            = 0;
40906a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41106a1af2fSStefano Zampini }
41206a1af2fSStefano Zampini 
413d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
414d71ae5a4SJacob Faibussowitsch {
415362febeeSStefano Zampini   PetscFunctionBegin;
4169566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4179566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL));
4353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
436d8588912SDave May }
437d8588912SDave May 
438d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
439d71ae5a4SJacob Faibussowitsch {
440381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
441381b8e50SStefano Zampini   PetscInt  i;
442381b8e50SStefano Zampini 
443381b8e50SStefano Zampini   PetscFunctionBegin;
444381b8e50SStefano Zampini   if (dd) *dd = 0;
445381b8e50SStefano Zampini   if (!vs->nr) {
446381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4473ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
448381b8e50SStefano Zampini   }
449381b8e50SStefano Zampini   *missing = PETSC_FALSE;
450381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
451381b8e50SStefano Zampini     *missing = PETSC_TRUE;
452381b8e50SStefano Zampini     if (vs->m[i][i]) {
4539566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
45408401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
455381b8e50SStefano Zampini     }
456381b8e50SStefano Zampini   }
4573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
458381b8e50SStefano Zampini }
459381b8e50SStefano Zampini 
460d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
461d71ae5a4SJacob Faibussowitsch {
462d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
463d8588912SDave May   PetscInt  i, j;
46406a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
465d8588912SDave May 
466d8588912SDave May   PetscFunctionBegin;
467d8588912SDave May   for (i = 0; i < vs->nr; i++) {
468d8588912SDave May     for (j = 0; j < vs->nc; j++) {
46906a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
470e7c19651SJed Brown       if (vs->m[i][j]) {
4719566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
472e7c19651SJed Brown         if (!vs->splitassembly) {
473e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
474e7c19651SJed 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
475e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
476e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
477e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
478e7c19651SJed Brown            */
4799566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4809566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
481e7c19651SJed Brown         }
482e7c19651SJed Brown       }
48306a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
48406a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
485d8588912SDave May     }
486d8588912SDave May   }
48706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
4883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
489d8588912SDave May }
490d8588912SDave May 
491d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
492d71ae5a4SJacob Faibussowitsch {
493d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
494d8588912SDave May   PetscInt  i, j;
495d8588912SDave May 
496d8588912SDave May   PetscFunctionBegin;
497d8588912SDave May   for (i = 0; i < vs->nr; i++) {
498d8588912SDave May     for (j = 0; j < vs->nc; j++) {
499e7c19651SJed Brown       if (vs->m[i][j]) {
50048a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
501e7c19651SJed Brown       }
502d8588912SDave May     }
503d8588912SDave May   }
5043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
505d8588912SDave May }
506d8588912SDave May 
507d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
508d71ae5a4SJacob Faibussowitsch {
509f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
510f349c1fdSJed Brown   PetscInt  j;
511f349c1fdSJed Brown   Mat       sub;
512d8588912SDave May 
513d8588912SDave May   PetscFunctionBegin;
5140298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
515f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5169566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
517f349c1fdSJed Brown   *B = sub;
5183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
519d8588912SDave May }
520d8588912SDave May 
521d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
522d71ae5a4SJacob Faibussowitsch {
523f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
524f349c1fdSJed Brown   PetscInt  i;
525f349c1fdSJed Brown   Mat       sub;
526f349c1fdSJed Brown 
527f349c1fdSJed Brown   PetscFunctionBegin;
5280298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
529f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5309566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
531f349c1fdSJed Brown   *B = sub;
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
533d8588912SDave May }
534d8588912SDave May 
535d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
536d71ae5a4SJacob Faibussowitsch {
53718d228c0SPierre Jolivet   PetscInt  i, j, size, m;
538f349c1fdSJed Brown   PetscBool flg;
53918d228c0SPierre Jolivet   IS        out, concatenate[2];
540f349c1fdSJed Brown 
541f349c1fdSJed Brown   PetscFunctionBegin;
5424f572ea9SToby Isaac   PetscAssertPointer(list, 3);
543f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
54418d228c0SPierre Jolivet   if (begin) {
5454f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
54618d228c0SPierre Jolivet     *begin = -1;
54718d228c0SPierre Jolivet   }
54818d228c0SPierre Jolivet   if (end) {
5494f572ea9SToby Isaac     PetscAssertPointer(end, 6);
55018d228c0SPierre Jolivet     *end = -1;
55118d228c0SPierre Jolivet   }
552f349c1fdSJed Brown   for (i = 0; i < n; i++) {
553207556f9SJed Brown     if (!list[i]) continue;
5549566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
555f349c1fdSJed Brown     if (flg) {
55618d228c0SPierre Jolivet       if (begin) *begin = i;
55718d228c0SPierre Jolivet       if (end) *end = i + 1;
5583ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
559f349c1fdSJed Brown     }
560f349c1fdSJed Brown   }
5619566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
56218d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
56318d228c0SPierre Jolivet     if (!list[i]) continue;
56418d228c0SPierre Jolivet     m = 0;
5659566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5669566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
56718d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
56818d228c0SPierre Jolivet       if (list[j]) {
56918d228c0SPierre Jolivet         concatenate[0] = out;
57018d228c0SPierre Jolivet         concatenate[1] = list[j];
5719566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5729566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5739566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
57418d228c0SPierre Jolivet       }
57518d228c0SPierre Jolivet     }
57618d228c0SPierre Jolivet     if (m == size) {
5779566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
57818d228c0SPierre Jolivet       if (flg) {
57918d228c0SPierre Jolivet         if (begin) *begin = i;
58018d228c0SPierre Jolivet         if (end) *end = j;
5819566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
5823ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
58318d228c0SPierre Jolivet       }
58418d228c0SPierre Jolivet     }
5859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
58618d228c0SPierre Jolivet   }
5873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
588f349c1fdSJed Brown }
589f349c1fdSJed Brown 
590d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
591d71ae5a4SJacob Faibussowitsch {
5928188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
59318d228c0SPierre Jolivet   PetscInt  lr, lc;
59418d228c0SPierre Jolivet 
59518d228c0SPierre Jolivet   PetscFunctionBegin;
5969566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5989566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
5999566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
6009566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6019566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6029566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6039566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6049566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60818d228c0SPierre Jolivet }
60918d228c0SPierre Jolivet 
610d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
611d71ae5a4SJacob Faibussowitsch {
61218d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
61318d228c0SPierre Jolivet   Mat       *a;
61418d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6158188e55aSJed Brown   char       keyname[256];
61618d228c0SPierre Jolivet   PetscBool *b;
61718d228c0SPierre Jolivet   PetscBool  flg;
6188188e55aSJed Brown 
6198188e55aSJed Brown   PetscFunctionBegin;
6200298fd71SBarry Smith   *B = NULL;
6219566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6229566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6233ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6248188e55aSJed Brown 
6259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
62618d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
62718d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
62818d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
62918d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
63018d228c0SPierre Jolivet     }
63118d228c0SPierre Jolivet   }
63218d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
63318d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
63418d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
63518d228c0SPierre Jolivet         flg = PETSC_FALSE;
63618d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
63718d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
63818d228c0SPierre Jolivet         }
63918d228c0SPierre Jolivet         if (flg) {
64018d228c0SPierre Jolivet           flg = PETSC_FALSE;
64118d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
64218d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
64318d228c0SPierre Jolivet           }
64418d228c0SPierre Jolivet         }
64518d228c0SPierre Jolivet         if (!flg) {
64618d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6479566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
64818d228c0SPierre Jolivet         }
64918d228c0SPierre Jolivet       }
65018d228c0SPierre Jolivet     }
65118d228c0SPierre Jolivet   }
6529566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
65318d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
65418d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
65548a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
65618d228c0SPierre Jolivet     }
65718d228c0SPierre Jolivet   }
6589566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6598188e55aSJed Brown   (*B)->assembled = A->assembled;
6609566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6619566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6638188e55aSJed Brown }
6648188e55aSJed Brown 
665d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
666d71ae5a4SJacob Faibussowitsch {
667f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
66818d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
669f349c1fdSJed Brown 
670f349c1fdSJed Brown   PetscFunctionBegin;
6719566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6729566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
67318d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
67448a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
67518d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
67618d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6779566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
67818d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
6793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
680f349c1fdSJed Brown }
681f349c1fdSJed Brown 
68206a1af2fSStefano Zampini /*
68306a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
68406a1af2fSStefano Zampini */
685d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
686d71ae5a4SJacob Faibussowitsch {
687f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
688f349c1fdSJed Brown   Mat       sub;
689f349c1fdSJed Brown 
690f349c1fdSJed Brown   PetscFunctionBegin;
6919566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
692f349c1fdSJed Brown   switch (reuse) {
693f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6949566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
695f349c1fdSJed Brown     *B = sub;
696f349c1fdSJed Brown     break;
697d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
698d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
699d71ae5a4SJacob Faibussowitsch     break;
700d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
701d71ae5a4SJacob Faibussowitsch     break;
702d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
703d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
704f349c1fdSJed Brown   }
7053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
706f349c1fdSJed Brown }
707f349c1fdSJed Brown 
70866976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
709d71ae5a4SJacob Faibussowitsch {
710f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
711f349c1fdSJed Brown   Mat       sub;
712f349c1fdSJed Brown 
713f349c1fdSJed Brown   PetscFunctionBegin;
7149566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
715f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7169566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
717f349c1fdSJed Brown   *B = sub;
7183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
719d8588912SDave May }
720d8588912SDave May 
721d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
722d71ae5a4SJacob Faibussowitsch {
723f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
724f349c1fdSJed Brown   Mat       sub;
725d8588912SDave May 
726d8588912SDave May   PetscFunctionBegin;
7279566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
72808401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
729f349c1fdSJed Brown   if (sub) {
730aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7319566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
732d8588912SDave May   }
7333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
734d8588912SDave May }
735d8588912SDave May 
736d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
737d71ae5a4SJacob Faibussowitsch {
7387874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7397874fa86SDave May   PetscInt  i;
7407874fa86SDave May 
7417874fa86SDave May   PetscFunctionBegin;
7427874fa86SDave May   for (i = 0; i < bA->nr; i++) {
743429bac76SJed Brown     Vec bv;
7449566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7457874fa86SDave May     if (bA->m[i][i]) {
7469566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7477874fa86SDave May     } else {
7489566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7497874fa86SDave May     }
7509566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7517874fa86SDave May   }
7523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7537874fa86SDave May }
7547874fa86SDave May 
755d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
756d71ae5a4SJacob Faibussowitsch {
7577874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
758429bac76SJed Brown   Vec       bl, *br;
7597874fa86SDave May   PetscInt  i, j;
7607874fa86SDave May 
7617874fa86SDave May   PetscFunctionBegin;
7629566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7632e6472ebSElliott Sales de Andrade   if (r) {
7649566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7652e6472ebSElliott Sales de Andrade   }
7662e6472ebSElliott Sales de Andrade   bl = NULL;
7677874fa86SDave May   for (i = 0; i < bA->nr; i++) {
76848a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7697874fa86SDave May     for (j = 0; j < bA->nc; j++) {
77048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7717874fa86SDave May     }
77248a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7732e6472ebSElliott Sales de Andrade   }
7742e6472ebSElliott Sales de Andrade   if (r) {
7759566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7762e6472ebSElliott Sales de Andrade   }
7779566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7797874fa86SDave May }
7807874fa86SDave May 
781d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
782d71ae5a4SJacob Faibussowitsch {
783a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
784a061e289SJed Brown   PetscInt  i, j;
785a061e289SJed Brown 
786a061e289SJed Brown   PetscFunctionBegin;
787a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
788a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
78948a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
790a061e289SJed Brown     }
791a061e289SJed Brown   }
7923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
793a061e289SJed Brown }
794a061e289SJed Brown 
795d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
796d71ae5a4SJacob Faibussowitsch {
797a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
798a061e289SJed Brown   PetscInt  i;
79906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
800a061e289SJed Brown 
801a061e289SJed Brown   PetscFunctionBegin;
802a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
80306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
80408401ef6SPierre 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);
8059566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8069566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
80706a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
80806a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
809a061e289SJed Brown   }
81006a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
812a061e289SJed Brown }
813a061e289SJed Brown 
814d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
815d71ae5a4SJacob Faibussowitsch {
81613135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
81713135bc6SAlex Fikl   PetscInt  i;
81806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
81913135bc6SAlex Fikl 
82013135bc6SAlex Fikl   PetscFunctionBegin;
82113135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
82206a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82313135bc6SAlex Fikl     Vec              bv;
8249566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
82513135bc6SAlex Fikl     if (bA->m[i][i]) {
8269566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8279566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82813135bc6SAlex Fikl     }
8299566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
83006a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
83106a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
83213135bc6SAlex Fikl   }
83306a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83513135bc6SAlex Fikl }
83613135bc6SAlex Fikl 
837d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
838d71ae5a4SJacob Faibussowitsch {
839f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
840f8170845SAlex Fikl   PetscInt  i, j;
841f8170845SAlex Fikl 
842f8170845SAlex Fikl   PetscFunctionBegin;
843f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
844f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
84548a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
846f8170845SAlex Fikl     }
847f8170845SAlex Fikl   }
8483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
849f8170845SAlex Fikl }
850f8170845SAlex Fikl 
851d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
852d71ae5a4SJacob Faibussowitsch {
853d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
854d8588912SDave May   Vec      *L, *R;
855d8588912SDave May   MPI_Comm  comm;
856d8588912SDave May   PetscInt  i, j;
857d8588912SDave May 
858d8588912SDave May   PetscFunctionBegin;
8599566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
860d8588912SDave May   if (right) {
861d8588912SDave May     /* allocate R */
8629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
863d8588912SDave May     /* Create the right vectors */
864d8588912SDave May     for (j = 0; j < bA->nc; j++) {
865d8588912SDave May       for (i = 0; i < bA->nr; i++) {
866d8588912SDave May         if (bA->m[i][j]) {
8679566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
868d8588912SDave May           break;
869d8588912SDave May         }
870d8588912SDave May       }
87108401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
872d8588912SDave May     }
8739566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
874d8588912SDave May     /* hand back control to the nest vector */
87548a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8769566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
877d8588912SDave May   }
878d8588912SDave May 
879d8588912SDave May   if (left) {
880d8588912SDave May     /* allocate L */
8819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
882d8588912SDave May     /* Create the left vectors */
883d8588912SDave May     for (i = 0; i < bA->nr; i++) {
884d8588912SDave May       for (j = 0; j < bA->nc; j++) {
885d8588912SDave May         if (bA->m[i][j]) {
8869566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
887d8588912SDave May           break;
888d8588912SDave May         }
889d8588912SDave May       }
89008401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
891d8588912SDave May     }
892d8588912SDave May 
8939566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
89448a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
895d8588912SDave May 
8969566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
897d8588912SDave May   }
8983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
899d8588912SDave May }
900d8588912SDave May 
901d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
902d71ae5a4SJacob Faibussowitsch {
903d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
90429e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
905d8588912SDave May   PetscInt  i, j;
906d8588912SDave May 
907d8588912SDave May   PetscFunctionBegin;
9089566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
909d8588912SDave May   if (isascii) {
9109566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9119566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
9129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
914d8588912SDave May 
9159566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
916d8588912SDave May     for (i = 0; i < bA->nr; i++) {
917d8588912SDave May       for (j = 0; j < bA->nc; j++) {
91819fd82e9SBarry Smith         MatType   type;
919270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
920d8588912SDave May         PetscInt  NR, NC;
921d8588912SDave May         PetscBool isNest = PETSC_FALSE;
922d8588912SDave May 
923d8588912SDave May         if (!bA->m[i][j]) {
9249566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
925d8588912SDave May           continue;
926d8588912SDave May         }
9279566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9289566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9299566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9309566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9319566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
932d8588912SDave May 
9339566063dSJacob 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));
934d8588912SDave May 
93529e60adbSStefano Zampini         if (isNest || viewSub) {
9369566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9379566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9389566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
939d8588912SDave May         }
940d8588912SDave May       }
941d8588912SDave May     }
9429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
943d8588912SDave May   }
9443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
945d8588912SDave May }
946d8588912SDave May 
947d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
948d71ae5a4SJacob Faibussowitsch {
949d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
950d8588912SDave May   PetscInt  i, j;
951d8588912SDave May 
952d8588912SDave May   PetscFunctionBegin;
953d8588912SDave May   for (i = 0; i < bA->nr; i++) {
954d8588912SDave May     for (j = 0; j < bA->nc; j++) {
955d8588912SDave May       if (!bA->m[i][j]) continue;
9569566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
957d8588912SDave May     }
958d8588912SDave May   }
9593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
960d8588912SDave May }
961d8588912SDave May 
962d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
963d71ae5a4SJacob Faibussowitsch {
964c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
965c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
96606a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
967c222c20dSDavid Ham 
968c222c20dSDavid Ham   PetscFunctionBegin;
969aed4548fSBarry 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);
970c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
971c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
97206a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
97346a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9749566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
97508401ef6SPierre 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);
9769566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
97706a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
97806a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
979c222c20dSDavid Ham     }
980c222c20dSDavid Ham   }
98106a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
9823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
983c222c20dSDavid Ham }
984c222c20dSDavid Ham 
985d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
986d71ae5a4SJacob Faibussowitsch {
9876e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
9886e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
98906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
9906e76ffeaSPierre Jolivet 
9916e76ffeaSPierre Jolivet   PetscFunctionBegin;
992aed4548fSBarry 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);
9936e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
9946e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
99506a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9966e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9979566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
998c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
999c066aebcSStefano Zampini         Mat M;
1000c066aebcSStefano Zampini 
1001e75569e9SPierre 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);
10029566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10039566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10049566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1005c066aebcSStefano Zampini       }
10069566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
100706a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
100806a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10096e76ffeaSPierre Jolivet     }
10106e76ffeaSPierre Jolivet   }
101106a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10136e76ffeaSPierre Jolivet }
10146e76ffeaSPierre Jolivet 
1015d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1016d71ae5a4SJacob Faibussowitsch {
1017d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1018841e96a3SJed Brown   Mat      *b;
1019841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1020d8588912SDave May 
1021d8588912SDave May   PetscFunctionBegin;
10229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1023841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1024841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1025841e96a3SJed Brown       if (bA->m[i][j]) {
10269566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1027841e96a3SJed Brown       } else {
10280298fd71SBarry Smith         b[i * nc + j] = NULL;
1029d8588912SDave May       }
1030d8588912SDave May     }
1031d8588912SDave May   }
10329566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1033841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
103448a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10359566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1036d8588912SDave May 
10379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1040d8588912SDave May }
1041d8588912SDave May 
1042d8588912SDave May /* nest api */
104366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1044d71ae5a4SJacob Faibussowitsch {
1045d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10465fd66863SKarl Rupp 
1047d8588912SDave May   PetscFunctionBegin;
104808401ef6SPierre 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);
104908401ef6SPierre 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);
1050d8588912SDave May   *mat = bA->m[idxm][jdxm];
10513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1052d8588912SDave May }
1053d8588912SDave May 
10549ba0d327SJed Brown /*@
105511a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1056d8588912SDave May 
10572ef1f0ffSBarry Smith   Not Collective
1058d8588912SDave May 
1059d8588912SDave May   Input Parameters:
106011a5261eSBarry Smith + A    - `MATNEST` matrix
1061d8588912SDave May . idxm - index of the matrix within the nest matrix
1062629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1063d8588912SDave May 
1064d8588912SDave May   Output Parameter:
10652ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1066d8588912SDave May 
1067d8588912SDave May   Level: developer
1068d8588912SDave May 
1069fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1070db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1071d8588912SDave May @*/
1072d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1073d71ae5a4SJacob Faibussowitsch {
1074d8588912SDave May   PetscFunctionBegin;
1075cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
10763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1077d8588912SDave May }
1078d8588912SDave May 
107966976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1080d71ae5a4SJacob Faibussowitsch {
10810782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
10820782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
10830782ca92SJed Brown 
10840782ca92SJed Brown   PetscFunctionBegin;
108508401ef6SPierre 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);
108608401ef6SPierre 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);
10879566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
10889566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
10899566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
10909566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
10919566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
10929566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1093aed4548fSBarry 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);
1094aed4548fSBarry 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);
109526fbe8dcSKarl Rupp 
109606a1af2fSStefano Zampini   /* do not increase object state */
10973ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
109806a1af2fSStefano Zampini 
10999566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11010782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11029566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11039566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
110406a1af2fSStefano Zampini   A->nonzerostate++;
11053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11060782ca92SJed Brown }
11070782ca92SJed Brown 
11089ba0d327SJed Brown /*@
110911a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11100782ca92SJed Brown 
11112ef1f0ffSBarry Smith   Logically Collective
11120782ca92SJed Brown 
11130782ca92SJed Brown   Input Parameters:
111411a5261eSBarry Smith + A    - `MATNEST` matrix
11150782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11160782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11172ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11182ef1f0ffSBarry Smith 
11192ef1f0ffSBarry Smith   Level: developer
11200782ca92SJed Brown 
11210782ca92SJed Brown   Notes:
11220782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11230782ca92SJed Brown 
11240782ca92SJed Brown   This increments the reference count of the submatrix.
11250782ca92SJed Brown 
1126fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1127db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11280782ca92SJed Brown @*/
1129d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1130d71ae5a4SJacob Faibussowitsch {
11310782ca92SJed Brown   PetscFunctionBegin;
1132cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11340782ca92SJed Brown }
11350782ca92SJed Brown 
113666976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1137d71ae5a4SJacob Faibussowitsch {
1138d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11395fd66863SKarl Rupp 
1140d8588912SDave May   PetscFunctionBegin;
114126fbe8dcSKarl Rupp   if (M) *M = bA->nr;
114226fbe8dcSKarl Rupp   if (N) *N = bA->nc;
114326fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1145d8588912SDave May }
1146d8588912SDave May 
1147d8588912SDave May /*@C
114811a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1149d8588912SDave May 
11502ef1f0ffSBarry Smith   Not Collective
1151d8588912SDave May 
1152f899ff85SJose E. Roman   Input Parameter:
1153629881c0SJed Brown . A - nest matrix
1154d8588912SDave May 
1155d8d19677SJose E. Roman   Output Parameters:
1156629881c0SJed Brown + M   - number of rows in the nest matrix
1157d8588912SDave May . N   - number of cols in the nest matrix
1158629881c0SJed Brown - mat - 2d array of matrices
1159d8588912SDave May 
11602ef1f0ffSBarry Smith   Level: developer
11612ef1f0ffSBarry Smith 
116211a5261eSBarry Smith   Note:
11632ef1f0ffSBarry Smith   The user should not free the array `mat`.
1164d8588912SDave May 
1165fe59aa6dSJacob Faibussowitsch   Fortran Notes:
116611a5261eSBarry Smith   This routine has a calling sequence
1167351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
116820f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1169351962e3SVincent Le Chenadec 
1170fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1171db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1172d8588912SDave May @*/
1173d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1174d71ae5a4SJacob Faibussowitsch {
1175d8588912SDave May   PetscFunctionBegin;
1176cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
11773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1178d8588912SDave May }
1179d8588912SDave May 
118066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1181d71ae5a4SJacob Faibussowitsch {
1182d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1183d8588912SDave May 
1184d8588912SDave May   PetscFunctionBegin;
118526fbe8dcSKarl Rupp   if (M) *M = bA->nr;
118626fbe8dcSKarl Rupp   if (N) *N = bA->nc;
11873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1188d8588912SDave May }
1189d8588912SDave May 
11909ba0d327SJed Brown /*@
119111a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1192d8588912SDave May 
11932ef1f0ffSBarry Smith   Not Collective
1194d8588912SDave May 
1195f899ff85SJose E. Roman   Input Parameter:
119611a5261eSBarry Smith . A - `MATNEST` matrix
1197d8588912SDave May 
1198d8d19677SJose E. Roman   Output Parameters:
1199629881c0SJed Brown + M - number of rows in the nested mat
1200629881c0SJed Brown - N - number of cols in the nested mat
1201d8588912SDave May 
1202d8588912SDave May   Level: developer
1203d8588912SDave May 
1204fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1205db781477SPatrick Sanan           `MatNestGetISs()`
1206d8588912SDave May @*/
1207d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1208d71ae5a4SJacob Faibussowitsch {
1209d8588912SDave May   PetscFunctionBegin;
1210cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1212d8588912SDave May }
1213d8588912SDave May 
1214d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1215d71ae5a4SJacob Faibussowitsch {
1216900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1217900e7ff2SJed Brown   PetscInt  i;
1218900e7ff2SJed Brown 
1219900e7ff2SJed Brown   PetscFunctionBegin;
12209371c9d4SSatish Balay   if (rows)
12219371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12229371c9d4SSatish Balay   if (cols)
12239371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1225900e7ff2SJed Brown }
1226900e7ff2SJed Brown 
12273a4d7b9aSSatish Balay /*@C
122811a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1229900e7ff2SJed Brown 
12302ef1f0ffSBarry Smith   Not Collective
1231900e7ff2SJed Brown 
1232f899ff85SJose E. Roman   Input Parameter:
123311a5261eSBarry Smith . A - `MATNEST` matrix
1234900e7ff2SJed Brown 
1235d8d19677SJose E. Roman   Output Parameters:
1236900e7ff2SJed Brown + rows - array of row index sets
1237900e7ff2SJed Brown - cols - array of column index sets
1238900e7ff2SJed Brown 
1239900e7ff2SJed Brown   Level: advanced
1240900e7ff2SJed Brown 
124111a5261eSBarry Smith   Note:
12422ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1243900e7ff2SJed Brown 
1244fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1245fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1246900e7ff2SJed Brown @*/
1247d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1248d71ae5a4SJacob Faibussowitsch {
1249900e7ff2SJed Brown   PetscFunctionBegin;
1250900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1251cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1253900e7ff2SJed Brown }
1254900e7ff2SJed Brown 
1255d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1256d71ae5a4SJacob Faibussowitsch {
1257900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1258900e7ff2SJed Brown   PetscInt  i;
1259900e7ff2SJed Brown 
1260900e7ff2SJed Brown   PetscFunctionBegin;
12619371c9d4SSatish Balay   if (rows)
12629371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12639371c9d4SSatish Balay   if (cols)
12649371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
12653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1266900e7ff2SJed Brown }
1267900e7ff2SJed Brown 
1268900e7ff2SJed Brown /*@C
126911a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1270900e7ff2SJed Brown 
12712ef1f0ffSBarry Smith   Not Collective
1272900e7ff2SJed Brown 
1273f899ff85SJose E. Roman   Input Parameter:
127411a5261eSBarry Smith . A - `MATNEST` matrix
1275900e7ff2SJed Brown 
1276d8d19677SJose E. Roman   Output Parameters:
12772ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore)
12782ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore)
1279900e7ff2SJed Brown 
1280900e7ff2SJed Brown   Level: advanced
1281900e7ff2SJed Brown 
128211a5261eSBarry Smith   Note:
12832ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1284900e7ff2SJed Brown 
12851cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1286fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1287900e7ff2SJed Brown @*/
1288d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1289d71ae5a4SJacob Faibussowitsch {
1290900e7ff2SJed Brown   PetscFunctionBegin;
1291900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1292cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1294900e7ff2SJed Brown }
1295900e7ff2SJed Brown 
129666976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1297d71ae5a4SJacob Faibussowitsch {
1298207556f9SJed Brown   PetscBool flg;
1299207556f9SJed Brown 
1300207556f9SJed Brown   PetscFunctionBegin;
13019566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1302207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13032a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
130412b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
13053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1306207556f9SJed Brown }
1307207556f9SJed Brown 
1308207556f9SJed Brown /*@C
130911a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1310207556f9SJed Brown 
13112ef1f0ffSBarry Smith   Not Collective
1312207556f9SJed Brown 
1313207556f9SJed Brown   Input Parameters:
131411a5261eSBarry Smith + A     - `MATNEST` matrix
131511a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1316207556f9SJed Brown 
1317207556f9SJed Brown   Level: developer
1318207556f9SJed Brown 
1319fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1320207556f9SJed Brown @*/
1321d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1322d71ae5a4SJacob Faibussowitsch {
1323207556f9SJed Brown   PetscFunctionBegin;
1324cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1326207556f9SJed Brown }
1327207556f9SJed Brown 
132866976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1329d71ae5a4SJacob Faibussowitsch {
1330c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1331c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
133288ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
133388ffe2e8SJose E. Roman   VecType   vtype, type;
1334d8588912SDave May 
1335d8588912SDave May   PetscFunctionBegin;
13369566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
133706a1af2fSStefano Zampini 
1338c8883902SJed Brown   s->nr = nr;
1339c8883902SJed Brown   s->nc = nc;
1340d8588912SDave May 
1341c8883902SJed Brown   /* Create space for submatrices */
13429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
134348a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i]));
1344c8883902SJed Brown   for (i = 0; i < nr; i++) {
1345c8883902SJed Brown     for (j = 0; j < nc; j++) {
1346c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
134748a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1348d8588912SDave May     }
1349d8588912SDave May   }
13509566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13519566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
135288ffe2e8SJose E. Roman   if (isstd) {
135388ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
135488ffe2e8SJose E. Roman     vtype = NULL;
135588ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
135688ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
135788ffe2e8SJose E. Roman         if (a[i * nc + j]) {
135888ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13599566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
136088ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
136188ffe2e8SJose E. Roman           } else if (sametype) {
13629566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13639566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
136488ffe2e8SJose E. Roman           }
136588ffe2e8SJose E. Roman         }
136688ffe2e8SJose E. Roman       }
136788ffe2e8SJose E. Roman     }
136888ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13699566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
137088ffe2e8SJose E. Roman     }
137188ffe2e8SJose E. Roman   }
1372d8588912SDave May 
13739566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1374d8588912SDave May 
13759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
13769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1377c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1378c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1379d8588912SDave May 
13809566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
138106a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
138206a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
138348a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
138406a1af2fSStefano Zampini     }
138506a1af2fSStefano Zampini   }
138606a1af2fSStefano Zampini 
13879566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1388d8588912SDave May 
13899566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
13909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
13919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
13929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1393c8883902SJed Brown 
13949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
13959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1396c8883902SJed Brown 
139706a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
139806a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
13999566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
140006a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
140106a1af2fSStefano Zampini   if (cong) {
140248a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
140306a1af2fSStefano Zampini   }
140406a1af2fSStefano Zampini   if (!cong) {
1405381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
140606a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
140706a1af2fSStefano Zampini     A->ops->shift           = NULL;
140806a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
140906a1af2fSStefano Zampini   }
141006a1af2fSStefano Zampini 
14119566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14129566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
141306a1af2fSStefano Zampini   A->nonzerostate++;
14143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1415d8588912SDave May }
1416d8588912SDave May 
1417c8883902SJed Brown /*@
141811a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1419c8883902SJed Brown 
1420c3339decSBarry Smith   Collective
1421c8883902SJed Brown 
1422d8d19677SJose E. Roman   Input Parameters:
142311a5261eSBarry Smith + A      - `MATNEST` matrix
1424c8883902SJed Brown . nr     - number of nested row blocks
14252ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1426c8883902SJed Brown . nc     - number of nested column blocks
14272ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
14282ef1f0ffSBarry Smith - a      - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL`
14292ef1f0ffSBarry Smith 
14302ef1f0ffSBarry Smith   Level: advanced
1431c8883902SJed Brown 
143211a5261eSBarry Smith   Note:
143311a5261eSBarry Smith   This always resets any submatrix information previously set
143406a1af2fSStefano Zampini 
14351cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1436c8883902SJed Brown @*/
1437d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1438d71ae5a4SJacob Faibussowitsch {
143906a1af2fSStefano Zampini   PetscInt i;
1440c8883902SJed Brown 
1441c8883902SJed Brown   PetscFunctionBegin;
1442c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
144308401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1444c8883902SJed Brown   if (nr && is_row) {
14454f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
1446c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1447c8883902SJed Brown   }
144808401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14491664e352SJed Brown   if (nc && is_col) {
14504f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
14519b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1452c8883902SJed Brown   }
14534f572ea9SToby Isaac   if (nr * nc > 0) PetscAssertPointer(a, 6);
1454cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1456c8883902SJed Brown }
1457d8588912SDave May 
1458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1459d71ae5a4SJacob Faibussowitsch {
146077019fcaSJed Brown   PetscBool flg;
146177019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
146277019fcaSJed Brown 
146377019fcaSJed Brown   PetscFunctionBegin;
1464aea6d515SStefano Zampini   *ltog = NULL;
146577019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
146677019fcaSJed Brown     if (islocal[i]) {
14679566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
146877019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
146977019fcaSJed Brown     } else {
14709566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
147177019fcaSJed Brown     }
147277019fcaSJed Brown     m += mi;
147377019fcaSJed Brown   }
14743ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1475aea6d515SStefano Zampini 
14769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1477165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
14780298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1479e108cb99SStefano Zampini     Mat                    sub  = NULL;
1480f6d38dbbSStefano Zampini     PetscSF                sf;
1481f6d38dbbSStefano Zampini     PetscLayout            map;
1482aea6d515SStefano Zampini     const PetscInt        *ix2;
148377019fcaSJed Brown 
1484165cd838SBarry Smith     if (!colflg) {
14859566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
148677019fcaSJed Brown     } else {
14879566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
148877019fcaSJed Brown     }
1489191fd14bSBarry Smith     if (sub) {
1490191fd14bSBarry Smith       if (!colflg) {
14919566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1492191fd14bSBarry Smith       } else {
14939566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1494191fd14bSBarry Smith       }
1495191fd14bSBarry Smith     }
149677019fcaSJed Brown     /*
149777019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
149877019fcaSJed 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.
149977019fcaSJed Brown     */
15009566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1501aea6d515SStefano Zampini     if (islocal[i]) {
1502aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1503aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1504aea6d515SStefano Zampini 
15059566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150628b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1507aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15089566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1509aea6d515SStefano Zampini 
1510aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15119566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1512aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1513aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1514aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1515aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1516aea6d515SStefano Zampini         nleaves++;
1517aea6d515SStefano Zampini       }
15189566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15199566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15209566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15219566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15229566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15239566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15249566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15269566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15279566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15289566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1529aea6d515SStefano Zampini     } else {
15309566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1531aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1532aea6d515SStefano Zampini     }
15339566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
153477019fcaSJed Brown     m += mi;
153577019fcaSJed Brown   }
15369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153877019fcaSJed Brown }
153977019fcaSJed Brown 
1540d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1541d8588912SDave May /*
1542d8588912SDave May   nprocessors = NP
1543d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1544d8588912SDave May        proc 0: => (g_0,h_0,)
1545d8588912SDave May        proc 1: => (g_1,h_1,)
1546d8588912SDave May        ...
1547d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1548d8588912SDave May 
1549d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1550d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1551d8588912SDave May 
1552d8588912SDave May             proc 0:
1553d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1554d8588912SDave May             proc 1:
1555d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1556d8588912SDave May 
1557d8588912SDave May             proc NP-1:
1558d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1559d8588912SDave May */
1560d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1561d71ae5a4SJacob Faibussowitsch {
1562e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15638188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15640298fd71SBarry Smith   Mat       sub = NULL;
1565d8588912SDave May 
1566d8588912SDave May   PetscFunctionBegin;
15679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
15689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1569d8588912SDave May   if (is_row) { /* valid IS is passed in */
1570a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1571e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15729566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
157326fbe8dcSKarl Rupp 
1574e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1575d8588912SDave May     }
15762ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
15778188e55aSJed Brown     nsum = 0;
15788188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
15799566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
158028b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
15819566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
158208401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15838188e55aSJed Brown       nsum += n;
15848188e55aSJed Brown     }
15859566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
158630bc264bSJed Brown     offset -= nsum;
1587e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15889566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15899566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
15909566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15919566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
15929566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
15932ae74bdbSJed Brown       offset += n;
1594d8588912SDave May     }
1595d8588912SDave May   }
1596d8588912SDave May 
1597d8588912SDave May   if (is_col) { /* valid IS is passed in */
1598a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1599e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16009566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
160126fbe8dcSKarl Rupp 
1602e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1603d8588912SDave May     }
16042ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16052ae74bdbSJed Brown     offset = A->cmap->rstart;
16068188e55aSJed Brown     nsum   = 0;
16078188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16089566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
160928b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16109566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
161108401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16128188e55aSJed Brown       nsum += n;
16138188e55aSJed Brown     }
16149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
161530bc264bSJed Brown     offset -= nsum;
1616e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16179566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16189566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16199566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16209566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16219566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16222ae74bdbSJed Brown       offset += n;
1623d8588912SDave May     }
1624d8588912SDave May   }
1625e2d7f03fSJed Brown 
1626e2d7f03fSJed Brown   /* Set up the local ISs */
16279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1629e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1630e2d7f03fSJed Brown     IS                     isloc;
16310298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1632e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16339566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16349566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1635207556f9SJed Brown     if (rmap) {
16369566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16379566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16389566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16399566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1640207556f9SJed Brown     } else {
1641207556f9SJed Brown       nlocal = 0;
16420298fd71SBarry Smith       isloc  = NULL;
1643207556f9SJed Brown     }
1644e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1645e2d7f03fSJed Brown     offset += nlocal;
1646e2d7f03fSJed Brown   }
16478188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1648e2d7f03fSJed Brown     IS                     isloc;
16490298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1650e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16519566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16529566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1653207556f9SJed Brown     if (cmap) {
16549566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16559566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16569566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16579566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1658207556f9SJed Brown     } else {
1659207556f9SJed Brown       nlocal = 0;
16600298fd71SBarry Smith       isloc  = NULL;
1661207556f9SJed Brown     }
1662e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1663e2d7f03fSJed Brown     offset += nlocal;
1664e2d7f03fSJed Brown   }
16650189643fSJed Brown 
166677019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
166777019fcaSJed Brown   {
166845b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
16699566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
16709566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
16719566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
16729566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
16739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
167477019fcaSJed Brown   }
167577019fcaSJed Brown 
167676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
16770189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
16780189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
16790189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
16800189643fSJed Brown         Mat      B = vs->m[i][j];
16810189643fSJed Brown         if (!B) continue;
16829566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
16839566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
16849566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
16859566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
16869566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
16879566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1688aed4548fSBarry 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);
1689aed4548fSBarry 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);
16900189643fSJed Brown       }
16910189643fSJed Brown     }
169276bd3646SJed Brown   }
1693a061e289SJed Brown 
1694a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1695a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1696a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
16973ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1698a061e289SJed Brown     }
1699a061e289SJed Brown   }
1700a061e289SJed Brown   A->assembled = PETSC_TRUE;
17013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1702d8588912SDave May }
1703d8588912SDave May 
170445c38901SJed Brown /*@C
170511a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1706659c6bb0SJed Brown 
170711a5261eSBarry Smith   Collective
1708659c6bb0SJed Brown 
1709d8d19677SJose E. Roman   Input Parameters:
171011a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1711659c6bb0SJed Brown . nr     - number of nested row blocks
17122ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1713659c6bb0SJed Brown . nc     - number of nested column blocks
17142ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
17152ef1f0ffSBarry Smith - a      - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1716659c6bb0SJed Brown 
1717659c6bb0SJed Brown   Output Parameter:
1718659c6bb0SJed Brown . B - new matrix
1719659c6bb0SJed Brown 
1720659c6bb0SJed Brown   Level: advanced
1721659c6bb0SJed Brown 
17221cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1723db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1724db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1725659c6bb0SJed Brown @*/
1726d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1727d71ae5a4SJacob Faibussowitsch {
1728d8588912SDave May   Mat A;
1729d8588912SDave May 
1730d8588912SDave May   PetscFunctionBegin;
1731f4259b30SLisandro Dalcin   *B = NULL;
17329566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17339566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
173491a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17359566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1736d8588912SDave May   *B = A;
17373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1738d8588912SDave May }
1739659c6bb0SJed Brown 
174066976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1741d71ae5a4SJacob Faibussowitsch {
1742b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
174323875855Sstefano_zampini   Mat          *trans;
1744b68353e5Sstefano_zampini   PetscScalar **avv;
1745b68353e5Sstefano_zampini   PetscScalar  *vv;
1746b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1747b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1748b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1749b68353e5Sstefano_zampini   PetscBool     done;
1750b68353e5Sstefano_zampini 
1751b68353e5Sstefano_zampini   PetscFunctionBegin;
17529566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1753b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1754b68353e5Sstefano_zampini     PetscInt rnr;
1755b68353e5Sstefano_zampini 
17569566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
175728b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
175808401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
17599566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1760b68353e5Sstefano_zampini   }
1761b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1762b68353e5Sstefano_zampini   nnz = 0;
17639566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1764b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1765b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1766b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1767b68353e5Sstefano_zampini       if (B) {
1768b68353e5Sstefano_zampini         PetscScalar *naa;
1769b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
177023875855Sstefano_zampini         PetscBool    istrans;
1771b68353e5Sstefano_zampini 
1772013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
177323875855Sstefano_zampini         if (istrans) {
177423875855Sstefano_zampini           Mat Bt;
177523875855Sstefano_zampini 
17769566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
17779566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
177823875855Sstefano_zampini           B = trans[i * nest->nc + j];
1779013e2dc7SBarry Smith         } else {
1780013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1781013e2dc7SBarry Smith           if (istrans) {
1782013e2dc7SBarry Smith             Mat Bt;
1783013e2dc7SBarry Smith 
1784013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1785013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1786013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1787013e2dc7SBarry Smith           }
178823875855Sstefano_zampini         }
17899566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
179028b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
17919566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1792b68353e5Sstefano_zampini         nnz += nii[nnr];
1793b68353e5Sstefano_zampini 
1794b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1795b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1796b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1797b68353e5Sstefano_zampini       }
1798b68353e5Sstefano_zampini     }
1799b68353e5Sstefano_zampini   }
1800b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1804b68353e5Sstefano_zampini   } else {
180508401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1806b68353e5Sstefano_zampini   }
1807b68353e5Sstefano_zampini 
1808b68353e5Sstefano_zampini   /* new row pointer */
18099566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1810b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1811b68353e5Sstefano_zampini     PetscInt ncr, rst;
1812b68353e5Sstefano_zampini 
18139566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18149566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1815b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1816b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1817b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1818b68353e5Sstefano_zampini         PetscInt  ir;
1819b68353e5Sstefano_zampini 
1820b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1821b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1822b68353e5Sstefano_zampini           nii++;
1823b68353e5Sstefano_zampini         }
1824b68353e5Sstefano_zampini       }
1825b68353e5Sstefano_zampini     }
1826b68353e5Sstefano_zampini   }
1827b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1828b68353e5Sstefano_zampini 
1829b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18309566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1831b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1832b68353e5Sstefano_zampini     PetscInt ncr, rst;
1833b68353e5Sstefano_zampini 
18349566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18359566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1836b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1837b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1838b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1839b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1840b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1841b68353e5Sstefano_zampini         PetscInt     ir, cst;
1842b68353e5Sstefano_zampini 
18439566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1844b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1845b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1846b68353e5Sstefano_zampini 
1847b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1848b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1849b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1850b68353e5Sstefano_zampini             njj++;
1851b68353e5Sstefano_zampini             nvv++;
1852b68353e5Sstefano_zampini           }
1853b68353e5Sstefano_zampini           ci[ir] += rsize;
1854b68353e5Sstefano_zampini           nii++;
1855b68353e5Sstefano_zampini         }
1856b68353e5Sstefano_zampini       }
1857b68353e5Sstefano_zampini     }
1858b68353e5Sstefano_zampini   }
18599566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1860b68353e5Sstefano_zampini 
1861b68353e5Sstefano_zampini   /* restore info */
1862b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1863b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1864b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1865b68353e5Sstefano_zampini       if (B) {
1866b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
186723875855Sstefano_zampini 
186823875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
18699566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
187028b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
18719566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
18729566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1873b68353e5Sstefano_zampini       }
1874b68353e5Sstefano_zampini     }
1875b68353e5Sstefano_zampini   }
18769566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1877b68353e5Sstefano_zampini 
1878b68353e5Sstefano_zampini   /* finalize newmat */
1879b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
18809566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1881b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1882b68353e5Sstefano_zampini     Mat B;
1883b68353e5Sstefano_zampini 
18849566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
18859566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1886b68353e5Sstefano_zampini   }
18879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
18889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1889b68353e5Sstefano_zampini   {
1890b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1891b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1892b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1893b68353e5Sstefano_zampini   }
18943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1895b68353e5Sstefano_zampini }
1896b68353e5Sstefano_zampini 
1897d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1898d71ae5a4SJacob Faibussowitsch {
1899be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1900be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1901be705e3aSPierre Jolivet   PetscBool flg;
1902be705e3aSPierre Jolivet 
1903be705e3aSPierre Jolivet   PetscFunctionBegin;
1904be705e3aSPierre Jolivet   /* Fill by row */
1905be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1906be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1907be705e3aSPierre Jolivet     IS              bNis;
1908be705e3aSPierre Jolivet     PetscInt        bN;
1909be705e3aSPierre Jolivet     const PetscInt *bNindices;
19109566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19119566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19129566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1913be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1914fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1915be705e3aSPierre Jolivet       PetscInt        bm, br;
1916be705e3aSPierre Jolivet       const PetscInt *bmindices;
1917be705e3aSPierre Jolivet       if (!B) continue;
1918013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1919be705e3aSPierre Jolivet       if (flg) {
1920cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1921cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19229566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1923be705e3aSPierre Jolivet         B = D;
1924be705e3aSPierre Jolivet       }
19259566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1926be705e3aSPierre Jolivet       if (flg) {
1927fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1928fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1929be705e3aSPierre Jolivet         B = D;
1930be705e3aSPierre Jolivet       }
19319566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19329566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19339566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1934be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1935be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1936be705e3aSPierre Jolivet         const PetscInt    *brcols;
1937be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1938be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19399566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19409566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1941be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1942be705e3aSPierre Jolivet         /*
1943be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1944be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1945be705e3aSPierre Jolivet          */
1946be705e3aSPierre Jolivet         if (a != 1.0) {
19479566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1948be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19499566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19509566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1951be705e3aSPierre Jolivet         } else {
19529566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1953be705e3aSPierre Jolivet         }
19549566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19559566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1956be705e3aSPierre Jolivet       }
1957fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19589566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1959be705e3aSPierre Jolivet     }
19609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
19619566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1962be705e3aSPierre Jolivet   }
19639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
19649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
19653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1966be705e3aSPierre Jolivet }
1967be705e3aSPierre Jolivet 
196866976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1969d71ae5a4SJacob Faibussowitsch {
1970629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
1971e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
1972b68353e5Sstefano_zampini   PetscMPIInt size;
1973629c3df2SDmitry Karpeev   Mat         C;
1974629c3df2SDmitry Karpeev 
1975629c3df2SDmitry Karpeev   PetscFunctionBegin;
19769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1977b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1978b68353e5Sstefano_zampini     PetscInt  nf;
1979b68353e5Sstefano_zampini     PetscBool fast;
1980b68353e5Sstefano_zampini 
19819566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
198248a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
1983b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
1984b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
1985b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1986b68353e5Sstefano_zampini         if (B) {
19879566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
198823875855Sstefano_zampini           if (!fast) {
198923875855Sstefano_zampini             PetscBool istrans;
199023875855Sstefano_zampini 
1991013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
199223875855Sstefano_zampini             if (istrans) {
199323875855Sstefano_zampini               Mat Bt;
199423875855Sstefano_zampini 
19959566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
19969566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1997013e2dc7SBarry Smith             } else {
1998013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1999013e2dc7SBarry Smith               if (istrans) {
2000013e2dc7SBarry Smith                 Mat Bt;
2001013e2dc7SBarry Smith 
2002013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2003013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2004013e2dc7SBarry Smith               }
200523875855Sstefano_zampini             }
2006b68353e5Sstefano_zampini           }
2007b68353e5Sstefano_zampini         }
2008b68353e5Sstefano_zampini       }
2009b68353e5Sstefano_zampini     }
2010b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20119566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2012b68353e5Sstefano_zampini       if (fast) {
2013b68353e5Sstefano_zampini         PetscInt f, s;
2014b68353e5Sstefano_zampini 
20159566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20169371c9d4SSatish Balay         if (f != nf || s != 1) {
20179371c9d4SSatish Balay           fast = PETSC_FALSE;
20189371c9d4SSatish Balay         } else {
20199566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2020b68353e5Sstefano_zampini           nf += f;
2021b68353e5Sstefano_zampini         }
2022b68353e5Sstefano_zampini       }
2023b68353e5Sstefano_zampini     }
2024b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20259566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2026b68353e5Sstefano_zampini       if (fast) {
2027b68353e5Sstefano_zampini         PetscInt f, s;
2028b68353e5Sstefano_zampini 
20299566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20309371c9d4SSatish Balay         if (f != nf || s != 1) {
20319371c9d4SSatish Balay           fast = PETSC_FALSE;
20329371c9d4SSatish Balay         } else {
20339566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2034b68353e5Sstefano_zampini           nf += f;
2035b68353e5Sstefano_zampini         }
2036b68353e5Sstefano_zampini       }
2037b68353e5Sstefano_zampini     }
2038b68353e5Sstefano_zampini     if (fast) {
20399566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20403ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2041b68353e5Sstefano_zampini     }
2042b68353e5Sstefano_zampini   }
20439566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20449566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20459566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2046d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2047d1487292SPierre Jolivet   else {
20489566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20499566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20509566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2051629c3df2SDmitry Karpeev   }
20529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2053e30678d3SPierre Jolivet   if (m) {
2054629c3df2SDmitry Karpeev     onnz = dnnz + m;
2055629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2056629c3df2SDmitry Karpeev       dnnz[k] = 0;
2057629c3df2SDmitry Karpeev       onnz[k] = 0;
2058629c3df2SDmitry Karpeev     }
2059e30678d3SPierre Jolivet   }
2060629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2061629c3df2SDmitry Karpeev     IS              bNis;
2062629c3df2SDmitry Karpeev     PetscInt        bN;
2063629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2064fd8a7442SPierre Jolivet     PetscBool       flg;
2065629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20669566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20679566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2069629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2070629c3df2SDmitry Karpeev       PetscSF         bmsf;
2071649b366bSFande Kong       PetscSFNode    *iremote;
2072fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2073649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2074629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2075629c3df2SDmitry Karpeev       if (!B) continue;
20769566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20779566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20789566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
20799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
20809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
20819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2082649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2083649b366bSFande Kong         sub_dnnz[k] = 0;
2084649b366bSFande Kong         sub_onnz[k] = 0;
2085649b366bSFande Kong       }
2086dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2087fd8a7442SPierre Jolivet       if (flg) {
2088fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2089fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2090fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2091fd8a7442SPierre Jolivet         B = D;
2092fd8a7442SPierre Jolivet       }
2093fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2094fd8a7442SPierre Jolivet       if (flg) {
2095fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2096fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2097fd8a7442SPierre Jolivet         B = D;
2098fd8a7442SPierre Jolivet       }
2099629c3df2SDmitry Karpeev       /*
2100629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2101629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2102629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2103629c3df2SDmitry Karpeev        */
21049566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2105629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2106131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2107629c3df2SDmitry Karpeev         const PetscInt *brcols;
2108a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2109131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21109566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2111649b366bSFande Kong         /* how many roots  */
21129371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21139371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2114649b366bSFande Kong         /* get nonzero pattern */
21159566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2116629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2117629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2118649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2119649b366bSFande Kong             sub_dnnz[br]++;
2120649b366bSFande Kong           } else {
2121649b366bSFande Kong             sub_onnz[br]++;
2122649b366bSFande Kong           }
2123629c3df2SDmitry Karpeev         }
21249566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2125629c3df2SDmitry Karpeev       }
2126fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21279566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2128629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21299566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21309566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21319566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21329566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21339566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21349566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21359566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21369566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2137629c3df2SDmitry Karpeev     }
21389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21399566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
214065a4a0a3Sstefano_zampini   }
214165a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
214265a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
214365a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
214465a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2145629c3df2SDmitry Karpeev   }
21469566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21479566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21489566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21499566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2150d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21519566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2152d1487292SPierre Jolivet   } else *newmat = C;
21533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2154be705e3aSPierre Jolivet }
2155629c3df2SDmitry Karpeev 
215666976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2157d71ae5a4SJacob Faibussowitsch {
2158629c3df2SDmitry Karpeev   Mat      B;
2159be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2160be705e3aSPierre Jolivet 
2161be705e3aSPierre Jolivet   PetscFunctionBegin;
21629566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
21639566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2164be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2165be705e3aSPierre Jolivet     B = *newmat;
21669566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2167be705e3aSPierre Jolivet   } else {
21689566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2169629c3df2SDmitry Karpeev   }
21709566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2171be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21729566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2173be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
21743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2175629c3df2SDmitry Karpeev }
2176629c3df2SDmitry Karpeev 
217766976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2178d71ae5a4SJacob Faibussowitsch {
21798b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
21803c6db4c4SPierre Jolivet   MatOperation opAdd;
21818b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
21828b7d3b4bSBarry Smith   PetscBool    flg;
218352c5f739Sprj-   PetscFunctionBegin;
21848b7d3b4bSBarry Smith 
218552c5f739Sprj-   *has = PETSC_FALSE;
21863c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21873c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21888b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
21898b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
21908b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21919566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
21923ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
21938b7d3b4bSBarry Smith       }
21948b7d3b4bSBarry Smith     }
21958b7d3b4bSBarry Smith   }
21963c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
21973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21988b7d3b4bSBarry Smith }
21998b7d3b4bSBarry Smith 
2200659c6bb0SJed Brown /*MC
22012ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2202659c6bb0SJed Brown 
2203659c6bb0SJed Brown   Level: intermediate
2204659c6bb0SJed Brown 
2205659c6bb0SJed Brown   Notes:
220611a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2207659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
220811a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2209659c6bb0SJed Brown 
22108b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22118b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22128b7d3b4bSBarry Smith   than the nest matrix.
22138b7d3b4bSBarry Smith 
22141cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2215db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2216db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2217659c6bb0SJed Brown M*/
2218d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2219d71ae5a4SJacob Faibussowitsch {
2220c8883902SJed Brown   Mat_Nest *s;
2221c8883902SJed Brown 
2222c8883902SJed Brown   PetscFunctionBegin;
22234dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2224c8883902SJed Brown   A->data = (void *)s;
2225e7c19651SJed Brown 
2226e7c19651SJed Brown   s->nr            = -1;
2227e7c19651SJed Brown   s->nc            = -1;
22280298fd71SBarry Smith   s->m             = NULL;
2229e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2230c8883902SJed Brown 
22319566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
223226fbe8dcSKarl Rupp 
2233c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22349194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2235c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22369194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2237f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2238c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2239c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2240c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2241c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22426e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2243c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22447dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2245c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2246c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2247f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2248c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2249c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2250429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2251429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2252a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2253a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
225413135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2255f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22568b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2257381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2258c8883902SJed Brown 
2259f4259b30SLisandro Dalcin   A->spptr     = NULL;
2260c8883902SJed Brown   A->assembled = PETSC_FALSE;
2261c8883902SJed Brown 
2262c8883902SJed Brown   /* expose Nest api's */
22639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
22649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
22659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
22669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
22679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
22689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
22709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
22719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
22729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
22749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
22759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
22779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
22789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
22799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense));
2280c8883902SJed Brown 
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
22823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2283c8883902SJed Brown }
2284