xref: /petsc/src/mat/impls/nest/matnest.c (revision 1cc06b555e92f8ec64db10330b8bbd830e5bc876)
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- 
92d71ae5a4SJacob Faibussowitsch PETSC_INTERN 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;
1036718818eSStefano Zampini   MatCheckProduct(C, 3);
1046718818eSStefano Zampini   A = C->product->A;
1056718818eSStefano Zampini   B = C->product->B;
1069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
1076718818eSStefano Zampini   if (!N) {
1089566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1099566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1116718818eSStefano Zampini   }
1126718818eSStefano Zampini   contents = (Nest_Dense *)C->product->data;
11328b400f6SJacob Faibussowitsch   PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
1146718818eSStefano Zampini   bA = (Mat_Nest *)A->data;
1156718818eSStefano Zampini   nr = bA->nr;
1166718818eSStefano Zampini   nc = bA->nc;
1179566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
1189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(C, &ldc));
1199566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(C));
1209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
1219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(C, &carray));
12252c5f739Sprj-   for (i = 0; i < nr; i++) {
1239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &M));
1249566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, carray + contents->dm[i], &viewC));
1259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC, ldc));
12652c5f739Sprj-     for (j = 0; j < nc; j++) {
12752c5f739Sprj-       if (!bA->m[i][j]) continue;
1289566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
1299566063dSJacob Faibussowitsch       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB));
1309566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB, ldb));
1314222ddf1SHong Zhang 
1324222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1334222ddf1SHong Zhang       workC             = contents->workC[i * nc + j];
1344222ddf1SHong Zhang       productB          = workC->product->B;
1354222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1369566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1384222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1394222ddf1SHong Zhang 
14052c5f739Sprj-       /* C[i] <- workC + C[i] */
1419566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
14252c5f739Sprj-     }
1439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14452c5f739Sprj-   }
1459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C, &carray));
1469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
1474222ddf1SHong Zhang 
1489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15152c5f739Sprj- }
15252c5f739Sprj- 
153d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNest_DenseDestroy(void *ctx)
154d71ae5a4SJacob Faibussowitsch {
15552c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15652c5f739Sprj-   PetscInt    i;
15752c5f739Sprj- 
15852c5f739Sprj-   PetscFunctionBegin;
1599566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16048a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1619566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1629566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
1633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16452c5f739Sprj- }
16552c5f739Sprj- 
166d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
167d71ae5a4SJacob Faibussowitsch {
1686718818eSStefano Zampini   Mat_Nest          *bA;
1696718818eSStefano Zampini   Mat                viewB, workC;
17052c5f739Sprj-   const PetscScalar *barray;
1716718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1724222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1736718818eSStefano Zampini   PetscBool          cisdense;
1746718818eSStefano Zampini   Mat                A, B;
1756718818eSStefano Zampini   PetscReal          fill;
17652c5f739Sprj- 
17752c5f739Sprj-   PetscFunctionBegin;
1786718818eSStefano Zampini   MatCheckProduct(C, 4);
17928b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1806718818eSStefano Zampini   A    = C->product->A;
1816718818eSStefano Zampini   B    = C->product->B;
1826718818eSStefano Zampini   fill = C->product->fill;
1836718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1846718818eSStefano Zampini   nr   = bA->nr;
1856718818eSStefano Zampini   nc   = bA->nc;
1869566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1880572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1899566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1909566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1919566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1939566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1940572eedcSPierre Jolivet   }
1959566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19648a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1979566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
1986718818eSStefano Zampini   if (!N) {
1996718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2003ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20152c5f739Sprj-   }
20252c5f739Sprj- 
2039566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2046718818eSStefano Zampini   C->product->data    = contents;
2056718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2069566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20752c5f739Sprj-   contents->k = nr * nc;
20852c5f739Sprj-   for (i = 0; i < nr; i++) {
2099566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
21052c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
21152c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
21252c5f739Sprj-   }
21352c5f739Sprj-   for (i = 0; i < nc; i++) {
2149566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
21552c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21652c5f739Sprj-   }
2179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2199566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
22152c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22252c5f739Sprj-   for (j = 0; j < nc; j++) {
2239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
2249566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB));
2259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22652c5f739Sprj-     for (i = 0; i < nr; i++) {
22752c5f739Sprj-       if (!bA->m[i][j]) continue;
22852c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2294222ddf1SHong Zhang 
2309566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2314222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2329566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2339566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2349566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2359566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2374222ddf1SHong Zhang 
2386718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2399566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2409566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
24152c5f739Sprj-     }
2429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24352c5f739Sprj-   }
2449566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
24552c5f739Sprj- 
2466718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24852c5f739Sprj- }
24952c5f739Sprj- 
250d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
251d71ae5a4SJacob Faibussowitsch {
2524222ddf1SHong Zhang   PetscFunctionBegin;
2536718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2554222ddf1SHong Zhang }
2564222ddf1SHong Zhang 
257d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
258d71ae5a4SJacob Faibussowitsch {
2594222ddf1SHong Zhang   Mat_Product *product = C->product;
26052c5f739Sprj- 
26152c5f739Sprj-   PetscFunctionBegin;
26248a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
2633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26452c5f739Sprj- }
26552c5f739Sprj- 
266d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
267d71ae5a4SJacob Faibussowitsch {
268d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
269207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
270207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
271d8588912SDave May 
272d8588912SDave May   PetscFunctionBegin;
2739566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2749566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
275207556f9SJed Brown   for (j = 0; j < nc; j++) {
2769566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
277609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2786c75ac25SJed Brown       if (!bA->m[i][j]) continue;
279609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2809566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));
281d8588912SDave May     }
282d8588912SDave May   }
2839566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2849566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
286d8588912SDave May }
287d8588912SDave May 
288d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
289d71ae5a4SJacob Faibussowitsch {
2909194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2919194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
2929194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
2939194d70fSJed Brown 
2949194d70fSJed Brown   PetscFunctionBegin;
2959566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2969566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
2979194d70fSJed Brown   for (j = 0; j < nc; j++) {
2989194d70fSJed Brown     if (y != z) {
2999194d70fSJed Brown       Vec by;
3009566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3019566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3029566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3039194d70fSJed Brown     }
3049194d70fSJed Brown     for (i = 0; i < nr; i++) {
3056c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3069194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3079566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));
3089194d70fSJed Brown     }
3099194d70fSJed Brown   }
3109566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3119566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3139194d70fSJed Brown }
3149194d70fSJed Brown 
315d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
316d71ae5a4SJacob Faibussowitsch {
317f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
318f8170845SAlex Fikl   Mat       C;
319f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
320f8170845SAlex Fikl 
321f8170845SAlex Fikl   PetscFunctionBegin;
3227fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
323aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
324f8170845SAlex Fikl 
325cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
326f8170845SAlex Fikl     Mat *subs;
327f8170845SAlex Fikl     IS  *is_row, *is_col;
328f8170845SAlex Fikl 
3299566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3319566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
332cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
333ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
334ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
335ddeb9bd8SAlex Fikl       }
336ddeb9bd8SAlex Fikl     }
337ddeb9bd8SAlex Fikl 
3389566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3399566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3409566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
341f8170845SAlex Fikl   } else {
342f8170845SAlex Fikl     C = *B;
343f8170845SAlex Fikl   }
344f8170845SAlex Fikl 
345f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
346f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
347f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
348f8170845SAlex Fikl       if (bA->m[i][j]) {
3499566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
350f8170845SAlex Fikl       } else {
351f8170845SAlex Fikl         bC->m[j][i] = NULL;
352f8170845SAlex Fikl       }
353f8170845SAlex Fikl     }
354f8170845SAlex Fikl   }
355f8170845SAlex Fikl 
356cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
357f8170845SAlex Fikl     *B = C;
358f8170845SAlex Fikl   } else {
3599566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
360f8170845SAlex Fikl   }
3613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
362f8170845SAlex Fikl }
363f8170845SAlex Fikl 
364d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
365d71ae5a4SJacob Faibussowitsch {
366e2d7f03fSJed Brown   IS      *lst = *list;
367e2d7f03fSJed Brown   PetscInt i;
368e2d7f03fSJed Brown 
369e2d7f03fSJed Brown   PetscFunctionBegin;
3703ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
3719371c9d4SSatish Balay   for (i = 0; i < n; i++)
3729371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3739566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3740298fd71SBarry Smith   *list = NULL;
3753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
376e2d7f03fSJed Brown }
377e2d7f03fSJed Brown 
378d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
379d71ae5a4SJacob Faibussowitsch {
380d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
381d8588912SDave May   PetscInt  i, j;
382d8588912SDave May 
383d8588912SDave May   PetscFunctionBegin;
384d8588912SDave May   /* release the matrices and the place holders */
3859566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
3869566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
3879566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
3889566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
389d8588912SDave May 
3909566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
3919566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
393d8588912SDave May 
3949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
395207556f9SJed Brown 
396d8588912SDave May   /* release the matrices and the place holders */
397d8588912SDave May   if (vs->m) {
398d8588912SDave May     for (i = 0; i < vs->nr; i++) {
39948a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
4009566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
401d8588912SDave May     }
4029566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
403d8588912SDave May   }
40406a1af2fSStefano Zampini 
40506a1af2fSStefano Zampini   /* restore defaults */
40606a1af2fSStefano Zampini   vs->nr            = 0;
40706a1af2fSStefano Zampini   vs->nc            = 0;
40806a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41006a1af2fSStefano Zampini }
41106a1af2fSStefano Zampini 
412d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
413d71ae5a4SJacob Faibussowitsch {
414362febeeSStefano Zampini   PetscFunctionBegin;
4159566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4169566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL));
4343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
435d8588912SDave May }
436d8588912SDave May 
437d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
438d71ae5a4SJacob Faibussowitsch {
439381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
440381b8e50SStefano Zampini   PetscInt  i;
441381b8e50SStefano Zampini 
442381b8e50SStefano Zampini   PetscFunctionBegin;
443381b8e50SStefano Zampini   if (dd) *dd = 0;
444381b8e50SStefano Zampini   if (!vs->nr) {
445381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
447381b8e50SStefano Zampini   }
448381b8e50SStefano Zampini   *missing = PETSC_FALSE;
449381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
450381b8e50SStefano Zampini     *missing = PETSC_TRUE;
451381b8e50SStefano Zampini     if (vs->m[i][i]) {
4529566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
45308401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
454381b8e50SStefano Zampini     }
455381b8e50SStefano Zampini   }
4563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
457381b8e50SStefano Zampini }
458381b8e50SStefano Zampini 
459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
460d71ae5a4SJacob Faibussowitsch {
461d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
462d8588912SDave May   PetscInt  i, j;
46306a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
464d8588912SDave May 
465d8588912SDave May   PetscFunctionBegin;
466d8588912SDave May   for (i = 0; i < vs->nr; i++) {
467d8588912SDave May     for (j = 0; j < vs->nc; j++) {
46806a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
469e7c19651SJed Brown       if (vs->m[i][j]) {
4709566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
471e7c19651SJed Brown         if (!vs->splitassembly) {
472e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
473e7c19651SJed 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
474e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
475e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
476e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
477e7c19651SJed Brown            */
4789566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4799566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
480e7c19651SJed Brown         }
481e7c19651SJed Brown       }
48206a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
48306a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
484d8588912SDave May     }
485d8588912SDave May   }
48606a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
4873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
488d8588912SDave May }
489d8588912SDave May 
490d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
491d71ae5a4SJacob Faibussowitsch {
492d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
493d8588912SDave May   PetscInt  i, j;
494d8588912SDave May 
495d8588912SDave May   PetscFunctionBegin;
496d8588912SDave May   for (i = 0; i < vs->nr; i++) {
497d8588912SDave May     for (j = 0; j < vs->nc; j++) {
498e7c19651SJed Brown       if (vs->m[i][j]) {
49948a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
500e7c19651SJed Brown       }
501d8588912SDave May     }
502d8588912SDave May   }
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504d8588912SDave May }
505d8588912SDave May 
506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
507d71ae5a4SJacob Faibussowitsch {
508f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
509f349c1fdSJed Brown   PetscInt  j;
510f349c1fdSJed Brown   Mat       sub;
511d8588912SDave May 
512d8588912SDave May   PetscFunctionBegin;
5130298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
514f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5159566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
516f349c1fdSJed Brown   *B = sub;
5173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
518d8588912SDave May }
519d8588912SDave May 
520d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
521d71ae5a4SJacob Faibussowitsch {
522f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
523f349c1fdSJed Brown   PetscInt  i;
524f349c1fdSJed Brown   Mat       sub;
525f349c1fdSJed Brown 
526f349c1fdSJed Brown   PetscFunctionBegin;
5270298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
528f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5299566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
530f349c1fdSJed Brown   *B = sub;
5313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
532d8588912SDave May }
533d8588912SDave May 
534d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
535d71ae5a4SJacob Faibussowitsch {
53618d228c0SPierre Jolivet   PetscInt  i, j, size, m;
537f349c1fdSJed Brown   PetscBool flg;
53818d228c0SPierre Jolivet   IS        out, concatenate[2];
539f349c1fdSJed Brown 
540f349c1fdSJed Brown   PetscFunctionBegin;
541f349c1fdSJed Brown   PetscValidPointer(list, 3);
542f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
54318d228c0SPierre Jolivet   if (begin) {
54418d228c0SPierre Jolivet     PetscValidIntPointer(begin, 5);
54518d228c0SPierre Jolivet     *begin = -1;
54618d228c0SPierre Jolivet   }
54718d228c0SPierre Jolivet   if (end) {
54818d228c0SPierre Jolivet     PetscValidIntPointer(end, 6);
54918d228c0SPierre Jolivet     *end = -1;
55018d228c0SPierre Jolivet   }
551f349c1fdSJed Brown   for (i = 0; i < n; i++) {
552207556f9SJed Brown     if (!list[i]) continue;
5539566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
554f349c1fdSJed Brown     if (flg) {
55518d228c0SPierre Jolivet       if (begin) *begin = i;
55618d228c0SPierre Jolivet       if (end) *end = i + 1;
5573ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
558f349c1fdSJed Brown     }
559f349c1fdSJed Brown   }
5609566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
56118d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
56218d228c0SPierre Jolivet     if (!list[i]) continue;
56318d228c0SPierre Jolivet     m = 0;
5649566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5659566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
56618d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
56718d228c0SPierre Jolivet       if (list[j]) {
56818d228c0SPierre Jolivet         concatenate[0] = out;
56918d228c0SPierre Jolivet         concatenate[1] = list[j];
5709566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5719566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5729566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
57318d228c0SPierre Jolivet       }
57418d228c0SPierre Jolivet     }
57518d228c0SPierre Jolivet     if (m == size) {
5769566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
57718d228c0SPierre Jolivet       if (flg) {
57818d228c0SPierre Jolivet         if (begin) *begin = i;
57918d228c0SPierre Jolivet         if (end) *end = j;
5809566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
5813ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
58218d228c0SPierre Jolivet       }
58318d228c0SPierre Jolivet     }
5849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
58518d228c0SPierre Jolivet   }
5863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
587f349c1fdSJed Brown }
588f349c1fdSJed Brown 
589d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
590d71ae5a4SJacob Faibussowitsch {
5918188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
59218d228c0SPierre Jolivet   PetscInt  lr, lc;
59318d228c0SPierre Jolivet 
59418d228c0SPierre Jolivet   PetscFunctionBegin;
5959566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5969566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
5989566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
5999566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6009566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6019566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6029566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6039566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60718d228c0SPierre Jolivet }
60818d228c0SPierre Jolivet 
609d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
610d71ae5a4SJacob Faibussowitsch {
61118d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
61218d228c0SPierre Jolivet   Mat       *a;
61318d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6148188e55aSJed Brown   char       keyname[256];
61518d228c0SPierre Jolivet   PetscBool *b;
61618d228c0SPierre Jolivet   PetscBool  flg;
6178188e55aSJed Brown 
6188188e55aSJed Brown   PetscFunctionBegin;
6190298fd71SBarry Smith   *B = NULL;
6209566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6219566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6223ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6238188e55aSJed Brown 
6249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
62518d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
62618d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
62718d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
62818d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
62918d228c0SPierre Jolivet     }
63018d228c0SPierre Jolivet   }
63118d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
63218d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
63318d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
63418d228c0SPierre Jolivet         flg = PETSC_FALSE;
63518d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
63618d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
63718d228c0SPierre Jolivet         }
63818d228c0SPierre Jolivet         if (flg) {
63918d228c0SPierre Jolivet           flg = PETSC_FALSE;
64018d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
64118d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
64218d228c0SPierre Jolivet           }
64318d228c0SPierre Jolivet         }
64418d228c0SPierre Jolivet         if (!flg) {
64518d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6469566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
64718d228c0SPierre Jolivet         }
64818d228c0SPierre Jolivet       }
64918d228c0SPierre Jolivet     }
65018d228c0SPierre Jolivet   }
6519566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
65218d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
65318d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
65448a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
65518d228c0SPierre Jolivet     }
65618d228c0SPierre Jolivet   }
6579566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6588188e55aSJed Brown   (*B)->assembled = A->assembled;
6599566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6609566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6628188e55aSJed Brown }
6638188e55aSJed Brown 
664d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
665d71ae5a4SJacob Faibussowitsch {
666f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
66718d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
668f349c1fdSJed Brown 
669f349c1fdSJed Brown   PetscFunctionBegin;
6709566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6719566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
67218d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
67348a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
67418d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
67518d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6769566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
67718d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
6783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
679f349c1fdSJed Brown }
680f349c1fdSJed Brown 
68106a1af2fSStefano Zampini /*
68206a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
68306a1af2fSStefano Zampini */
684d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
685d71ae5a4SJacob Faibussowitsch {
686f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
687f349c1fdSJed Brown   Mat       sub;
688f349c1fdSJed Brown 
689f349c1fdSJed Brown   PetscFunctionBegin;
6909566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
691f349c1fdSJed Brown   switch (reuse) {
692f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6939566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
694f349c1fdSJed Brown     *B = sub;
695f349c1fdSJed Brown     break;
696d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
697d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
698d71ae5a4SJacob Faibussowitsch     break;
699d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
700d71ae5a4SJacob Faibussowitsch     break;
701d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
702d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
703f349c1fdSJed Brown   }
7043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
705f349c1fdSJed Brown }
706f349c1fdSJed Brown 
707d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
708d71ae5a4SJacob Faibussowitsch {
709f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
710f349c1fdSJed Brown   Mat       sub;
711f349c1fdSJed Brown 
712f349c1fdSJed Brown   PetscFunctionBegin;
7139566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
714f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7159566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
716f349c1fdSJed Brown   *B = sub;
7173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
718d8588912SDave May }
719d8588912SDave May 
720d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
721d71ae5a4SJacob Faibussowitsch {
722f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
723f349c1fdSJed Brown   Mat       sub;
724d8588912SDave May 
725d8588912SDave May   PetscFunctionBegin;
7269566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
72708401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
728f349c1fdSJed Brown   if (sub) {
729aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7309566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
731d8588912SDave May   }
7323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
733d8588912SDave May }
734d8588912SDave May 
735d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
736d71ae5a4SJacob Faibussowitsch {
7377874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7387874fa86SDave May   PetscInt  i;
7397874fa86SDave May 
7407874fa86SDave May   PetscFunctionBegin;
7417874fa86SDave May   for (i = 0; i < bA->nr; i++) {
742429bac76SJed Brown     Vec bv;
7439566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7447874fa86SDave May     if (bA->m[i][i]) {
7459566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7467874fa86SDave May     } else {
7479566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7487874fa86SDave May     }
7499566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7507874fa86SDave May   }
7513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7527874fa86SDave May }
7537874fa86SDave May 
754d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
755d71ae5a4SJacob Faibussowitsch {
7567874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
757429bac76SJed Brown   Vec       bl, *br;
7587874fa86SDave May   PetscInt  i, j;
7597874fa86SDave May 
7607874fa86SDave May   PetscFunctionBegin;
7619566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7622e6472ebSElliott Sales de Andrade   if (r) {
7639566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7642e6472ebSElliott Sales de Andrade   }
7652e6472ebSElliott Sales de Andrade   bl = NULL;
7667874fa86SDave May   for (i = 0; i < bA->nr; i++) {
76748a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7687874fa86SDave May     for (j = 0; j < bA->nc; j++) {
76948a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7707874fa86SDave May     }
77148a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7722e6472ebSElliott Sales de Andrade   }
7732e6472ebSElliott Sales de Andrade   if (r) {
7749566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7752e6472ebSElliott Sales de Andrade   }
7769566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7787874fa86SDave May }
7797874fa86SDave May 
780d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
781d71ae5a4SJacob Faibussowitsch {
782a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
783a061e289SJed Brown   PetscInt  i, j;
784a061e289SJed Brown 
785a061e289SJed Brown   PetscFunctionBegin;
786a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
787a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
78848a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
789a061e289SJed Brown     }
790a061e289SJed Brown   }
7913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
792a061e289SJed Brown }
793a061e289SJed Brown 
794d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
795d71ae5a4SJacob Faibussowitsch {
796a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
797a061e289SJed Brown   PetscInt  i;
79806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
799a061e289SJed Brown 
800a061e289SJed Brown   PetscFunctionBegin;
801a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
80206a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
80308401ef6SPierre 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);
8049566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8059566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
80606a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
80706a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
808a061e289SJed Brown   }
80906a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
811a061e289SJed Brown }
812a061e289SJed Brown 
813d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
814d71ae5a4SJacob Faibussowitsch {
81513135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
81613135bc6SAlex Fikl   PetscInt  i;
81706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
81813135bc6SAlex Fikl 
81913135bc6SAlex Fikl   PetscFunctionBegin;
82013135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
82106a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82213135bc6SAlex Fikl     Vec              bv;
8239566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
82413135bc6SAlex Fikl     if (bA->m[i][i]) {
8259566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8269566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82713135bc6SAlex Fikl     }
8289566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
82906a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
83006a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
83113135bc6SAlex Fikl   }
83206a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83413135bc6SAlex Fikl }
83513135bc6SAlex Fikl 
836d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
837d71ae5a4SJacob Faibussowitsch {
838f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
839f8170845SAlex Fikl   PetscInt  i, j;
840f8170845SAlex Fikl 
841f8170845SAlex Fikl   PetscFunctionBegin;
842f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
843f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
84448a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
845f8170845SAlex Fikl     }
846f8170845SAlex Fikl   }
8473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
848f8170845SAlex Fikl }
849f8170845SAlex Fikl 
850d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
851d71ae5a4SJacob Faibussowitsch {
852d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
853d8588912SDave May   Vec      *L, *R;
854d8588912SDave May   MPI_Comm  comm;
855d8588912SDave May   PetscInt  i, j;
856d8588912SDave May 
857d8588912SDave May   PetscFunctionBegin;
8589566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
859d8588912SDave May   if (right) {
860d8588912SDave May     /* allocate R */
8619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
862d8588912SDave May     /* Create the right vectors */
863d8588912SDave May     for (j = 0; j < bA->nc; j++) {
864d8588912SDave May       for (i = 0; i < bA->nr; i++) {
865d8588912SDave May         if (bA->m[i][j]) {
8669566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
867d8588912SDave May           break;
868d8588912SDave May         }
869d8588912SDave May       }
87008401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
871d8588912SDave May     }
8729566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
873d8588912SDave May     /* hand back control to the nest vector */
87448a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8759566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
876d8588912SDave May   }
877d8588912SDave May 
878d8588912SDave May   if (left) {
879d8588912SDave May     /* allocate L */
8809566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
881d8588912SDave May     /* Create the left vectors */
882d8588912SDave May     for (i = 0; i < bA->nr; i++) {
883d8588912SDave May       for (j = 0; j < bA->nc; j++) {
884d8588912SDave May         if (bA->m[i][j]) {
8859566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
886d8588912SDave May           break;
887d8588912SDave May         }
888d8588912SDave May       }
88908401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
890d8588912SDave May     }
891d8588912SDave May 
8929566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
89348a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
894d8588912SDave May 
8959566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
896d8588912SDave May   }
8973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
898d8588912SDave May }
899d8588912SDave May 
900d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
901d71ae5a4SJacob Faibussowitsch {
902d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
90329e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
904d8588912SDave May   PetscInt  i, j;
905d8588912SDave May 
906d8588912SDave May   PetscFunctionBegin;
9079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
908d8588912SDave May   if (isascii) {
9099566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object: \n"));
9119566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n", bA->nr, bA->nc));
913d8588912SDave May 
9149566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure: \n"));
915d8588912SDave May     for (i = 0; i < bA->nr; i++) {
916d8588912SDave May       for (j = 0; j < bA->nc; j++) {
91719fd82e9SBarry Smith         MatType   type;
918270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
919d8588912SDave May         PetscInt  NR, NC;
920d8588912SDave May         PetscBool isNest = PETSC_FALSE;
921d8588912SDave May 
922d8588912SDave May         if (!bA->m[i][j]) {
9239566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n", i, j));
924d8588912SDave May           continue;
925d8588912SDave May         }
9269566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9279566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9289566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9299566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9309566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
931d8588912SDave May 
9329566063dSJacob 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));
933d8588912SDave May 
93429e60adbSStefano Zampini         if (isNest || viewSub) {
9359566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9369566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9379566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
938d8588912SDave May         }
939d8588912SDave May       }
940d8588912SDave May     }
9419566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
942d8588912SDave May   }
9433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
944d8588912SDave May }
945d8588912SDave May 
946d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
947d71ae5a4SJacob Faibussowitsch {
948d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
949d8588912SDave May   PetscInt  i, j;
950d8588912SDave May 
951d8588912SDave May   PetscFunctionBegin;
952d8588912SDave May   for (i = 0; i < bA->nr; i++) {
953d8588912SDave May     for (j = 0; j < bA->nc; j++) {
954d8588912SDave May       if (!bA->m[i][j]) continue;
9559566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
956d8588912SDave May     }
957d8588912SDave May   }
9583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
959d8588912SDave May }
960d8588912SDave May 
961d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
962d71ae5a4SJacob Faibussowitsch {
963c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
964c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
96506a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
966c222c20dSDavid Ham 
967c222c20dSDavid Ham   PetscFunctionBegin;
968aed4548fSBarry 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);
969c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
970c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
97106a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
97246a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9739566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
97408401ef6SPierre 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);
9759566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
97606a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
97706a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
978c222c20dSDavid Ham     }
979c222c20dSDavid Ham   }
98006a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
9813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
982c222c20dSDavid Ham }
983c222c20dSDavid Ham 
984d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
985d71ae5a4SJacob Faibussowitsch {
9866e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
9876e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
98806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
9896e76ffeaSPierre Jolivet 
9906e76ffeaSPierre Jolivet   PetscFunctionBegin;
991aed4548fSBarry 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);
9926e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
9936e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
99406a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9956e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9969566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
997c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
998c066aebcSStefano Zampini         Mat M;
999c066aebcSStefano Zampini 
100008401ef6SPierre Jolivet         PetscCheck(str == DIFFERENT_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN", i, j);
10019566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10029566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10039566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1004c066aebcSStefano Zampini       }
10059566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
100606a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
100706a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10086e76ffeaSPierre Jolivet     }
10096e76ffeaSPierre Jolivet   }
101006a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10126e76ffeaSPierre Jolivet }
10136e76ffeaSPierre Jolivet 
1014d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1015d71ae5a4SJacob Faibussowitsch {
1016d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1017841e96a3SJed Brown   Mat      *b;
1018841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1019d8588912SDave May 
1020d8588912SDave May   PetscFunctionBegin;
10219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1022841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1023841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1024841e96a3SJed Brown       if (bA->m[i][j]) {
10259566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1026841e96a3SJed Brown       } else {
10270298fd71SBarry Smith         b[i * nc + j] = NULL;
1028d8588912SDave May       }
1029d8588912SDave May     }
1030d8588912SDave May   }
10319566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1032841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
103348a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10349566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1035d8588912SDave May 
10369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1039d8588912SDave May }
1040d8588912SDave May 
1041d8588912SDave May /* nest api */
1042d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1043d71ae5a4SJacob Faibussowitsch {
1044d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10455fd66863SKarl Rupp 
1046d8588912SDave May   PetscFunctionBegin;
104708401ef6SPierre 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);
104808401ef6SPierre 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);
1049d8588912SDave May   *mat = bA->m[idxm][jdxm];
10503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1051d8588912SDave May }
1052d8588912SDave May 
10539ba0d327SJed Brown /*@
105411a5261eSBarry Smith  MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1055d8588912SDave May 
10562ef1f0ffSBarry Smith  Not Collective
1057d8588912SDave May 
1058d8588912SDave May  Input Parameters:
105911a5261eSBarry Smith +   A  - `MATNEST` matrix
1060d8588912SDave May .   idxm - index of the matrix within the nest matrix
1061629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1062d8588912SDave May 
1063d8588912SDave May  Output Parameter:
10642ef1f0ffSBarry Smith .   sub - matrix at index `idxm`, `jdxm` within the nest matrix
1065d8588912SDave May 
1066d8588912SDave May  Level: developer
1067d8588912SDave May 
1068*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`,
1069db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1070d8588912SDave May @*/
1071d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1072d71ae5a4SJacob Faibussowitsch {
1073d8588912SDave May   PetscFunctionBegin;
1074cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
10753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1076d8588912SDave May }
1077d8588912SDave May 
1078d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1079d71ae5a4SJacob Faibussowitsch {
10800782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
10810782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
10820782ca92SJed Brown 
10830782ca92SJed Brown   PetscFunctionBegin;
108408401ef6SPierre 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);
108508401ef6SPierre 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);
10869566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
10879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
10889566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
10899566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
10909566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
10919566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1092aed4548fSBarry 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);
1093aed4548fSBarry 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);
109426fbe8dcSKarl Rupp 
109506a1af2fSStefano Zampini   /* do not increase object state */
10963ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
109706a1af2fSStefano Zampini 
10989566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
10999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11000782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11019566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11029566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
110306a1af2fSStefano Zampini   A->nonzerostate++;
11043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11050782ca92SJed Brown }
11060782ca92SJed Brown 
11079ba0d327SJed Brown /*@
110811a5261eSBarry Smith  MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11090782ca92SJed Brown 
11102ef1f0ffSBarry Smith  Logically Collective
11110782ca92SJed Brown 
11120782ca92SJed Brown  Input Parameters:
111311a5261eSBarry Smith +   A  - `MATNEST` matrix
11140782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
11150782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
11162ef1f0ffSBarry Smith -   sub - matrix at index `idxm`, `jdxm` within the nest matrix
11172ef1f0ffSBarry Smith 
11182ef1f0ffSBarry Smith  Level: developer
11190782ca92SJed Brown 
11200782ca92SJed Brown  Notes:
11210782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
11220782ca92SJed Brown 
11230782ca92SJed Brown  This increments the reference count of the submatrix.
11240782ca92SJed Brown 
1125*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1126db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11270782ca92SJed Brown @*/
1128d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1129d71ae5a4SJacob Faibussowitsch {
11300782ca92SJed Brown   PetscFunctionBegin;
1131cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11330782ca92SJed Brown }
11340782ca92SJed Brown 
1135d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1136d71ae5a4SJacob Faibussowitsch {
1137d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11385fd66863SKarl Rupp 
1139d8588912SDave May   PetscFunctionBegin;
114026fbe8dcSKarl Rupp   if (M) *M = bA->nr;
114126fbe8dcSKarl Rupp   if (N) *N = bA->nc;
114226fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1144d8588912SDave May }
1145d8588912SDave May 
1146d8588912SDave May /*@C
114711a5261eSBarry Smith  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1148d8588912SDave May 
11492ef1f0ffSBarry Smith  Not Collective
1150d8588912SDave May 
1151f899ff85SJose E. Roman  Input Parameter:
1152629881c0SJed Brown .   A  - nest matrix
1153d8588912SDave May 
1154d8d19677SJose E. Roman  Output Parameters:
1155629881c0SJed Brown +   M - number of rows in the nest matrix
1156d8588912SDave May .   N - number of cols in the nest matrix
1157629881c0SJed Brown -   mat - 2d array of matrices
1158d8588912SDave May 
11592ef1f0ffSBarry Smith  Level: developer
11602ef1f0ffSBarry Smith 
116111a5261eSBarry Smith  Note:
11622ef1f0ffSBarry Smith  The user should not free the array `mat`.
1163d8588912SDave May 
116411a5261eSBarry Smith  Fortran Note:
116511a5261eSBarry Smith  This routine has a calling sequence
1166351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
116720f4b53cSBarry Smith  where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1168351962e3SVincent Le Chenadec 
1169*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1170db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1171d8588912SDave May @*/
1172d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1173d71ae5a4SJacob Faibussowitsch {
1174d8588912SDave May   PetscFunctionBegin;
1175cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
11763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1177d8588912SDave May }
1178d8588912SDave May 
1179d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1180d71ae5a4SJacob Faibussowitsch {
1181d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1182d8588912SDave May 
1183d8588912SDave May   PetscFunctionBegin;
118426fbe8dcSKarl Rupp   if (M) *M = bA->nr;
118526fbe8dcSKarl Rupp   if (N) *N = bA->nc;
11863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1187d8588912SDave May }
1188d8588912SDave May 
11899ba0d327SJed Brown /*@
119011a5261eSBarry Smith  MatNestGetSize - Returns the size of the `MATNEST` matrix.
1191d8588912SDave May 
11922ef1f0ffSBarry Smith  Not Collective
1193d8588912SDave May 
1194f899ff85SJose E. Roman  Input Parameter:
119511a5261eSBarry Smith .   A  - `MATNEST` matrix
1196d8588912SDave May 
1197d8d19677SJose E. Roman  Output Parameters:
1198629881c0SJed Brown +   M - number of rows in the nested mat
1199629881c0SJed Brown -   N - number of cols in the nested mat
1200d8588912SDave May 
1201d8588912SDave May  Level: developer
1202d8588912SDave May 
1203*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1204db781477SPatrick Sanan           `MatNestGetISs()`
1205d8588912SDave May @*/
1206d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1207d71ae5a4SJacob Faibussowitsch {
1208d8588912SDave May   PetscFunctionBegin;
1209cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1211d8588912SDave May }
1212d8588912SDave May 
1213d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1214d71ae5a4SJacob Faibussowitsch {
1215900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1216900e7ff2SJed Brown   PetscInt  i;
1217900e7ff2SJed Brown 
1218900e7ff2SJed Brown   PetscFunctionBegin;
12199371c9d4SSatish Balay   if (rows)
12209371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12219371c9d4SSatish Balay   if (cols)
12229371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1224900e7ff2SJed Brown }
1225900e7ff2SJed Brown 
12263a4d7b9aSSatish Balay /*@C
122711a5261eSBarry Smith  MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1228900e7ff2SJed Brown 
12292ef1f0ffSBarry Smith  Not Collective
1230900e7ff2SJed Brown 
1231f899ff85SJose E. Roman  Input Parameter:
123211a5261eSBarry Smith .   A  - `MATNEST` matrix
1233900e7ff2SJed Brown 
1234d8d19677SJose E. Roman  Output Parameters:
1235900e7ff2SJed Brown +   rows - array of row index sets
1236900e7ff2SJed Brown -   cols - array of column index sets
1237900e7ff2SJed Brown 
1238900e7ff2SJed Brown  Level: advanced
1239900e7ff2SJed Brown 
124011a5261eSBarry Smith  Note:
12412ef1f0ffSBarry Smith  The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1242900e7ff2SJed Brown 
1243*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`,
1244db781477SPatrick Sanan           `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()`
1245900e7ff2SJed Brown @*/
1246d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1247d71ae5a4SJacob Faibussowitsch {
1248900e7ff2SJed Brown   PetscFunctionBegin;
1249900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1250cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1252900e7ff2SJed Brown }
1253900e7ff2SJed Brown 
1254d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1255d71ae5a4SJacob Faibussowitsch {
1256900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1257900e7ff2SJed Brown   PetscInt  i;
1258900e7ff2SJed Brown 
1259900e7ff2SJed Brown   PetscFunctionBegin;
12609371c9d4SSatish Balay   if (rows)
12619371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12629371c9d4SSatish Balay   if (cols)
12639371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
12643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1265900e7ff2SJed Brown }
1266900e7ff2SJed Brown 
1267900e7ff2SJed Brown /*@C
126811a5261eSBarry Smith  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1269900e7ff2SJed Brown 
12702ef1f0ffSBarry Smith  Not Collective
1271900e7ff2SJed Brown 
1272f899ff85SJose E. Roman  Input Parameter:
127311a5261eSBarry Smith .   A  - `MATNEST` matrix
1274900e7ff2SJed Brown 
1275d8d19677SJose E. Roman  Output Parameters:
12762ef1f0ffSBarry Smith +   rows - array of row index sets (or `NULL` to ignore)
12772ef1f0ffSBarry Smith -   cols - array of column index sets (or `NULL` to ignore)
1278900e7ff2SJed Brown 
1279900e7ff2SJed Brown  Level: advanced
1280900e7ff2SJed Brown 
128111a5261eSBarry Smith  Note:
12822ef1f0ffSBarry Smith  The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1283900e7ff2SJed Brown 
1284*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1285db781477SPatrick Sanan           `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()`
1286900e7ff2SJed Brown @*/
1287d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1288d71ae5a4SJacob Faibussowitsch {
1289900e7ff2SJed Brown   PetscFunctionBegin;
1290900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1291cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1293900e7ff2SJed Brown }
1294900e7ff2SJed Brown 
1295d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1296d71ae5a4SJacob Faibussowitsch {
1297207556f9SJed Brown   PetscBool flg;
1298207556f9SJed Brown 
1299207556f9SJed Brown   PetscFunctionBegin;
13009566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1301207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13022a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
130312b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
13043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1305207556f9SJed Brown }
1306207556f9SJed Brown 
1307207556f9SJed Brown /*@C
130811a5261eSBarry Smith  MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1309207556f9SJed Brown 
13102ef1f0ffSBarry Smith  Not Collective
1311207556f9SJed Brown 
1312207556f9SJed Brown  Input Parameters:
131311a5261eSBarry Smith +  A  - `MATNEST` matrix
131411a5261eSBarry Smith -  vtype - `VecType` to use for creating vectors
1315207556f9SJed Brown 
1316207556f9SJed Brown  Level: developer
1317207556f9SJed Brown 
1318*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MATNEST`, `MatCreateNest()`, `VecType`
1319207556f9SJed Brown @*/
1320d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1321d71ae5a4SJacob Faibussowitsch {
1322207556f9SJed Brown   PetscFunctionBegin;
1323cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1325207556f9SJed Brown }
1326207556f9SJed Brown 
1327d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1328d71ae5a4SJacob Faibussowitsch {
1329c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1330c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
133188ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
133288ffe2e8SJose E. Roman   VecType   vtype, type;
1333d8588912SDave May 
1334d8588912SDave May   PetscFunctionBegin;
13359566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
133606a1af2fSStefano Zampini 
1337c8883902SJed Brown   s->nr = nr;
1338c8883902SJed Brown   s->nc = nc;
1339d8588912SDave May 
1340c8883902SJed Brown   /* Create space for submatrices */
13419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
134248a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i]));
1343c8883902SJed Brown   for (i = 0; i < nr; i++) {
1344c8883902SJed Brown     for (j = 0; j < nc; j++) {
1345c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
134648a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1347d8588912SDave May     }
1348d8588912SDave May   }
13499566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13509566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
135188ffe2e8SJose E. Roman   if (isstd) {
135288ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
135388ffe2e8SJose E. Roman     vtype = NULL;
135488ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
135588ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
135688ffe2e8SJose E. Roman         if (a[i * nc + j]) {
135788ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13589566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
135988ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
136088ffe2e8SJose E. Roman           } else if (sametype) {
13619566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13629566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
136388ffe2e8SJose E. Roman           }
136488ffe2e8SJose E. Roman         }
136588ffe2e8SJose E. Roman       }
136688ffe2e8SJose E. Roman     }
136788ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13689566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
136988ffe2e8SJose E. Roman     }
137088ffe2e8SJose E. Roman   }
1371d8588912SDave May 
13729566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1373d8588912SDave May 
13749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
13759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1376c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1377c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1378d8588912SDave May 
13799566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
138006a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
138106a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
138248a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
138306a1af2fSStefano Zampini     }
138406a1af2fSStefano Zampini   }
138506a1af2fSStefano Zampini 
13869566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1387d8588912SDave May 
13889566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
13899566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
13909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
13919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1392c8883902SJed Brown 
13939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
13949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1395c8883902SJed Brown 
139606a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
139706a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
13989566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
139906a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
140006a1af2fSStefano Zampini   if (cong) {
140148a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
140206a1af2fSStefano Zampini   }
140306a1af2fSStefano Zampini   if (!cong) {
1404381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
140506a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
140606a1af2fSStefano Zampini     A->ops->shift           = NULL;
140706a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
140806a1af2fSStefano Zampini   }
140906a1af2fSStefano Zampini 
14109566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14119566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
141206a1af2fSStefano Zampini   A->nonzerostate++;
14133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1414d8588912SDave May }
1415d8588912SDave May 
1416c8883902SJed Brown /*@
141711a5261eSBarry Smith    MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1418c8883902SJed Brown 
1419c3339decSBarry Smith    Collective
1420c8883902SJed Brown 
1421d8d19677SJose E. Roman    Input Parameters:
142211a5261eSBarry Smith +  A - `MATNEST` matrix
1423c8883902SJed Brown .  nr - number of nested row blocks
14242ef1f0ffSBarry Smith .  is_row - index sets for each nested row block, or `NULL` to make contiguous
1425c8883902SJed Brown .  nc - number of nested column blocks
14262ef1f0ffSBarry Smith .  is_col - index sets for each nested column block, or `NULL` to make contiguous
14272ef1f0ffSBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL`
14282ef1f0ffSBarry Smith 
14292ef1f0ffSBarry Smith    Level: advanced
1430c8883902SJed Brown 
143111a5261eSBarry Smith    Note:
143211a5261eSBarry Smith    This always resets any submatrix information previously set
143306a1af2fSStefano Zampini 
1434*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1435c8883902SJed Brown @*/
1436d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1437d71ae5a4SJacob Faibussowitsch {
143806a1af2fSStefano Zampini   PetscInt i;
1439c8883902SJed Brown 
1440c8883902SJed Brown   PetscFunctionBegin;
1441c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
144208401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1443c8883902SJed Brown   if (nr && is_row) {
1444c8883902SJed Brown     PetscValidPointer(is_row, 3);
1445c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1446c8883902SJed Brown   }
144708401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14481664e352SJed Brown   if (nc && is_col) {
1449c8883902SJed Brown     PetscValidPointer(is_col, 5);
14509b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1451c8883902SJed Brown   }
145206a1af2fSStefano Zampini   if (nr * nc > 0) PetscValidPointer(a, 6);
1453cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1455c8883902SJed Brown }
1456d8588912SDave May 
1457d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1458d71ae5a4SJacob Faibussowitsch {
145977019fcaSJed Brown   PetscBool flg;
146077019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
146177019fcaSJed Brown 
146277019fcaSJed Brown   PetscFunctionBegin;
1463aea6d515SStefano Zampini   *ltog = NULL;
146477019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
146577019fcaSJed Brown     if (islocal[i]) {
14669566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
146777019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
146877019fcaSJed Brown     } else {
14699566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
147077019fcaSJed Brown     }
147177019fcaSJed Brown     m += mi;
147277019fcaSJed Brown   }
14733ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1474aea6d515SStefano Zampini 
14759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1476165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
14770298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1478e108cb99SStefano Zampini     Mat                    sub  = NULL;
1479f6d38dbbSStefano Zampini     PetscSF                sf;
1480f6d38dbbSStefano Zampini     PetscLayout            map;
1481aea6d515SStefano Zampini     const PetscInt        *ix2;
148277019fcaSJed Brown 
1483165cd838SBarry Smith     if (!colflg) {
14849566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
148577019fcaSJed Brown     } else {
14869566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
148777019fcaSJed Brown     }
1488191fd14bSBarry Smith     if (sub) {
1489191fd14bSBarry Smith       if (!colflg) {
14909566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1491191fd14bSBarry Smith       } else {
14929566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1493191fd14bSBarry Smith       }
1494191fd14bSBarry Smith     }
149577019fcaSJed Brown     /*
149677019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
149777019fcaSJed 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.
149877019fcaSJed Brown     */
14999566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1500aea6d515SStefano Zampini     if (islocal[i]) {
1501aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1502aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1503aea6d515SStefano Zampini 
15049566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150528b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1506aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15079566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1508aea6d515SStefano Zampini 
1509aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15109566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1511aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1512aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1513aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1514aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1515aea6d515SStefano Zampini         nleaves++;
1516aea6d515SStefano Zampini       }
15179566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15189566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15199566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15209566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15219566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15229566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15239566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15269566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15279566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1528aea6d515SStefano Zampini     } else {
15299566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1530aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1531aea6d515SStefano Zampini     }
15329566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
153377019fcaSJed Brown     m += mi;
153477019fcaSJed Brown   }
15359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153777019fcaSJed Brown }
153877019fcaSJed Brown 
1539d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1540d8588912SDave May /*
1541d8588912SDave May   nprocessors = NP
1542d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1543d8588912SDave May        proc 0: => (g_0,h_0,)
1544d8588912SDave May        proc 1: => (g_1,h_1,)
1545d8588912SDave May        ...
1546d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1547d8588912SDave May 
1548d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1549d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1550d8588912SDave May 
1551d8588912SDave May             proc 0:
1552d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1553d8588912SDave May             proc 1:
1554d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1555d8588912SDave May 
1556d8588912SDave May             proc NP-1:
1557d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1558d8588912SDave May */
1559d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1560d71ae5a4SJacob Faibussowitsch {
1561e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15628188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15630298fd71SBarry Smith   Mat       sub = NULL;
1564d8588912SDave May 
1565d8588912SDave May   PetscFunctionBegin;
15669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
15679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1568d8588912SDave May   if (is_row) { /* valid IS is passed in */
1569a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1570e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15719566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
157226fbe8dcSKarl Rupp 
1573e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1574d8588912SDave May     }
15752ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
15768188e55aSJed Brown     nsum = 0;
15778188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
15789566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
157928b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
15809566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
158108401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15828188e55aSJed Brown       nsum += n;
15838188e55aSJed Brown     }
15849566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
158530bc264bSJed Brown     offset -= nsum;
1586e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15879566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15889566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
15899566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15909566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
15919566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
15922ae74bdbSJed Brown       offset += n;
1593d8588912SDave May     }
1594d8588912SDave May   }
1595d8588912SDave May 
1596d8588912SDave May   if (is_col) { /* valid IS is passed in */
1597a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1598e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
15999566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
160026fbe8dcSKarl Rupp 
1601e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1602d8588912SDave May     }
16032ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16042ae74bdbSJed Brown     offset = A->cmap->rstart;
16058188e55aSJed Brown     nsum   = 0;
16068188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16079566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
160828b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16099566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
161008401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16118188e55aSJed Brown       nsum += n;
16128188e55aSJed Brown     }
16139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
161430bc264bSJed Brown     offset -= nsum;
1615e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16169566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16179566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16189566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16199566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16209566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16212ae74bdbSJed Brown       offset += n;
1622d8588912SDave May     }
1623d8588912SDave May   }
1624e2d7f03fSJed Brown 
1625e2d7f03fSJed Brown   /* Set up the local ISs */
16269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1628e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1629e2d7f03fSJed Brown     IS                     isloc;
16300298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1631e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16329566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16339566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1634207556f9SJed Brown     if (rmap) {
16359566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16369566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16379566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16389566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1639207556f9SJed Brown     } else {
1640207556f9SJed Brown       nlocal = 0;
16410298fd71SBarry Smith       isloc  = NULL;
1642207556f9SJed Brown     }
1643e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1644e2d7f03fSJed Brown     offset += nlocal;
1645e2d7f03fSJed Brown   }
16468188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1647e2d7f03fSJed Brown     IS                     isloc;
16480298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1649e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16509566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16519566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1652207556f9SJed Brown     if (cmap) {
16539566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16549566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16559566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16569566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1657207556f9SJed Brown     } else {
1658207556f9SJed Brown       nlocal = 0;
16590298fd71SBarry Smith       isloc  = NULL;
1660207556f9SJed Brown     }
1661e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1662e2d7f03fSJed Brown     offset += nlocal;
1663e2d7f03fSJed Brown   }
16640189643fSJed Brown 
166577019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
166677019fcaSJed Brown   {
166745b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
16689566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
16699566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
16709566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
16719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
16729566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
167377019fcaSJed Brown   }
167477019fcaSJed Brown 
167576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
16760189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
16770189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
16780189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
16790189643fSJed Brown         Mat      B = vs->m[i][j];
16800189643fSJed Brown         if (!B) continue;
16819566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
16829566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
16839566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
16849566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
16859566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
16869566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1687aed4548fSBarry 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);
1688aed4548fSBarry 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);
16890189643fSJed Brown       }
16900189643fSJed Brown     }
169176bd3646SJed Brown   }
1692a061e289SJed Brown 
1693a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1694a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1695a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
16963ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1697a061e289SJed Brown     }
1698a061e289SJed Brown   }
1699a061e289SJed Brown   A->assembled = PETSC_TRUE;
17003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1701d8588912SDave May }
1702d8588912SDave May 
170345c38901SJed Brown /*@C
170411a5261eSBarry Smith    MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1705659c6bb0SJed Brown 
170611a5261eSBarry Smith    Collective
1707659c6bb0SJed Brown 
1708d8d19677SJose E. Roman    Input Parameters:
170911a5261eSBarry Smith +  comm - Communicator for the new `MATNEST`
1710659c6bb0SJed Brown .  nr - number of nested row blocks
17112ef1f0ffSBarry Smith .  is_row - index sets for each nested row block, or `NULL` to make contiguous
1712659c6bb0SJed Brown .  nc - number of nested column blocks
17132ef1f0ffSBarry Smith .  is_col - index sets for each nested column block, or `NULL` to make contiguous
17142ef1f0ffSBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1715659c6bb0SJed Brown 
1716659c6bb0SJed Brown    Output Parameter:
1717659c6bb0SJed Brown .  B - new matrix
1718659c6bb0SJed Brown 
1719659c6bb0SJed Brown    Level: advanced
1720659c6bb0SJed Brown 
1721*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1722db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1723db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1724659c6bb0SJed Brown @*/
1725d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1726d71ae5a4SJacob Faibussowitsch {
1727d8588912SDave May   Mat A;
1728d8588912SDave May 
1729d8588912SDave May   PetscFunctionBegin;
1730f4259b30SLisandro Dalcin   *B = NULL;
17319566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17329566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
173391a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17349566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1735d8588912SDave May   *B = A;
17363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1737d8588912SDave May }
1738659c6bb0SJed Brown 
1739d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1740d71ae5a4SJacob Faibussowitsch {
1741b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
174223875855Sstefano_zampini   Mat          *trans;
1743b68353e5Sstefano_zampini   PetscScalar **avv;
1744b68353e5Sstefano_zampini   PetscScalar  *vv;
1745b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1746b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1747b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1748b68353e5Sstefano_zampini   PetscBool     done;
1749b68353e5Sstefano_zampini 
1750b68353e5Sstefano_zampini   PetscFunctionBegin;
17519566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1752b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1753b68353e5Sstefano_zampini     PetscInt rnr;
1754b68353e5Sstefano_zampini 
17559566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
175628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
175708401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
17589566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1759b68353e5Sstefano_zampini   }
1760b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1761b68353e5Sstefano_zampini   nnz = 0;
17629566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1763b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1764b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1765b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1766b68353e5Sstefano_zampini       if (B) {
1767b68353e5Sstefano_zampini         PetscScalar *naa;
1768b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
176923875855Sstefano_zampini         PetscBool    istrans;
1770b68353e5Sstefano_zampini 
1771013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
177223875855Sstefano_zampini         if (istrans) {
177323875855Sstefano_zampini           Mat Bt;
177423875855Sstefano_zampini 
17759566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
17769566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
177723875855Sstefano_zampini           B = trans[i * nest->nc + j];
1778013e2dc7SBarry Smith         } else {
1779013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1780013e2dc7SBarry Smith           if (istrans) {
1781013e2dc7SBarry Smith             Mat Bt;
1782013e2dc7SBarry Smith 
1783013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1784013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1785013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1786013e2dc7SBarry Smith           }
178723875855Sstefano_zampini         }
17889566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
178928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
17909566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1791b68353e5Sstefano_zampini         nnz += nii[nnr];
1792b68353e5Sstefano_zampini 
1793b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1794b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1795b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1796b68353e5Sstefano_zampini       }
1797b68353e5Sstefano_zampini     }
1798b68353e5Sstefano_zampini   }
1799b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1803b68353e5Sstefano_zampini   } else {
180408401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1805b68353e5Sstefano_zampini   }
1806b68353e5Sstefano_zampini 
1807b68353e5Sstefano_zampini   /* new row pointer */
18089566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1809b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1810b68353e5Sstefano_zampini     PetscInt ncr, rst;
1811b68353e5Sstefano_zampini 
18129566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18139566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1814b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1815b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1816b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1817b68353e5Sstefano_zampini         PetscInt  ir;
1818b68353e5Sstefano_zampini 
1819b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1820b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1821b68353e5Sstefano_zampini           nii++;
1822b68353e5Sstefano_zampini         }
1823b68353e5Sstefano_zampini       }
1824b68353e5Sstefano_zampini     }
1825b68353e5Sstefano_zampini   }
1826b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1827b68353e5Sstefano_zampini 
1828b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18299566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1830b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1831b68353e5Sstefano_zampini     PetscInt ncr, rst;
1832b68353e5Sstefano_zampini 
18339566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18349566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1835b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1836b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1837b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1838b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1839b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1840b68353e5Sstefano_zampini         PetscInt     ir, cst;
1841b68353e5Sstefano_zampini 
18429566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1843b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1844b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1845b68353e5Sstefano_zampini 
1846b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1847b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1848b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1849b68353e5Sstefano_zampini             njj++;
1850b68353e5Sstefano_zampini             nvv++;
1851b68353e5Sstefano_zampini           }
1852b68353e5Sstefano_zampini           ci[ir] += rsize;
1853b68353e5Sstefano_zampini           nii++;
1854b68353e5Sstefano_zampini         }
1855b68353e5Sstefano_zampini       }
1856b68353e5Sstefano_zampini     }
1857b68353e5Sstefano_zampini   }
18589566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1859b68353e5Sstefano_zampini 
1860b68353e5Sstefano_zampini   /* restore info */
1861b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1862b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1863b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1864b68353e5Sstefano_zampini       if (B) {
1865b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
186623875855Sstefano_zampini 
186723875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
18689566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
186928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
18709566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
18719566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1872b68353e5Sstefano_zampini       }
1873b68353e5Sstefano_zampini     }
1874b68353e5Sstefano_zampini   }
18759566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1876b68353e5Sstefano_zampini 
1877b68353e5Sstefano_zampini   /* finalize newmat */
1878b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
18799566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1880b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1881b68353e5Sstefano_zampini     Mat B;
1882b68353e5Sstefano_zampini 
18839566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
18849566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1885b68353e5Sstefano_zampini   }
18869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
18879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1888b68353e5Sstefano_zampini   {
1889b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1890b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1891b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1892b68353e5Sstefano_zampini   }
18933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1894b68353e5Sstefano_zampini }
1895b68353e5Sstefano_zampini 
1896d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1897d71ae5a4SJacob Faibussowitsch {
1898be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1899be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1900be705e3aSPierre Jolivet   PetscBool flg;
1901be705e3aSPierre Jolivet 
1902be705e3aSPierre Jolivet   PetscFunctionBegin;
1903be705e3aSPierre Jolivet   /* Fill by row */
1904be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1905be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1906be705e3aSPierre Jolivet     IS              bNis;
1907be705e3aSPierre Jolivet     PetscInt        bN;
1908be705e3aSPierre Jolivet     const PetscInt *bNindices;
19099566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19109566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19119566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1912be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1913fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1914be705e3aSPierre Jolivet       PetscInt        bm, br;
1915be705e3aSPierre Jolivet       const PetscInt *bmindices;
1916be705e3aSPierre Jolivet       if (!B) continue;
1917013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1918be705e3aSPierre Jolivet       if (flg) {
1919cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1920cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19219566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1922be705e3aSPierre Jolivet         B = D;
1923be705e3aSPierre Jolivet       }
19249566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1925be705e3aSPierre Jolivet       if (flg) {
1926fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1927fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1928be705e3aSPierre Jolivet         B = D;
1929be705e3aSPierre Jolivet       }
19309566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19319566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19329566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1933be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1934be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1935be705e3aSPierre Jolivet         const PetscInt    *brcols;
1936be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1937be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19389566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19399566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1940be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1941be705e3aSPierre Jolivet         /*
1942be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1943be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1944be705e3aSPierre Jolivet          */
1945be705e3aSPierre Jolivet         if (a != 1.0) {
19469566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1947be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19489566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19499566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1950be705e3aSPierre Jolivet         } else {
19519566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1952be705e3aSPierre Jolivet         }
19539566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19549566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1955be705e3aSPierre Jolivet       }
1956fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19579566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1958be705e3aSPierre Jolivet     }
19599566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
19609566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1961be705e3aSPierre Jolivet   }
19629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
19639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
19643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1965be705e3aSPierre Jolivet }
1966be705e3aSPierre Jolivet 
1967d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1968d71ae5a4SJacob Faibussowitsch {
1969629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
1970be705e3aSPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz, rstart, cstart, cend;
1971b68353e5Sstefano_zampini   PetscMPIInt size;
1972629c3df2SDmitry Karpeev   Mat         C;
1973629c3df2SDmitry Karpeev 
1974629c3df2SDmitry Karpeev   PetscFunctionBegin;
19759566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1976b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1977b68353e5Sstefano_zampini     PetscInt  nf;
1978b68353e5Sstefano_zampini     PetscBool fast;
1979b68353e5Sstefano_zampini 
19809566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
198148a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
1982b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
1983b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
1984b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1985b68353e5Sstefano_zampini         if (B) {
19869566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
198723875855Sstefano_zampini           if (!fast) {
198823875855Sstefano_zampini             PetscBool istrans;
198923875855Sstefano_zampini 
1990013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
199123875855Sstefano_zampini             if (istrans) {
199223875855Sstefano_zampini               Mat Bt;
199323875855Sstefano_zampini 
19949566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
19959566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1996013e2dc7SBarry Smith             } else {
1997013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1998013e2dc7SBarry Smith               if (istrans) {
1999013e2dc7SBarry Smith                 Mat Bt;
2000013e2dc7SBarry Smith 
2001013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2002013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2003013e2dc7SBarry Smith               }
200423875855Sstefano_zampini             }
2005b68353e5Sstefano_zampini           }
2006b68353e5Sstefano_zampini         }
2007b68353e5Sstefano_zampini       }
2008b68353e5Sstefano_zampini     }
2009b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20109566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2011b68353e5Sstefano_zampini       if (fast) {
2012b68353e5Sstefano_zampini         PetscInt f, s;
2013b68353e5Sstefano_zampini 
20149566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20159371c9d4SSatish Balay         if (f != nf || s != 1) {
20169371c9d4SSatish Balay           fast = PETSC_FALSE;
20179371c9d4SSatish Balay         } else {
20189566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2019b68353e5Sstefano_zampini           nf += f;
2020b68353e5Sstefano_zampini         }
2021b68353e5Sstefano_zampini       }
2022b68353e5Sstefano_zampini     }
2023b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20249566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2025b68353e5Sstefano_zampini       if (fast) {
2026b68353e5Sstefano_zampini         PetscInt f, s;
2027b68353e5Sstefano_zampini 
20289566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20299371c9d4SSatish Balay         if (f != nf || s != 1) {
20309371c9d4SSatish Balay           fast = PETSC_FALSE;
20319371c9d4SSatish Balay         } else {
20329566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2033b68353e5Sstefano_zampini           nf += f;
2034b68353e5Sstefano_zampini         }
2035b68353e5Sstefano_zampini       }
2036b68353e5Sstefano_zampini     }
2037b68353e5Sstefano_zampini     if (fast) {
20389566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20393ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2040b68353e5Sstefano_zampini     }
2041b68353e5Sstefano_zampini   }
20429566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20439566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20449566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2045d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2046d1487292SPierre Jolivet   else {
20479566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20489566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20499566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2050629c3df2SDmitry Karpeev   }
20519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2052629c3df2SDmitry Karpeev   onnz = dnnz + m;
2053629c3df2SDmitry Karpeev   for (k = 0; k < m; k++) {
2054629c3df2SDmitry Karpeev     dnnz[k] = 0;
2055629c3df2SDmitry Karpeev     onnz[k] = 0;
2056629c3df2SDmitry Karpeev   }
2057629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2058629c3df2SDmitry Karpeev     IS              bNis;
2059629c3df2SDmitry Karpeev     PetscInt        bN;
2060629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2061fd8a7442SPierre Jolivet     PetscBool       flg;
2062629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20639566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20649566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2066629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2067629c3df2SDmitry Karpeev       PetscSF         bmsf;
2068649b366bSFande Kong       PetscSFNode    *iremote;
2069fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2070649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2071629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2072629c3df2SDmitry Karpeev       if (!B) continue;
20739566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20749566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20759566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
20769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
20779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
20789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2079649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2080649b366bSFande Kong         sub_dnnz[k] = 0;
2081649b366bSFande Kong         sub_onnz[k] = 0;
2082649b366bSFande Kong       }
2083dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2084fd8a7442SPierre Jolivet       if (flg) {
2085fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2086fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2087fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2088fd8a7442SPierre Jolivet         B = D;
2089fd8a7442SPierre Jolivet       }
2090fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2091fd8a7442SPierre Jolivet       if (flg) {
2092fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2093fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2094fd8a7442SPierre Jolivet         B = D;
2095fd8a7442SPierre Jolivet       }
2096629c3df2SDmitry Karpeev       /*
2097629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2098629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2099629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2100629c3df2SDmitry Karpeev        */
21019566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2102629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2103131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2104629c3df2SDmitry Karpeev         const PetscInt *brcols;
2105a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2106131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21079566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2108649b366bSFande Kong         /* how many roots  */
21099371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21109371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2111649b366bSFande Kong         /* get nonzero pattern */
21129566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2113629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2114629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2115649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2116649b366bSFande Kong             sub_dnnz[br]++;
2117649b366bSFande Kong           } else {
2118649b366bSFande Kong             sub_onnz[br]++;
2119649b366bSFande Kong           }
2120629c3df2SDmitry Karpeev         }
21219566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2122629c3df2SDmitry Karpeev       }
2123fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21249566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2125629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21269566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21279566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21289566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21299566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21309566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21319566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21329566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21339566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2134629c3df2SDmitry Karpeev     }
21359566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
213765a4a0a3Sstefano_zampini   }
213865a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
213965a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
214065a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
214165a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2142629c3df2SDmitry Karpeev   }
21439566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21449566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21459566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21469566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2147d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21489566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2149d1487292SPierre Jolivet   } else *newmat = C;
21503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2151be705e3aSPierre Jolivet }
2152629c3df2SDmitry Karpeev 
2153d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2154d71ae5a4SJacob Faibussowitsch {
2155629c3df2SDmitry Karpeev   Mat      B;
2156be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2157be705e3aSPierre Jolivet 
2158be705e3aSPierre Jolivet   PetscFunctionBegin;
21599566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
21609566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2161be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2162be705e3aSPierre Jolivet     B = *newmat;
21639566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2164be705e3aSPierre Jolivet   } else {
21659566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2166629c3df2SDmitry Karpeev   }
21679566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2168be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21699566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2170be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
21713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2172629c3df2SDmitry Karpeev }
2173629c3df2SDmitry Karpeev 
2174d71ae5a4SJacob Faibussowitsch PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2175d71ae5a4SJacob Faibussowitsch {
21768b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
21773c6db4c4SPierre Jolivet   MatOperation opAdd;
21788b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
21798b7d3b4bSBarry Smith   PetscBool    flg;
218052c5f739Sprj-   PetscFunctionBegin;
21818b7d3b4bSBarry Smith 
218252c5f739Sprj-   *has = PETSC_FALSE;
21833c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21843c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21858b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
21868b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
21878b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21889566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
21893ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
21908b7d3b4bSBarry Smith       }
21918b7d3b4bSBarry Smith     }
21928b7d3b4bSBarry Smith   }
21933c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
21943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21958b7d3b4bSBarry Smith }
21968b7d3b4bSBarry Smith 
2197659c6bb0SJed Brown /*MC
21982ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2199659c6bb0SJed Brown 
2200659c6bb0SJed Brown   Level: intermediate
2201659c6bb0SJed Brown 
2202659c6bb0SJed Brown   Notes:
220311a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2204659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
220511a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2206659c6bb0SJed Brown 
22078b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22088b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22098b7d3b4bSBarry Smith   than the nest matrix.
22108b7d3b4bSBarry Smith 
2211*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2212db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2213db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2214659c6bb0SJed Brown M*/
2215d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2216d71ae5a4SJacob Faibussowitsch {
2217c8883902SJed Brown   Mat_Nest *s;
2218c8883902SJed Brown 
2219c8883902SJed Brown   PetscFunctionBegin;
22204dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2221c8883902SJed Brown   A->data = (void *)s;
2222e7c19651SJed Brown 
2223e7c19651SJed Brown   s->nr            = -1;
2224e7c19651SJed Brown   s->nc            = -1;
22250298fd71SBarry Smith   s->m             = NULL;
2226e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2227c8883902SJed Brown 
22289566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
222926fbe8dcSKarl Rupp 
2230c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22319194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2232c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22339194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2234f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2235c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2236c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2237c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2238c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22396e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2240c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22417dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2242c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2243c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2244f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2245c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2246c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2247429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2248429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2249a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2250a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
225113135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2252f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22538b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2254381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2255c8883902SJed Brown 
2256f4259b30SLisandro Dalcin   A->spptr     = NULL;
2257c8883902SJed Brown   A->assembled = PETSC_FALSE;
2258c8883902SJed Brown 
2259c8883902SJed Brown   /* expose Nest api's */
22609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
22619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
22629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
22639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
22649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
22659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
22669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
22679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
22689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
22709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
22719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
22729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
22749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
22759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense));
2277c8883902SJed Brown 
22789566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
22793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2280c8883902SJed Brown }
2281