xref: /petsc/src/mat/impls/nest/matnest.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
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   }
33d8588912SDave May   PetscFunctionReturn(0);
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]));
56d8588912SDave May   PetscFunctionReturn(0);
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]));
839194d70fSJed Brown   PetscFunctionReturn(0);
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));
1106718818eSStefano Zampini     PetscFunctionReturn(0);
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));
15052c5f739Sprj-   PetscFunctionReturn(0);
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));
16352c5f739Sprj-   PetscFunctionReturn(0);
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;
2006718818eSStefano Zampini     PetscFunctionReturn(0);
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;
24752c5f739Sprj-   PetscFunctionReturn(0);
24852c5f739Sprj- }
24952c5f739Sprj- 
2504222ddf1SHong Zhang /* --------------------------------------------------------- */
251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
252d71ae5a4SJacob Faibussowitsch {
2534222ddf1SHong Zhang   PetscFunctionBegin;
2546718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2554222ddf1SHong Zhang   PetscFunctionReturn(0);
2564222ddf1SHong Zhang }
2574222ddf1SHong Zhang 
258d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
259d71ae5a4SJacob Faibussowitsch {
2604222ddf1SHong Zhang   Mat_Product *product = C->product;
26152c5f739Sprj- 
26252c5f739Sprj-   PetscFunctionBegin;
26348a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
26452c5f739Sprj-   PetscFunctionReturn(0);
26552c5f739Sprj- }
2664222ddf1SHong Zhang /* --------------------------------------------------------- */
26752c5f739Sprj- 
268d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
269d71ae5a4SJacob Faibussowitsch {
270d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
271207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
272207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
273d8588912SDave May 
274d8588912SDave May   PetscFunctionBegin;
2759566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2769566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
277207556f9SJed Brown   for (j = 0; j < nc; j++) {
2789566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
279609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2806c75ac25SJed Brown       if (!bA->m[i][j]) continue;
281609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2829566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));
283d8588912SDave May     }
284d8588912SDave May   }
2859566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2869566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
287d8588912SDave May   PetscFunctionReturn(0);
288d8588912SDave May }
289d8588912SDave May 
290d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
291d71ae5a4SJacob Faibussowitsch {
2929194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2939194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
2949194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
2959194d70fSJed Brown 
2969194d70fSJed Brown   PetscFunctionBegin;
2979566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2989566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
2999194d70fSJed Brown   for (j = 0; j < nc; j++) {
3009194d70fSJed Brown     if (y != z) {
3019194d70fSJed Brown       Vec by;
3029566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3039566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3049566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3059194d70fSJed Brown     }
3069194d70fSJed Brown     for (i = 0; i < nr; i++) {
3076c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3089194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3099566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));
3109194d70fSJed Brown     }
3119194d70fSJed Brown   }
3129566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3139566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3149194d70fSJed Brown   PetscFunctionReturn(0);
3159194d70fSJed Brown }
3169194d70fSJed Brown 
317d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
318d71ae5a4SJacob Faibussowitsch {
319f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
320f8170845SAlex Fikl   Mat       C;
321f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
322f8170845SAlex Fikl 
323f8170845SAlex Fikl   PetscFunctionBegin;
3247fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
325aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
326f8170845SAlex Fikl 
327cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
328f8170845SAlex Fikl     Mat *subs;
329f8170845SAlex Fikl     IS  *is_row, *is_col;
330f8170845SAlex Fikl 
3319566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3339566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
334cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
335ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
336ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
337ddeb9bd8SAlex Fikl       }
338ddeb9bd8SAlex Fikl     }
339ddeb9bd8SAlex Fikl 
3409566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3419566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3429566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
343f8170845SAlex Fikl   } else {
344f8170845SAlex Fikl     C = *B;
345f8170845SAlex Fikl   }
346f8170845SAlex Fikl 
347f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
348f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
349f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
350f8170845SAlex Fikl       if (bA->m[i][j]) {
3519566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
352f8170845SAlex Fikl       } else {
353f8170845SAlex Fikl         bC->m[j][i] = NULL;
354f8170845SAlex Fikl       }
355f8170845SAlex Fikl     }
356f8170845SAlex Fikl   }
357f8170845SAlex Fikl 
358cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
359f8170845SAlex Fikl     *B = C;
360f8170845SAlex Fikl   } else {
3619566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
362f8170845SAlex Fikl   }
363f8170845SAlex Fikl   PetscFunctionReturn(0);
364f8170845SAlex Fikl }
365f8170845SAlex Fikl 
366d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
367d71ae5a4SJacob Faibussowitsch {
368e2d7f03fSJed Brown   IS      *lst = *list;
369e2d7f03fSJed Brown   PetscInt i;
370e2d7f03fSJed Brown 
371e2d7f03fSJed Brown   PetscFunctionBegin;
372e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3739371c9d4SSatish Balay   for (i = 0; i < n; i++)
3749371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3759566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3760298fd71SBarry Smith   *list = NULL;
377e2d7f03fSJed Brown   PetscFunctionReturn(0);
378e2d7f03fSJed Brown }
379e2d7f03fSJed Brown 
380d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
381d71ae5a4SJacob Faibussowitsch {
382d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
383d8588912SDave May   PetscInt  i, j;
384d8588912SDave May 
385d8588912SDave May   PetscFunctionBegin;
386d8588912SDave May   /* release the matrices and the place holders */
3879566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
3889566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
3899566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
3909566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
391d8588912SDave May 
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
3939566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
3949566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
395d8588912SDave May 
3969566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
397207556f9SJed Brown 
398d8588912SDave May   /* release the matrices and the place holders */
399d8588912SDave May   if (vs->m) {
400d8588912SDave May     for (i = 0; i < vs->nr; i++) {
40148a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
4029566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
403d8588912SDave May     }
4049566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
405d8588912SDave May   }
40606a1af2fSStefano Zampini 
40706a1af2fSStefano Zampini   /* restore defaults */
40806a1af2fSStefano Zampini   vs->nr            = 0;
40906a1af2fSStefano Zampini   vs->nc            = 0;
41006a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
41106a1af2fSStefano Zampini   PetscFunctionReturn(0);
41206a1af2fSStefano Zampini }
41306a1af2fSStefano Zampini 
414d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
415d71ae5a4SJacob Faibussowitsch {
416362febeeSStefano Zampini   PetscFunctionBegin;
4179566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4189566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL));
436d8588912SDave May   PetscFunctionReturn(0);
437d8588912SDave May }
438d8588912SDave May 
439d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
440d71ae5a4SJacob Faibussowitsch {
441381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
442381b8e50SStefano Zampini   PetscInt  i;
443381b8e50SStefano Zampini 
444381b8e50SStefano Zampini   PetscFunctionBegin;
445381b8e50SStefano Zampini   if (dd) *dd = 0;
446381b8e50SStefano Zampini   if (!vs->nr) {
447381b8e50SStefano Zampini     *missing = PETSC_TRUE;
448381b8e50SStefano Zampini     PetscFunctionReturn(0);
449381b8e50SStefano Zampini   }
450381b8e50SStefano Zampini   *missing = PETSC_FALSE;
451381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
452381b8e50SStefano Zampini     *missing = PETSC_TRUE;
453381b8e50SStefano Zampini     if (vs->m[i][i]) {
4549566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
45508401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
456381b8e50SStefano Zampini     }
457381b8e50SStefano Zampini   }
458381b8e50SStefano Zampini   PetscFunctionReturn(0);
459381b8e50SStefano Zampini }
460381b8e50SStefano Zampini 
461d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
462d71ae5a4SJacob Faibussowitsch {
463d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
464d8588912SDave May   PetscInt  i, j;
46506a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
466d8588912SDave May 
467d8588912SDave May   PetscFunctionBegin;
468d8588912SDave May   for (i = 0; i < vs->nr; i++) {
469d8588912SDave May     for (j = 0; j < vs->nc; j++) {
47006a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
471e7c19651SJed Brown       if (vs->m[i][j]) {
4729566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
473e7c19651SJed Brown         if (!vs->splitassembly) {
474e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
475e7c19651SJed 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
476e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
477e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
478e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
479e7c19651SJed Brown            */
4809566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4819566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
482e7c19651SJed Brown         }
483e7c19651SJed Brown       }
48406a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
48506a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
486d8588912SDave May     }
487d8588912SDave May   }
48806a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
489d8588912SDave May   PetscFunctionReturn(0);
490d8588912SDave May }
491d8588912SDave May 
492d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
493d71ae5a4SJacob Faibussowitsch {
494d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
495d8588912SDave May   PetscInt  i, j;
496d8588912SDave May 
497d8588912SDave May   PetscFunctionBegin;
498d8588912SDave May   for (i = 0; i < vs->nr; i++) {
499d8588912SDave May     for (j = 0; j < vs->nc; j++) {
500e7c19651SJed Brown       if (vs->m[i][j]) {
50148a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
502e7c19651SJed Brown       }
503d8588912SDave May     }
504d8588912SDave May   }
505d8588912SDave May   PetscFunctionReturn(0);
506d8588912SDave May }
507d8588912SDave May 
508d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
509d71ae5a4SJacob Faibussowitsch {
510f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
511f349c1fdSJed Brown   PetscInt  j;
512f349c1fdSJed Brown   Mat       sub;
513d8588912SDave May 
514d8588912SDave May   PetscFunctionBegin;
5150298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
516f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5179566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
518f349c1fdSJed Brown   *B = sub;
519f349c1fdSJed Brown   PetscFunctionReturn(0);
520d8588912SDave May }
521d8588912SDave May 
522d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
523d71ae5a4SJacob Faibussowitsch {
524f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
525f349c1fdSJed Brown   PetscInt  i;
526f349c1fdSJed Brown   Mat       sub;
527f349c1fdSJed Brown 
528f349c1fdSJed Brown   PetscFunctionBegin;
5290298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
530f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5319566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
532f349c1fdSJed Brown   *B = sub;
533f349c1fdSJed Brown   PetscFunctionReturn(0);
534d8588912SDave May }
535d8588912SDave May 
536d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
537d71ae5a4SJacob Faibussowitsch {
53818d228c0SPierre Jolivet   PetscInt  i, j, size, m;
539f349c1fdSJed Brown   PetscBool flg;
54018d228c0SPierre Jolivet   IS        out, concatenate[2];
541f349c1fdSJed Brown 
542f349c1fdSJed Brown   PetscFunctionBegin;
543f349c1fdSJed Brown   PetscValidPointer(list, 3);
544f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
54518d228c0SPierre Jolivet   if (begin) {
54618d228c0SPierre Jolivet     PetscValidIntPointer(begin, 5);
54718d228c0SPierre Jolivet     *begin = -1;
54818d228c0SPierre Jolivet   }
54918d228c0SPierre Jolivet   if (end) {
55018d228c0SPierre Jolivet     PetscValidIntPointer(end, 6);
55118d228c0SPierre Jolivet     *end = -1;
55218d228c0SPierre Jolivet   }
553f349c1fdSJed Brown   for (i = 0; i < n; i++) {
554207556f9SJed Brown     if (!list[i]) continue;
5559566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
556f349c1fdSJed Brown     if (flg) {
55718d228c0SPierre Jolivet       if (begin) *begin = i;
55818d228c0SPierre Jolivet       if (end) *end = i + 1;
559f349c1fdSJed Brown       PetscFunctionReturn(0);
560f349c1fdSJed Brown     }
561f349c1fdSJed Brown   }
5629566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
56318d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
56418d228c0SPierre Jolivet     if (!list[i]) continue;
56518d228c0SPierre Jolivet     m = 0;
5669566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5679566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
56818d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
56918d228c0SPierre Jolivet       if (list[j]) {
57018d228c0SPierre Jolivet         concatenate[0] = out;
57118d228c0SPierre Jolivet         concatenate[1] = list[j];
5729566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5739566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5749566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
57518d228c0SPierre Jolivet       }
57618d228c0SPierre Jolivet     }
57718d228c0SPierre Jolivet     if (m == size) {
5789566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
57918d228c0SPierre Jolivet       if (flg) {
58018d228c0SPierre Jolivet         if (begin) *begin = i;
58118d228c0SPierre Jolivet         if (end) *end = j;
5829566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
58318d228c0SPierre Jolivet         PetscFunctionReturn(0);
58418d228c0SPierre Jolivet       }
58518d228c0SPierre Jolivet     }
5869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
58718d228c0SPierre Jolivet   }
58818d228c0SPierre Jolivet   PetscFunctionReturn(0);
589f349c1fdSJed Brown }
590f349c1fdSJed Brown 
591d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
592d71ae5a4SJacob Faibussowitsch {
5938188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
59418d228c0SPierre Jolivet   PetscInt  lr, lc;
59518d228c0SPierre Jolivet 
59618d228c0SPierre Jolivet   PetscFunctionBegin;
5979566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5989566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5999566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
6009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
6019566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6029566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6039566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6049566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6059566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
60818d228c0SPierre Jolivet   PetscFunctionReturn(0);
60918d228c0SPierre Jolivet }
61018d228c0SPierre Jolivet 
611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
612d71ae5a4SJacob Faibussowitsch {
61318d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
61418d228c0SPierre Jolivet   Mat       *a;
61518d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6168188e55aSJed Brown   char       keyname[256];
61718d228c0SPierre Jolivet   PetscBool *b;
61818d228c0SPierre Jolivet   PetscBool  flg;
6198188e55aSJed Brown 
6208188e55aSJed Brown   PetscFunctionBegin;
6210298fd71SBarry Smith   *B = NULL;
6229566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6239566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6248188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
6258188e55aSJed Brown 
6269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
62718d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
62818d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
62918d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
63018d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
63118d228c0SPierre Jolivet     }
63218d228c0SPierre Jolivet   }
63318d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
63418d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
63518d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
63618d228c0SPierre Jolivet         flg = PETSC_FALSE;
63718d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
63818d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
63918d228c0SPierre Jolivet         }
64018d228c0SPierre Jolivet         if (flg) {
64118d228c0SPierre Jolivet           flg = PETSC_FALSE;
64218d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
64318d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
64418d228c0SPierre Jolivet           }
64518d228c0SPierre Jolivet         }
64618d228c0SPierre Jolivet         if (!flg) {
64718d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6489566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
64918d228c0SPierre Jolivet         }
65018d228c0SPierre Jolivet       }
65118d228c0SPierre Jolivet     }
65218d228c0SPierre Jolivet   }
6539566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
65418d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
65518d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
65648a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
65718d228c0SPierre Jolivet     }
65818d228c0SPierre Jolivet   }
6599566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6608188e55aSJed Brown   (*B)->assembled = A->assembled;
6619566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6629566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6638188e55aSJed Brown   PetscFunctionReturn(0);
6648188e55aSJed Brown }
6658188e55aSJed Brown 
666d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
667d71ae5a4SJacob Faibussowitsch {
668f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
66918d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
670f349c1fdSJed Brown 
671f349c1fdSJed Brown   PetscFunctionBegin;
6729566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6739566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
67418d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
67548a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
67618d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
67718d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6789566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
67918d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
680f349c1fdSJed Brown   PetscFunctionReturn(0);
681f349c1fdSJed Brown }
682f349c1fdSJed Brown 
68306a1af2fSStefano Zampini /*
68406a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
68506a1af2fSStefano Zampini */
686d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
687d71ae5a4SJacob Faibussowitsch {
688f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
689f349c1fdSJed Brown   Mat       sub;
690f349c1fdSJed Brown 
691f349c1fdSJed Brown   PetscFunctionBegin;
6929566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
693f349c1fdSJed Brown   switch (reuse) {
694f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6959566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
696f349c1fdSJed Brown     *B = sub;
697f349c1fdSJed Brown     break;
698d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
699d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
700d71ae5a4SJacob Faibussowitsch     break;
701d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
702d71ae5a4SJacob Faibussowitsch     break;
703d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
704d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
705f349c1fdSJed Brown   }
706f349c1fdSJed Brown   PetscFunctionReturn(0);
707f349c1fdSJed Brown }
708f349c1fdSJed Brown 
709d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
710d71ae5a4SJacob Faibussowitsch {
711f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
712f349c1fdSJed Brown   Mat       sub;
713f349c1fdSJed Brown 
714f349c1fdSJed Brown   PetscFunctionBegin;
7159566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
716f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7179566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
718f349c1fdSJed Brown   *B = sub;
719d8588912SDave May   PetscFunctionReturn(0);
720d8588912SDave May }
721d8588912SDave May 
722d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
723d71ae5a4SJacob Faibussowitsch {
724f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
725f349c1fdSJed Brown   Mat       sub;
726d8588912SDave May 
727d8588912SDave May   PetscFunctionBegin;
7289566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
72908401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
730f349c1fdSJed Brown   if (sub) {
731aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7329566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
733d8588912SDave May   }
734d8588912SDave May   PetscFunctionReturn(0);
735d8588912SDave May }
736d8588912SDave May 
737d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
738d71ae5a4SJacob Faibussowitsch {
7397874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7407874fa86SDave May   PetscInt  i;
7417874fa86SDave May 
7427874fa86SDave May   PetscFunctionBegin;
7437874fa86SDave May   for (i = 0; i < bA->nr; i++) {
744429bac76SJed Brown     Vec bv;
7459566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7467874fa86SDave May     if (bA->m[i][i]) {
7479566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7487874fa86SDave May     } else {
7499566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7507874fa86SDave May     }
7519566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7527874fa86SDave May   }
7537874fa86SDave May   PetscFunctionReturn(0);
7547874fa86SDave May }
7557874fa86SDave May 
756d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
757d71ae5a4SJacob Faibussowitsch {
7587874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
759429bac76SJed Brown   Vec       bl, *br;
7607874fa86SDave May   PetscInt  i, j;
7617874fa86SDave May 
7627874fa86SDave May   PetscFunctionBegin;
7639566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7642e6472ebSElliott Sales de Andrade   if (r) {
7659566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7662e6472ebSElliott Sales de Andrade   }
7672e6472ebSElliott Sales de Andrade   bl = NULL;
7687874fa86SDave May   for (i = 0; i < bA->nr; i++) {
76948a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7707874fa86SDave May     for (j = 0; j < bA->nc; j++) {
77148a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7727874fa86SDave May     }
77348a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7742e6472ebSElliott Sales de Andrade   }
7752e6472ebSElliott Sales de Andrade   if (r) {
7769566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7772e6472ebSElliott Sales de Andrade   }
7789566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7797874fa86SDave May   PetscFunctionReturn(0);
7807874fa86SDave May }
7817874fa86SDave May 
782d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
783d71ae5a4SJacob Faibussowitsch {
784a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
785a061e289SJed Brown   PetscInt  i, j;
786a061e289SJed Brown 
787a061e289SJed Brown   PetscFunctionBegin;
788a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
789a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
79048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
791a061e289SJed Brown     }
792a061e289SJed Brown   }
793a061e289SJed Brown   PetscFunctionReturn(0);
794a061e289SJed Brown }
795a061e289SJed Brown 
796d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
797d71ae5a4SJacob Faibussowitsch {
798a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
799a061e289SJed Brown   PetscInt  i;
80006a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
801a061e289SJed Brown 
802a061e289SJed Brown   PetscFunctionBegin;
803a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
80406a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
80508401ef6SPierre 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);
8069566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8079566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
80806a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
80906a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
810a061e289SJed Brown   }
81106a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
812a061e289SJed Brown   PetscFunctionReturn(0);
813a061e289SJed Brown }
814a061e289SJed Brown 
815d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
816d71ae5a4SJacob Faibussowitsch {
81713135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
81813135bc6SAlex Fikl   PetscInt  i;
81906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
82013135bc6SAlex Fikl 
82113135bc6SAlex Fikl   PetscFunctionBegin;
82213135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
82306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82413135bc6SAlex Fikl     Vec              bv;
8259566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
82613135bc6SAlex Fikl     if (bA->m[i][i]) {
8279566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8289566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82913135bc6SAlex Fikl     }
8309566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
83106a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
83206a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
83313135bc6SAlex Fikl   }
83406a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
83513135bc6SAlex Fikl   PetscFunctionReturn(0);
83613135bc6SAlex Fikl }
83713135bc6SAlex Fikl 
838d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
839d71ae5a4SJacob Faibussowitsch {
840f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
841f8170845SAlex Fikl   PetscInt  i, j;
842f8170845SAlex Fikl 
843f8170845SAlex Fikl   PetscFunctionBegin;
844f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
845f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
84648a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
847f8170845SAlex Fikl     }
848f8170845SAlex Fikl   }
849f8170845SAlex Fikl   PetscFunctionReturn(0);
850f8170845SAlex Fikl }
851f8170845SAlex Fikl 
852d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
853d71ae5a4SJacob Faibussowitsch {
854d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
855d8588912SDave May   Vec      *L, *R;
856d8588912SDave May   MPI_Comm  comm;
857d8588912SDave May   PetscInt  i, j;
858d8588912SDave May 
859d8588912SDave May   PetscFunctionBegin;
8609566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
861d8588912SDave May   if (right) {
862d8588912SDave May     /* allocate R */
8639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
864d8588912SDave May     /* Create the right vectors */
865d8588912SDave May     for (j = 0; j < bA->nc; j++) {
866d8588912SDave May       for (i = 0; i < bA->nr; i++) {
867d8588912SDave May         if (bA->m[i][j]) {
8689566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
869d8588912SDave May           break;
870d8588912SDave May         }
871d8588912SDave May       }
87208401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
873d8588912SDave May     }
8749566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
875d8588912SDave May     /* hand back control to the nest vector */
87648a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8779566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
878d8588912SDave May   }
879d8588912SDave May 
880d8588912SDave May   if (left) {
881d8588912SDave May     /* allocate L */
8829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
883d8588912SDave May     /* Create the left vectors */
884d8588912SDave May     for (i = 0; i < bA->nr; i++) {
885d8588912SDave May       for (j = 0; j < bA->nc; j++) {
886d8588912SDave May         if (bA->m[i][j]) {
8879566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
888d8588912SDave May           break;
889d8588912SDave May         }
890d8588912SDave May       }
89108401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
892d8588912SDave May     }
893d8588912SDave May 
8949566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
89548a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
896d8588912SDave May 
8979566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
898d8588912SDave May   }
899d8588912SDave May   PetscFunctionReturn(0);
900d8588912SDave May }
901d8588912SDave May 
902d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
903d71ae5a4SJacob Faibussowitsch {
904d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
90529e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
906d8588912SDave May   PetscInt  i, j;
907d8588912SDave May 
908d8588912SDave May   PetscFunctionBegin;
9099566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
910d8588912SDave May   if (isascii) {
9119566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object: \n"));
9139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9149566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n", bA->nr, bA->nc));
915d8588912SDave May 
9169566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure: \n"));
917d8588912SDave May     for (i = 0; i < bA->nr; i++) {
918d8588912SDave May       for (j = 0; j < bA->nc; j++) {
91919fd82e9SBarry Smith         MatType   type;
920270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
921d8588912SDave May         PetscInt  NR, NC;
922d8588912SDave May         PetscBool isNest = PETSC_FALSE;
923d8588912SDave May 
924d8588912SDave May         if (!bA->m[i][j]) {
9259566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n", i, j));
926d8588912SDave May           continue;
927d8588912SDave May         }
9289566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9299566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9309566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9319566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9329566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
933d8588912SDave May 
9349566063dSJacob 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));
935d8588912SDave May 
93629e60adbSStefano Zampini         if (isNest || viewSub) {
9379566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9389566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9399566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
940d8588912SDave May         }
941d8588912SDave May       }
942d8588912SDave May     }
9439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
944d8588912SDave May   }
945d8588912SDave May   PetscFunctionReturn(0);
946d8588912SDave May }
947d8588912SDave May 
948d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
949d71ae5a4SJacob Faibussowitsch {
950d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
951d8588912SDave May   PetscInt  i, j;
952d8588912SDave May 
953d8588912SDave May   PetscFunctionBegin;
954d8588912SDave May   for (i = 0; i < bA->nr; i++) {
955d8588912SDave May     for (j = 0; j < bA->nc; j++) {
956d8588912SDave May       if (!bA->m[i][j]) continue;
9579566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
958d8588912SDave May     }
959d8588912SDave May   }
960d8588912SDave May   PetscFunctionReturn(0);
961d8588912SDave May }
962d8588912SDave May 
963d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
964d71ae5a4SJacob Faibussowitsch {
965c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
966c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
96706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
968c222c20dSDavid Ham 
969c222c20dSDavid Ham   PetscFunctionBegin;
970aed4548fSBarry 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);
971c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
972c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
97306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
97446a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9759566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
97608401ef6SPierre 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);
9779566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
97806a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
97906a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
980c222c20dSDavid Ham     }
981c222c20dSDavid Ham   }
98206a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
983c222c20dSDavid Ham   PetscFunctionReturn(0);
984c222c20dSDavid Ham }
985c222c20dSDavid Ham 
986d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
987d71ae5a4SJacob Faibussowitsch {
9886e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
9896e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
99006a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
9916e76ffeaSPierre Jolivet 
9926e76ffeaSPierre Jolivet   PetscFunctionBegin;
993aed4548fSBarry 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);
9946e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
9956e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
99606a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9976e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9989566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
999c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1000c066aebcSStefano Zampini         Mat M;
1001c066aebcSStefano Zampini 
100208401ef6SPierre 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);
10039566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10049566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10059566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1006c066aebcSStefano Zampini       }
10079566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
100806a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
100906a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10106e76ffeaSPierre Jolivet     }
10116e76ffeaSPierre Jolivet   }
101206a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10136e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
10146e76ffeaSPierre Jolivet }
10156e76ffeaSPierre Jolivet 
1016d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1017d71ae5a4SJacob Faibussowitsch {
1018d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1019841e96a3SJed Brown   Mat      *b;
1020841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1021d8588912SDave May 
1022d8588912SDave May   PetscFunctionBegin;
10239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1024841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1025841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1026841e96a3SJed Brown       if (bA->m[i][j]) {
10279566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1028841e96a3SJed Brown       } else {
10290298fd71SBarry Smith         b[i * nc + j] = NULL;
1030d8588912SDave May       }
1031d8588912SDave May     }
1032d8588912SDave May   }
10339566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1034841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
103548a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10369566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1037d8588912SDave May 
10389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1040d8588912SDave May   PetscFunctionReturn(0);
1041d8588912SDave May }
1042d8588912SDave May 
1043d8588912SDave May /* nest api */
1044d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1045d71ae5a4SJacob Faibussowitsch {
1046d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10475fd66863SKarl Rupp 
1048d8588912SDave May   PetscFunctionBegin;
104908401ef6SPierre 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);
105008401ef6SPierre 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);
1051d8588912SDave May   *mat = bA->m[idxm][jdxm];
1052d8588912SDave May   PetscFunctionReturn(0);
1053d8588912SDave May }
1054d8588912SDave May 
10559ba0d327SJed Brown /*@
105611a5261eSBarry Smith  MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1057d8588912SDave May 
1058d8588912SDave May  Not collective
1059d8588912SDave May 
1060d8588912SDave May  Input Parameters:
106111a5261eSBarry Smith +   A  - `MATNEST` matrix
1062d8588912SDave May .   idxm - index of the matrix within the nest matrix
1063629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1064d8588912SDave May 
1065d8588912SDave May  Output Parameter:
1066d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
1067d8588912SDave May 
1068d8588912SDave May  Level: developer
1069d8588912SDave May 
107011a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`,
1071db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1072d8588912SDave May @*/
1073d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1074d71ae5a4SJacob Faibussowitsch {
1075d8588912SDave May   PetscFunctionBegin;
1076cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
1077d8588912SDave May   PetscFunctionReturn(0);
1078d8588912SDave May }
1079d8588912SDave May 
1080d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1081d71ae5a4SJacob Faibussowitsch {
10820782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
10830782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
10840782ca92SJed Brown 
10850782ca92SJed Brown   PetscFunctionBegin;
108608401ef6SPierre 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);
108708401ef6SPierre 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);
10889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
10899566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
10909566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
10919566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
10929566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
10939566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1094aed4548fSBarry 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);
1095aed4548fSBarry 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);
109626fbe8dcSKarl Rupp 
109706a1af2fSStefano Zampini   /* do not increase object state */
109806a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
109906a1af2fSStefano Zampini 
11009566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11020782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11039566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11049566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
110506a1af2fSStefano Zampini   A->nonzerostate++;
11060782ca92SJed Brown   PetscFunctionReturn(0);
11070782ca92SJed Brown }
11080782ca92SJed Brown 
11099ba0d327SJed Brown /*@
111011a5261eSBarry Smith  MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11110782ca92SJed Brown 
11120782ca92SJed Brown  Logically collective on the submatrix communicator
11130782ca92SJed Brown 
11140782ca92SJed Brown  Input Parameters:
111511a5261eSBarry Smith +   A  - `MATNEST` matrix
11160782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
11170782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
11180782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
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 
11250782ca92SJed Brown  Level: developer
11260782ca92SJed Brown 
112711a5261eSBarry Smith .seealso: `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1128db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11290782ca92SJed Brown @*/
1130d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1131d71ae5a4SJacob Faibussowitsch {
11320782ca92SJed Brown   PetscFunctionBegin;
1133cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11340782ca92SJed Brown   PetscFunctionReturn(0);
11350782ca92SJed Brown }
11360782ca92SJed Brown 
1137d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1138d71ae5a4SJacob Faibussowitsch {
1139d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11405fd66863SKarl Rupp 
1141d8588912SDave May   PetscFunctionBegin;
114226fbe8dcSKarl Rupp   if (M) *M = bA->nr;
114326fbe8dcSKarl Rupp   if (N) *N = bA->nc;
114426fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1145d8588912SDave May   PetscFunctionReturn(0);
1146d8588912SDave May }
1147d8588912SDave May 
1148d8588912SDave May /*@C
114911a5261eSBarry Smith  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1150d8588912SDave May 
1151d8588912SDave May  Not collective
1152d8588912SDave May 
1153f899ff85SJose E. Roman  Input Parameter:
1154629881c0SJed Brown .   A  - nest matrix
1155d8588912SDave May 
1156d8d19677SJose E. Roman  Output Parameters:
1157629881c0SJed Brown +   M - number of rows in the nest matrix
1158d8588912SDave May .   N - number of cols in the nest matrix
1159629881c0SJed Brown -   mat - 2d array of matrices
1160d8588912SDave May 
116111a5261eSBarry Smith  Note:
1162d8588912SDave May  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)
1167351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1168351962e3SVincent Le Chenadec 
1169d8588912SDave May  Level: developer
1170d8588912SDave May 
117111a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1172db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1173d8588912SDave May @*/
1174d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1175d71ae5a4SJacob Faibussowitsch {
1176d8588912SDave May   PetscFunctionBegin;
1177cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
1178d8588912SDave May   PetscFunctionReturn(0);
1179d8588912SDave May }
1180d8588912SDave May 
1181d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1182d71ae5a4SJacob Faibussowitsch {
1183d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1184d8588912SDave May 
1185d8588912SDave May   PetscFunctionBegin;
118626fbe8dcSKarl Rupp   if (M) *M = bA->nr;
118726fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1188d8588912SDave May   PetscFunctionReturn(0);
1189d8588912SDave May }
1190d8588912SDave May 
11919ba0d327SJed Brown /*@
119211a5261eSBarry Smith  MatNestGetSize - Returns the size of the `MATNEST` matrix.
1193d8588912SDave May 
1194d8588912SDave May  Not collective
1195d8588912SDave May 
1196f899ff85SJose E. Roman  Input Parameter:
119711a5261eSBarry Smith .   A  - `MATNEST` matrix
1198d8588912SDave May 
1199d8d19677SJose E. Roman  Output Parameters:
1200629881c0SJed Brown +   M - number of rows in the nested mat
1201629881c0SJed Brown -   N - number of cols in the nested mat
1202d8588912SDave May 
1203d8588912SDave May  Level: developer
1204d8588912SDave May 
120511a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1206db781477SPatrick Sanan           `MatNestGetISs()`
1207d8588912SDave May @*/
1208d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1209d71ae5a4SJacob Faibussowitsch {
1210d8588912SDave May   PetscFunctionBegin;
1211cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
1212d8588912SDave May   PetscFunctionReturn(0);
1213d8588912SDave May }
1214d8588912SDave May 
1215d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1216d71ae5a4SJacob Faibussowitsch {
1217900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1218900e7ff2SJed Brown   PetscInt  i;
1219900e7ff2SJed Brown 
1220900e7ff2SJed Brown   PetscFunctionBegin;
12219371c9d4SSatish Balay   if (rows)
12229371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12239371c9d4SSatish Balay   if (cols)
12249371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
1225900e7ff2SJed Brown   PetscFunctionReturn(0);
1226900e7ff2SJed Brown }
1227900e7ff2SJed Brown 
12283a4d7b9aSSatish Balay /*@C
122911a5261eSBarry Smith  MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1230900e7ff2SJed Brown 
1231900e7ff2SJed Brown  Not collective
1232900e7ff2SJed Brown 
1233f899ff85SJose E. Roman  Input Parameter:
123411a5261eSBarry Smith .   A  - `MATNEST` matrix
1235900e7ff2SJed Brown 
1236d8d19677SJose E. Roman  Output Parameters:
1237900e7ff2SJed Brown +   rows - array of row index sets
1238900e7ff2SJed Brown -   cols - array of column index sets
1239900e7ff2SJed Brown 
1240900e7ff2SJed Brown  Level: advanced
1241900e7ff2SJed Brown 
124211a5261eSBarry Smith  Note:
1243900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1244900e7ff2SJed Brown 
124511a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`,
1246db781477SPatrick Sanan           `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()`
1247900e7ff2SJed Brown @*/
1248d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1249d71ae5a4SJacob Faibussowitsch {
1250900e7ff2SJed Brown   PetscFunctionBegin;
1251900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1252cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1253900e7ff2SJed Brown   PetscFunctionReturn(0);
1254900e7ff2SJed Brown }
1255900e7ff2SJed Brown 
1256d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1257d71ae5a4SJacob Faibussowitsch {
1258900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1259900e7ff2SJed Brown   PetscInt  i;
1260900e7ff2SJed Brown 
1261900e7ff2SJed Brown   PetscFunctionBegin;
12629371c9d4SSatish Balay   if (rows)
12639371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12649371c9d4SSatish Balay   if (cols)
12659371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
1266900e7ff2SJed Brown   PetscFunctionReturn(0);
1267900e7ff2SJed Brown }
1268900e7ff2SJed Brown 
1269900e7ff2SJed Brown /*@C
127011a5261eSBarry Smith  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1271900e7ff2SJed Brown 
1272900e7ff2SJed Brown  Not collective
1273900e7ff2SJed Brown 
1274f899ff85SJose E. Roman  Input Parameter:
127511a5261eSBarry Smith .   A  - `MATNEST` matrix
1276900e7ff2SJed Brown 
1277d8d19677SJose E. Roman  Output Parameters:
12780298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
12790298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1280900e7ff2SJed Brown 
1281900e7ff2SJed Brown  Level: advanced
1282900e7ff2SJed Brown 
128311a5261eSBarry Smith  Note:
1284900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1285900e7ff2SJed Brown 
128611a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1287db781477SPatrick Sanan           `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()`
1288900e7ff2SJed Brown @*/
1289d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1290d71ae5a4SJacob Faibussowitsch {
1291900e7ff2SJed Brown   PetscFunctionBegin;
1292900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1293cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1294900e7ff2SJed Brown   PetscFunctionReturn(0);
1295900e7ff2SJed Brown }
1296900e7ff2SJed Brown 
1297d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1298d71ae5a4SJacob Faibussowitsch {
1299207556f9SJed Brown   PetscBool flg;
1300207556f9SJed Brown 
1301207556f9SJed Brown   PetscFunctionBegin;
13029566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1303207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13042a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
130512b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
1306207556f9SJed Brown   PetscFunctionReturn(0);
1307207556f9SJed Brown }
1308207556f9SJed Brown 
1309207556f9SJed Brown /*@C
131011a5261eSBarry Smith  MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1311207556f9SJed Brown 
1312207556f9SJed Brown  Not collective
1313207556f9SJed Brown 
1314207556f9SJed Brown  Input Parameters:
131511a5261eSBarry Smith +  A  - `MATNEST` matrix
131611a5261eSBarry Smith -  vtype - `VecType` to use for creating vectors
1317207556f9SJed Brown 
1318207556f9SJed Brown  Level: developer
1319207556f9SJed Brown 
132011a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateVecs()`, `MATNEST`, `MatCreateNest()`, `VecType`
1321207556f9SJed Brown @*/
1322d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1323d71ae5a4SJacob Faibussowitsch {
1324207556f9SJed Brown   PetscFunctionBegin;
1325cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
1326207556f9SJed Brown   PetscFunctionReturn(0);
1327207556f9SJed Brown }
1328207556f9SJed Brown 
1329d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1330d71ae5a4SJacob Faibussowitsch {
1331c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1332c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
133388ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
133488ffe2e8SJose E. Roman   VecType   vtype, type;
1335d8588912SDave May 
1336d8588912SDave May   PetscFunctionBegin;
13379566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
133806a1af2fSStefano Zampini 
1339c8883902SJed Brown   s->nr = nr;
1340c8883902SJed Brown   s->nc = nc;
1341d8588912SDave May 
1342c8883902SJed Brown   /* Create space for submatrices */
13439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
134448a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i]));
1345c8883902SJed Brown   for (i = 0; i < nr; i++) {
1346c8883902SJed Brown     for (j = 0; j < nc; j++) {
1347c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
134848a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1349d8588912SDave May     }
1350d8588912SDave May   }
13519566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13529566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
135388ffe2e8SJose E. Roman   if (isstd) {
135488ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
135588ffe2e8SJose E. Roman     vtype = NULL;
135688ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
135788ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
135888ffe2e8SJose E. Roman         if (a[i * nc + j]) {
135988ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13609566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
136188ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
136288ffe2e8SJose E. Roman           } else if (sametype) {
13639566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13649566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
136588ffe2e8SJose E. Roman           }
136688ffe2e8SJose E. Roman         }
136788ffe2e8SJose E. Roman       }
136888ffe2e8SJose E. Roman     }
136988ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13709566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
137188ffe2e8SJose E. Roman     }
137288ffe2e8SJose E. Roman   }
1373d8588912SDave May 
13749566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1375d8588912SDave May 
13769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
13779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1378c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1379c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1380d8588912SDave May 
13819566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
138206a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
138306a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
138448a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
138506a1af2fSStefano Zampini     }
138606a1af2fSStefano Zampini   }
138706a1af2fSStefano Zampini 
13889566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1389d8588912SDave May 
13909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
13919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
13929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
13939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1394c8883902SJed Brown 
13959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
13969566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1397c8883902SJed Brown 
139806a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
139906a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14009566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
140106a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
140206a1af2fSStefano Zampini   if (cong) {
140348a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
140406a1af2fSStefano Zampini   }
140506a1af2fSStefano Zampini   if (!cong) {
1406381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
140706a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
140806a1af2fSStefano Zampini     A->ops->shift           = NULL;
140906a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
141006a1af2fSStefano Zampini   }
141106a1af2fSStefano Zampini 
14129566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14139566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
141406a1af2fSStefano Zampini   A->nonzerostate++;
1415d8588912SDave May   PetscFunctionReturn(0);
1416d8588912SDave May }
1417d8588912SDave May 
1418c8883902SJed Brown /*@
141911a5261eSBarry Smith    MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1420c8883902SJed Brown 
1421*c3339decSBarry Smith    Collective
1422c8883902SJed Brown 
1423d8d19677SJose E. Roman    Input Parameters:
142411a5261eSBarry Smith +  A - `MATNEST` matrix
1425c8883902SJed Brown .  nr - number of nested row blocks
14260298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1427c8883902SJed Brown .  nc - number of nested column blocks
14280298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
14290298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1430c8883902SJed Brown 
143111a5261eSBarry Smith    Note:
143211a5261eSBarry Smith    This always resets any submatrix information previously set
143306a1af2fSStefano Zampini 
1434c8883902SJed Brown    Level: advanced
1435c8883902SJed Brown 
143611a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1437c8883902SJed Brown @*/
1438d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1439d71ae5a4SJacob Faibussowitsch {
144006a1af2fSStefano Zampini   PetscInt i;
1441c8883902SJed Brown 
1442c8883902SJed Brown   PetscFunctionBegin;
1443c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
144408401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1445c8883902SJed Brown   if (nr && is_row) {
1446c8883902SJed Brown     PetscValidPointer(is_row, 3);
1447c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1448c8883902SJed Brown   }
144908401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14501664e352SJed Brown   if (nc && is_col) {
1451c8883902SJed Brown     PetscValidPointer(is_col, 5);
14529b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1453c8883902SJed Brown   }
145406a1af2fSStefano Zampini   if (nr * nc > 0) PetscValidPointer(a, 6);
1455cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
1456c8883902SJed Brown   PetscFunctionReturn(0);
1457c8883902SJed Brown }
1458d8588912SDave May 
1459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1460d71ae5a4SJacob Faibussowitsch {
146177019fcaSJed Brown   PetscBool flg;
146277019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
146377019fcaSJed Brown 
146477019fcaSJed Brown   PetscFunctionBegin;
1465aea6d515SStefano Zampini   *ltog = NULL;
146677019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
146777019fcaSJed Brown     if (islocal[i]) {
14689566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
146977019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
147077019fcaSJed Brown     } else {
14719566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
147277019fcaSJed Brown     }
147377019fcaSJed Brown     m += mi;
147477019fcaSJed Brown   }
1475aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1476aea6d515SStefano Zampini 
14779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1478165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
14790298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1480e108cb99SStefano Zampini     Mat                    sub  = NULL;
1481f6d38dbbSStefano Zampini     PetscSF                sf;
1482f6d38dbbSStefano Zampini     PetscLayout            map;
1483aea6d515SStefano Zampini     const PetscInt        *ix2;
148477019fcaSJed Brown 
1485165cd838SBarry Smith     if (!colflg) {
14869566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
148777019fcaSJed Brown     } else {
14889566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
148977019fcaSJed Brown     }
1490191fd14bSBarry Smith     if (sub) {
1491191fd14bSBarry Smith       if (!colflg) {
14929566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1493191fd14bSBarry Smith       } else {
14949566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1495191fd14bSBarry Smith       }
1496191fd14bSBarry Smith     }
149777019fcaSJed Brown     /*
149877019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
149977019fcaSJed 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.
150077019fcaSJed Brown     */
15019566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1502aea6d515SStefano Zampini     if (islocal[i]) {
1503aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1504aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1505aea6d515SStefano Zampini 
15069566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150728b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1508aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15099566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1510aea6d515SStefano Zampini 
1511aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1513aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1514aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1515aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1516aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1517aea6d515SStefano Zampini         nleaves++;
1518aea6d515SStefano Zampini       }
15199566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15209566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15219566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15229566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15239566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15249566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15259566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15269566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15279566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15289566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15299566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1530aea6d515SStefano Zampini     } else {
15319566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1532aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1533aea6d515SStefano Zampini     }
15349566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
153577019fcaSJed Brown     m += mi;
153677019fcaSJed Brown   }
15379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
153877019fcaSJed Brown   PetscFunctionReturn(0);
153977019fcaSJed Brown }
154077019fcaSJed Brown 
1541d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1542d8588912SDave May /*
1543d8588912SDave May   nprocessors = NP
1544d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1545d8588912SDave May        proc 0: => (g_0,h_0,)
1546d8588912SDave May        proc 1: => (g_1,h_1,)
1547d8588912SDave May        ...
1548d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1549d8588912SDave May 
1550d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1551d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1552d8588912SDave May 
1553d8588912SDave May             proc 0:
1554d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1555d8588912SDave May             proc 1:
1556d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1557d8588912SDave May 
1558d8588912SDave May             proc NP-1:
1559d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1560d8588912SDave May */
1561d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1562d71ae5a4SJacob Faibussowitsch {
1563e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15648188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15650298fd71SBarry Smith   Mat       sub = NULL;
1566d8588912SDave May 
1567d8588912SDave May   PetscFunctionBegin;
15689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
15699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1570d8588912SDave May   if (is_row) { /* valid IS is passed in */
1571a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1572e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15739566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
157426fbe8dcSKarl Rupp 
1575e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1576d8588912SDave May     }
15772ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
15788188e55aSJed Brown     nsum = 0;
15798188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
15809566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
158128b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
15829566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
158308401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15848188e55aSJed Brown       nsum += n;
15858188e55aSJed Brown     }
15869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
158730bc264bSJed Brown     offset -= nsum;
1588e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15899566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15909566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
15919566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15929566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
15939566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
15942ae74bdbSJed Brown       offset += n;
1595d8588912SDave May     }
1596d8588912SDave May   }
1597d8588912SDave May 
1598d8588912SDave May   if (is_col) { /* valid IS is passed in */
1599a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1600e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16019566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
160226fbe8dcSKarl Rupp 
1603e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1604d8588912SDave May     }
16052ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16062ae74bdbSJed Brown     offset = A->cmap->rstart;
16078188e55aSJed Brown     nsum   = 0;
16088188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16099566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
161028b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16119566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
161208401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16138188e55aSJed Brown       nsum += n;
16148188e55aSJed Brown     }
16159566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
161630bc264bSJed Brown     offset -= nsum;
1617e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16189566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16199566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16209566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16219566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16229566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16232ae74bdbSJed Brown       offset += n;
1624d8588912SDave May     }
1625d8588912SDave May   }
1626e2d7f03fSJed Brown 
1627e2d7f03fSJed Brown   /* Set up the local ISs */
16289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1630e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1631e2d7f03fSJed Brown     IS                     isloc;
16320298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1633e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16349566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16359566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1636207556f9SJed Brown     if (rmap) {
16379566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16399566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16409566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1641207556f9SJed Brown     } else {
1642207556f9SJed Brown       nlocal = 0;
16430298fd71SBarry Smith       isloc  = NULL;
1644207556f9SJed Brown     }
1645e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1646e2d7f03fSJed Brown     offset += nlocal;
1647e2d7f03fSJed Brown   }
16488188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1649e2d7f03fSJed Brown     IS                     isloc;
16500298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1651e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16529566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16539566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1654207556f9SJed Brown     if (cmap) {
16559566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16569566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16579566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16589566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1659207556f9SJed Brown     } else {
1660207556f9SJed Brown       nlocal = 0;
16610298fd71SBarry Smith       isloc  = NULL;
1662207556f9SJed Brown     }
1663e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1664e2d7f03fSJed Brown     offset += nlocal;
1665e2d7f03fSJed Brown   }
16660189643fSJed Brown 
166777019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
166877019fcaSJed Brown   {
166945b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
16709566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
16719566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
16729566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
16739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
16749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
167577019fcaSJed Brown   }
167677019fcaSJed Brown 
167776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
16780189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
16790189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
16800189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
16810189643fSJed Brown         Mat      B = vs->m[i][j];
16820189643fSJed Brown         if (!B) continue;
16839566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
16849566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
16859566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
16869566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
16879566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
16889566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1689aed4548fSBarry 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);
1690aed4548fSBarry 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);
16910189643fSJed Brown       }
16920189643fSJed Brown     }
169376bd3646SJed Brown   }
1694a061e289SJed Brown 
1695a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1696a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1697a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
1698a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1699a061e289SJed Brown     }
1700a061e289SJed Brown   }
1701a061e289SJed Brown   A->assembled = PETSC_TRUE;
1702d8588912SDave May   PetscFunctionReturn(0);
1703d8588912SDave May }
1704d8588912SDave May 
170545c38901SJed Brown /*@C
170611a5261eSBarry Smith    MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1707659c6bb0SJed Brown 
170811a5261eSBarry Smith    Collective
1709659c6bb0SJed Brown 
1710d8d19677SJose E. Roman    Input Parameters:
171111a5261eSBarry Smith +  comm - Communicator for the new `MATNEST`
1712659c6bb0SJed Brown .  nr - number of nested row blocks
17130298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1714659c6bb0SJed Brown .  nc - number of nested column blocks
17150298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
17160298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1717659c6bb0SJed Brown 
1718659c6bb0SJed Brown    Output Parameter:
1719659c6bb0SJed Brown .  B - new matrix
1720659c6bb0SJed Brown 
1721659c6bb0SJed Brown    Level: advanced
1722659c6bb0SJed Brown 
172311a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MATNEST`, `MatNestSetSubMat()`,
1724db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1725db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1726659c6bb0SJed Brown @*/
1727d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B)
1728d71ae5a4SJacob Faibussowitsch {
1729d8588912SDave May   Mat A;
1730d8588912SDave May 
1731d8588912SDave May   PetscFunctionBegin;
1732f4259b30SLisandro Dalcin   *B = NULL;
17339566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17349566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
173591a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17369566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1737d8588912SDave May   *B = A;
1738d8588912SDave May   PetscFunctionReturn(0);
1739d8588912SDave May }
1740659c6bb0SJed Brown 
1741d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1742d71ae5a4SJacob Faibussowitsch {
1743b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
174423875855Sstefano_zampini   Mat          *trans;
1745b68353e5Sstefano_zampini   PetscScalar **avv;
1746b68353e5Sstefano_zampini   PetscScalar  *vv;
1747b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1748b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1749b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1750b68353e5Sstefano_zampini   PetscBool     done;
1751b68353e5Sstefano_zampini 
1752b68353e5Sstefano_zampini   PetscFunctionBegin;
17539566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1754b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1755b68353e5Sstefano_zampini     PetscInt rnr;
1756b68353e5Sstefano_zampini 
17579566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
175828b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
175908401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
17609566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1761b68353e5Sstefano_zampini   }
1762b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1763b68353e5Sstefano_zampini   nnz = 0;
17649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1765b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1766b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1767b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1768b68353e5Sstefano_zampini       if (B) {
1769b68353e5Sstefano_zampini         PetscScalar *naa;
1770b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
177123875855Sstefano_zampini         PetscBool    istrans;
1772b68353e5Sstefano_zampini 
1773013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
177423875855Sstefano_zampini         if (istrans) {
177523875855Sstefano_zampini           Mat Bt;
177623875855Sstefano_zampini 
17779566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
17789566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
177923875855Sstefano_zampini           B = trans[i * nest->nc + j];
1780013e2dc7SBarry Smith         } else {
1781013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1782013e2dc7SBarry Smith           if (istrans) {
1783013e2dc7SBarry Smith             Mat Bt;
1784013e2dc7SBarry Smith 
1785013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1786013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1787013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1788013e2dc7SBarry Smith           }
178923875855Sstefano_zampini         }
17909566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
179128b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
17929566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1793b68353e5Sstefano_zampini         nnz += nii[nnr];
1794b68353e5Sstefano_zampini 
1795b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1796b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1797b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1798b68353e5Sstefano_zampini       }
1799b68353e5Sstefano_zampini     }
1800b68353e5Sstefano_zampini   }
1801b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1805b68353e5Sstefano_zampini   } else {
180608401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1807b68353e5Sstefano_zampini   }
1808b68353e5Sstefano_zampini 
1809b68353e5Sstefano_zampini   /* new row pointer */
18109566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1811b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1812b68353e5Sstefano_zampini     PetscInt ncr, rst;
1813b68353e5Sstefano_zampini 
18149566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18159566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1816b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1817b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1818b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1819b68353e5Sstefano_zampini         PetscInt  ir;
1820b68353e5Sstefano_zampini 
1821b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1822b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1823b68353e5Sstefano_zampini           nii++;
1824b68353e5Sstefano_zampini         }
1825b68353e5Sstefano_zampini       }
1826b68353e5Sstefano_zampini     }
1827b68353e5Sstefano_zampini   }
1828b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1829b68353e5Sstefano_zampini 
1830b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1832b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1833b68353e5Sstefano_zampini     PetscInt ncr, rst;
1834b68353e5Sstefano_zampini 
18359566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18369566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1837b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1838b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1839b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1840b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1841b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1842b68353e5Sstefano_zampini         PetscInt     ir, cst;
1843b68353e5Sstefano_zampini 
18449566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1845b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1846b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1847b68353e5Sstefano_zampini 
1848b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1849b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1850b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1851b68353e5Sstefano_zampini             njj++;
1852b68353e5Sstefano_zampini             nvv++;
1853b68353e5Sstefano_zampini           }
1854b68353e5Sstefano_zampini           ci[ir] += rsize;
1855b68353e5Sstefano_zampini           nii++;
1856b68353e5Sstefano_zampini         }
1857b68353e5Sstefano_zampini       }
1858b68353e5Sstefano_zampini     }
1859b68353e5Sstefano_zampini   }
18609566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1861b68353e5Sstefano_zampini 
1862b68353e5Sstefano_zampini   /* restore info */
1863b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1864b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1865b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1866b68353e5Sstefano_zampini       if (B) {
1867b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
186823875855Sstefano_zampini 
186923875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
18709566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
187128b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
18729566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
18739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1874b68353e5Sstefano_zampini       }
1875b68353e5Sstefano_zampini     }
1876b68353e5Sstefano_zampini   }
18779566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1878b68353e5Sstefano_zampini 
1879b68353e5Sstefano_zampini   /* finalize newmat */
1880b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
18819566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1882b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1883b68353e5Sstefano_zampini     Mat B;
1884b68353e5Sstefano_zampini 
18859566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
18869566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1887b68353e5Sstefano_zampini   }
18889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
18899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1890b68353e5Sstefano_zampini   {
1891b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1892b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1893b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1894b68353e5Sstefano_zampini   }
1895b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1896b68353e5Sstefano_zampini }
1897b68353e5Sstefano_zampini 
1898d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1899d71ae5a4SJacob Faibussowitsch {
1900be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1901be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1902be705e3aSPierre Jolivet   PetscBool flg;
1903be705e3aSPierre Jolivet 
1904be705e3aSPierre Jolivet   PetscFunctionBegin;
1905be705e3aSPierre Jolivet   /* Fill by row */
1906be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1907be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1908be705e3aSPierre Jolivet     IS              bNis;
1909be705e3aSPierre Jolivet     PetscInt        bN;
1910be705e3aSPierre Jolivet     const PetscInt *bNindices;
19119566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19129566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1914be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1915fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1916be705e3aSPierre Jolivet       PetscInt        bm, br;
1917be705e3aSPierre Jolivet       const PetscInt *bmindices;
1918be705e3aSPierre Jolivet       if (!B) continue;
1919013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1920be705e3aSPierre Jolivet       if (flg) {
1921cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1922cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19239566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1924be705e3aSPierre Jolivet         B = D;
1925be705e3aSPierre Jolivet       }
19269566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1927be705e3aSPierre Jolivet       if (flg) {
1928fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1929fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1930be705e3aSPierre Jolivet         B = D;
1931be705e3aSPierre Jolivet       }
19329566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19339566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19349566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1935be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1936be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1937be705e3aSPierre Jolivet         const PetscInt    *brcols;
1938be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1939be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19409566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19419566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1942be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1943be705e3aSPierre Jolivet         /*
1944be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1945be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1946be705e3aSPierre Jolivet          */
1947be705e3aSPierre Jolivet         if (a != 1.0) {
19489566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1949be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19509566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19519566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1952be705e3aSPierre Jolivet         } else {
19539566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1954be705e3aSPierre Jolivet         }
19559566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19569566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1957be705e3aSPierre Jolivet       }
1958fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19599566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1960be705e3aSPierre Jolivet     }
19619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
19629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1963be705e3aSPierre Jolivet   }
19649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
19659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
1966be705e3aSPierre Jolivet   PetscFunctionReturn(0);
1967be705e3aSPierre Jolivet }
1968be705e3aSPierre Jolivet 
1969d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1970d71ae5a4SJacob Faibussowitsch {
1971629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
1972be705e3aSPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz, rstart, cstart, cend;
1973b68353e5Sstefano_zampini   PetscMPIInt size;
1974629c3df2SDmitry Karpeev   Mat         C;
1975629c3df2SDmitry Karpeev 
1976629c3df2SDmitry Karpeev   PetscFunctionBegin;
19779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1978b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1979b68353e5Sstefano_zampini     PetscInt  nf;
1980b68353e5Sstefano_zampini     PetscBool fast;
1981b68353e5Sstefano_zampini 
19829566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
198348a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
1984b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
1985b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
1986b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1987b68353e5Sstefano_zampini         if (B) {
19889566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
198923875855Sstefano_zampini           if (!fast) {
199023875855Sstefano_zampini             PetscBool istrans;
199123875855Sstefano_zampini 
1992013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
199323875855Sstefano_zampini             if (istrans) {
199423875855Sstefano_zampini               Mat Bt;
199523875855Sstefano_zampini 
19969566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
19979566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1998013e2dc7SBarry Smith             } else {
1999013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2000013e2dc7SBarry Smith               if (istrans) {
2001013e2dc7SBarry Smith                 Mat Bt;
2002013e2dc7SBarry Smith 
2003013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2004013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2005013e2dc7SBarry Smith               }
200623875855Sstefano_zampini             }
2007b68353e5Sstefano_zampini           }
2008b68353e5Sstefano_zampini         }
2009b68353e5Sstefano_zampini       }
2010b68353e5Sstefano_zampini     }
2011b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20129566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2013b68353e5Sstefano_zampini       if (fast) {
2014b68353e5Sstefano_zampini         PetscInt f, s;
2015b68353e5Sstefano_zampini 
20169566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20179371c9d4SSatish Balay         if (f != nf || s != 1) {
20189371c9d4SSatish Balay           fast = PETSC_FALSE;
20199371c9d4SSatish Balay         } else {
20209566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2021b68353e5Sstefano_zampini           nf += f;
2022b68353e5Sstefano_zampini         }
2023b68353e5Sstefano_zampini       }
2024b68353e5Sstefano_zampini     }
2025b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20269566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2027b68353e5Sstefano_zampini       if (fast) {
2028b68353e5Sstefano_zampini         PetscInt f, s;
2029b68353e5Sstefano_zampini 
20309566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20319371c9d4SSatish Balay         if (f != nf || s != 1) {
20329371c9d4SSatish Balay           fast = PETSC_FALSE;
20339371c9d4SSatish Balay         } else {
20349566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2035b68353e5Sstefano_zampini           nf += f;
2036b68353e5Sstefano_zampini         }
2037b68353e5Sstefano_zampini       }
2038b68353e5Sstefano_zampini     }
2039b68353e5Sstefano_zampini     if (fast) {
20409566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
2041b68353e5Sstefano_zampini       PetscFunctionReturn(0);
2042b68353e5Sstefano_zampini     }
2043b68353e5Sstefano_zampini   }
20449566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20459566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20469566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2047d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2048d1487292SPierre Jolivet   else {
20499566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20509566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
20519566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2052629c3df2SDmitry Karpeev   }
20539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2054629c3df2SDmitry Karpeev   onnz = dnnz + m;
2055629c3df2SDmitry Karpeev   for (k = 0; k < m; k++) {
2056629c3df2SDmitry Karpeev     dnnz[k] = 0;
2057629c3df2SDmitry Karpeev     onnz[k] = 0;
2058629c3df2SDmitry Karpeev   }
2059629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2060629c3df2SDmitry Karpeev     IS              bNis;
2061629c3df2SDmitry Karpeev     PetscInt        bN;
2062629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2063fd8a7442SPierre Jolivet     PetscBool       flg;
2064629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20659566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20669566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20679566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2068629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2069629c3df2SDmitry Karpeev       PetscSF         bmsf;
2070649b366bSFande Kong       PetscSFNode    *iremote;
2071fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2072649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2073629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2074629c3df2SDmitry Karpeev       if (!B) continue;
20759566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20769566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20779566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
20789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
20799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
20809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2081649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2082649b366bSFande Kong         sub_dnnz[k] = 0;
2083649b366bSFande Kong         sub_onnz[k] = 0;
2084649b366bSFande Kong       }
2085013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &flg));
2086fd8a7442SPierre Jolivet       if (flg) {
2087fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2088fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2089fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2090fd8a7442SPierre Jolivet         B = D;
2091fd8a7442SPierre Jolivet       }
2092fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2093fd8a7442SPierre Jolivet       if (flg) {
2094fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2095fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2096fd8a7442SPierre Jolivet         B = D;
2097fd8a7442SPierre Jolivet       }
2098629c3df2SDmitry Karpeev       /*
2099629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2100629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2101629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2102629c3df2SDmitry Karpeev        */
21039566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2104629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2105131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2106629c3df2SDmitry Karpeev         const PetscInt *brcols;
2107a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2108131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21099566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2110649b366bSFande Kong         /* how many roots  */
21119371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21129371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2113649b366bSFande Kong         /* get nonzero pattern */
21149566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2115629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2116629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2117649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2118649b366bSFande Kong             sub_dnnz[br]++;
2119649b366bSFande Kong           } else {
2120649b366bSFande Kong             sub_onnz[br]++;
2121649b366bSFande Kong           }
2122629c3df2SDmitry Karpeev         }
21239566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2124629c3df2SDmitry Karpeev       }
2125fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21269566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2127629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21289566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21299566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21309566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21319566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21329566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21339566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21349566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21359566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2136629c3df2SDmitry Karpeev     }
21379566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21389566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
213965a4a0a3Sstefano_zampini   }
214065a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
214165a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
214265a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
214365a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2144629c3df2SDmitry Karpeev   }
21459566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21469566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21479566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21489566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2149d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21509566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2151d1487292SPierre Jolivet   } else *newmat = C;
2152be705e3aSPierre Jolivet   PetscFunctionReturn(0);
2153be705e3aSPierre Jolivet }
2154629c3df2SDmitry Karpeev 
2155d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2156d71ae5a4SJacob Faibussowitsch {
2157629c3df2SDmitry Karpeev   Mat      B;
2158be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2159be705e3aSPierre Jolivet 
2160be705e3aSPierre Jolivet   PetscFunctionBegin;
21619566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
21629566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2163be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2164be705e3aSPierre Jolivet     B = *newmat;
21659566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2166be705e3aSPierre Jolivet   } else {
21679566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2168629c3df2SDmitry Karpeev   }
21699566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2170be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21719566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2172be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2173629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
2174629c3df2SDmitry Karpeev }
2175629c3df2SDmitry Karpeev 
2176d71ae5a4SJacob Faibussowitsch PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2177d71ae5a4SJacob Faibussowitsch {
21788b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
21793c6db4c4SPierre Jolivet   MatOperation opAdd;
21808b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
21818b7d3b4bSBarry Smith   PetscBool    flg;
218252c5f739Sprj-   PetscFunctionBegin;
21838b7d3b4bSBarry Smith 
218452c5f739Sprj-   *has = PETSC_FALSE;
21853c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21863c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21878b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
21888b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
21898b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21909566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
21918b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
21928b7d3b4bSBarry Smith       }
21938b7d3b4bSBarry Smith     }
21948b7d3b4bSBarry Smith   }
21953c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
21968b7d3b4bSBarry Smith   PetscFunctionReturn(0);
21978b7d3b4bSBarry Smith }
21988b7d3b4bSBarry Smith 
2199659c6bb0SJed Brown /*MC
2200659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2201659c6bb0SJed Brown 
2202659c6bb0SJed Brown   Level: intermediate
2203659c6bb0SJed Brown 
2204659c6bb0SJed Brown   Notes:
220511a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2206659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
220711a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2208659c6bb0SJed Brown 
22098b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22108b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22118b7d3b4bSBarry Smith   than the nest matrix.
22128b7d3b4bSBarry Smith 
221311a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2214db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2215db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2216659c6bb0SJed Brown M*/
2217d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2218d71ae5a4SJacob Faibussowitsch {
2219c8883902SJed Brown   Mat_Nest *s;
2220c8883902SJed Brown 
2221c8883902SJed Brown   PetscFunctionBegin;
22224dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2223c8883902SJed Brown   A->data = (void *)s;
2224e7c19651SJed Brown 
2225e7c19651SJed Brown   s->nr            = -1;
2226e7c19651SJed Brown   s->nc            = -1;
22270298fd71SBarry Smith   s->m             = NULL;
2228e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2229c8883902SJed Brown 
22309566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
223126fbe8dcSKarl Rupp 
2232c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22339194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2234c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22359194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2236f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2237c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2238c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2239c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2240c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22416e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2242c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22437dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2244c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2245c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2246f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2247c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2248c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2249429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2250429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2251a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2252a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
225313135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2254f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22558b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2256381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2257c8883902SJed Brown 
2258f4259b30SLisandro Dalcin   A->spptr     = NULL;
2259c8883902SJed Brown   A->assembled = PETSC_FALSE;
2260c8883902SJed Brown 
2261c8883902SJed Brown   /* expose Nest api's */
22629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
22639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
22649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
22659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
22669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
22679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
22689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
22709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
22719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
22729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
22749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
22759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
22779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
22789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense));
2279c8883902SJed Brown 
22809566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
2281c8883902SJed Brown   PetscFunctionReturn(0);
2282c8883902SJed Brown }
2283