xref: /petsc/src/mat/impls/nest/matnest.c (revision 013e2dc7137d1d9dc4e6b44a828a8fb0f1bd6f29)
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 */
129371c9d4SSatish Balay static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N) {
13d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
148188e55aSJed Brown   PetscInt  i, j;
15d8588912SDave May 
16d8588912SDave May   PetscFunctionBegin;
178188e55aSJed Brown   *m = *n = *M = *N = 0;
188188e55aSJed Brown   for (i = 0; i < bA->nr; i++) { /* rows */
198188e55aSJed Brown     PetscInt sm, sM;
209566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm));
219566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &sM));
228188e55aSJed Brown     *m += sm;
238188e55aSJed Brown     *M += sM;
24d8588912SDave May   }
258188e55aSJed Brown   for (j = 0; j < bA->nc; j++) { /* cols */
268188e55aSJed Brown     PetscInt sn, sN;
279566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn));
289566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &sN));
298188e55aSJed Brown     *n += sn;
308188e55aSJed Brown     *N += sN;
31d8588912SDave May   }
32d8588912SDave May   PetscFunctionReturn(0);
33d8588912SDave May }
34d8588912SDave May 
35d8588912SDave May /* operations */
369371c9d4SSatish Balay static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y) {
37d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
38207556f9SJed Brown   Vec      *bx = bA->right, *by = bA->left;
39207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
40d8588912SDave May 
41d8588912SDave May   PetscFunctionBegin;
429566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i]));
439566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
44207556f9SJed Brown   for (i = 0; i < nr; i++) {
459566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[i]));
46207556f9SJed Brown     for (j = 0; j < nc; j++) {
47207556f9SJed Brown       if (!bA->m[i][j]) continue;
48d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
499566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i]));
50d8588912SDave May     }
51d8588912SDave May   }
529566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i]));
539566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
54d8588912SDave May   PetscFunctionReturn(0);
55d8588912SDave May }
56d8588912SDave May 
579371c9d4SSatish Balay static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z) {
589194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
599194d70fSJed Brown   Vec      *bx = bA->right, *bz = bA->left;
609194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
619194d70fSJed Brown 
629194d70fSJed Brown   PetscFunctionBegin;
639566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i]));
649566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
659194d70fSJed Brown   for (i = 0; i < nr; i++) {
669194d70fSJed Brown     if (y != z) {
679194d70fSJed Brown       Vec by;
689566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by));
699566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[i]));
709566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by));
719194d70fSJed Brown     }
729194d70fSJed Brown     for (j = 0; j < nc; j++) {
739194d70fSJed Brown       if (!bA->m[i][j]) continue;
749194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
759566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i]));
769194d70fSJed Brown     }
779194d70fSJed Brown   }
789566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i]));
799566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
809194d70fSJed Brown   PetscFunctionReturn(0);
819194d70fSJed Brown }
829194d70fSJed Brown 
8352c5f739Sprj- typedef struct {
8452c5f739Sprj-   Mat         *workC;      /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
8552c5f739Sprj-   PetscScalar *tarray;     /* buffer for storing all temporary products A[i][j] B[j] */
8652c5f739Sprj-   PetscInt    *dm, *dn, k; /* displacements and number of submatrices */
8752c5f739Sprj- } Nest_Dense;
8852c5f739Sprj- 
899371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductNumeric_Nest_Dense(Mat C) {
906718818eSStefano Zampini   Mat_Nest          *bA;
9152c5f739Sprj-   Nest_Dense        *contents;
926718818eSStefano Zampini   Mat                viewB, viewC, productB, workC;
9352c5f739Sprj-   const PetscScalar *barray;
9452c5f739Sprj-   PetscScalar       *carray;
956718818eSStefano Zampini   PetscInt           i, j, M, N, nr, nc, ldb, ldc;
966718818eSStefano Zampini   Mat                A, B;
9752c5f739Sprj- 
9852c5f739Sprj-   PetscFunctionBegin;
996718818eSStefano Zampini   MatCheckProduct(C, 3);
1006718818eSStefano Zampini   A = C->product->A;
1016718818eSStefano Zampini   B = C->product->B;
1029566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
1036718818eSStefano Zampini   if (!N) {
1049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1059566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1066718818eSStefano Zampini     PetscFunctionReturn(0);
1076718818eSStefano Zampini   }
1086718818eSStefano Zampini   contents = (Nest_Dense *)C->product->data;
10928b400f6SJacob Faibussowitsch   PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
1106718818eSStefano Zampini   bA = (Mat_Nest *)A->data;
1116718818eSStefano Zampini   nr = bA->nr;
1126718818eSStefano Zampini   nc = bA->nc;
1139566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
1149566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(C, &ldc));
1159566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(C));
1169566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
1179566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(C, &carray));
11852c5f739Sprj-   for (i = 0; i < nr; i++) {
1199566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &M));
1209566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, carray + contents->dm[i], &viewC));
1219566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC, ldc));
12252c5f739Sprj-     for (j = 0; j < nc; j++) {
12352c5f739Sprj-       if (!bA->m[i][j]) continue;
1249566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
1259566063dSJacob Faibussowitsch       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB));
1269566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB, ldb));
1274222ddf1SHong Zhang 
1284222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1294222ddf1SHong Zhang       workC             = contents->workC[i * nc + j];
1304222ddf1SHong Zhang       productB          = workC->product->B;
1314222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1329566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1339566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1344222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1354222ddf1SHong Zhang 
13652c5f739Sprj-       /* C[i] <- workC + C[i] */
1379566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
13852c5f739Sprj-     }
1399566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14052c5f739Sprj-   }
1419566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C, &carray));
1429566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
1434222ddf1SHong Zhang 
1449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
14652c5f739Sprj-   PetscFunctionReturn(0);
14752c5f739Sprj- }
14852c5f739Sprj- 
1499371c9d4SSatish Balay PetscErrorCode MatNest_DenseDestroy(void *ctx) {
15052c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15152c5f739Sprj-   PetscInt    i;
15252c5f739Sprj- 
15352c5f739Sprj-   PetscFunctionBegin;
1549566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
15548a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1569566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1579566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
15852c5f739Sprj-   PetscFunctionReturn(0);
15952c5f739Sprj- }
16052c5f739Sprj- 
1619371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) {
1626718818eSStefano Zampini   Mat_Nest          *bA;
1636718818eSStefano Zampini   Mat                viewB, workC;
16452c5f739Sprj-   const PetscScalar *barray;
1656718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1664222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1676718818eSStefano Zampini   PetscBool          cisdense;
1686718818eSStefano Zampini   Mat                A, B;
1696718818eSStefano Zampini   PetscReal          fill;
17052c5f739Sprj- 
17152c5f739Sprj-   PetscFunctionBegin;
1726718818eSStefano Zampini   MatCheckProduct(C, 4);
17328b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1746718818eSStefano Zampini   A    = C->product->A;
1756718818eSStefano Zampini   B    = C->product->B;
1766718818eSStefano Zampini   fill = C->product->fill;
1776718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1786718818eSStefano Zampini   nr   = bA->nr;
1796718818eSStefano Zampini   nc   = bA->nc;
1809566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1819566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1820572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1839566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1849566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1859566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1869566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1879566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1880572eedcSPierre Jolivet   }
1899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19048a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1919566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
1926718818eSStefano Zampini   if (!N) {
1936718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
1946718818eSStefano Zampini     PetscFunctionReturn(0);
19552c5f739Sprj-   }
19652c5f739Sprj- 
1979566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
1986718818eSStefano Zampini   C->product->data    = contents;
1996718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20152c5f739Sprj-   contents->k = nr * nc;
20252c5f739Sprj-   for (i = 0; i < nr; i++) {
2039566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
20452c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
20552c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
20652c5f739Sprj-   }
20752c5f739Sprj-   for (i = 0; i < nc; i++) {
2089566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
20952c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21052c5f739Sprj-   }
2119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2129566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2139566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2149566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
21552c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
21652c5f739Sprj-   for (j = 0; j < nc; j++) {
2179566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
2189566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB));
2199566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22052c5f739Sprj-     for (i = 0; i < nr; i++) {
22152c5f739Sprj-       if (!bA->m[i][j]) continue;
22252c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2234222ddf1SHong Zhang 
2249566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2254222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2269566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2279566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2289566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2299566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2309566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2314222ddf1SHong Zhang 
2326718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2339566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2349566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
23552c5f739Sprj-     }
2369566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
23752c5f739Sprj-   }
2389566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
23952c5f739Sprj- 
2406718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
24152c5f739Sprj-   PetscFunctionReturn(0);
24252c5f739Sprj- }
24352c5f739Sprj- 
2444222ddf1SHong Zhang /* --------------------------------------------------------- */
2459371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C) {
2464222ddf1SHong Zhang   PetscFunctionBegin;
2476718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2484222ddf1SHong Zhang   PetscFunctionReturn(0);
2494222ddf1SHong Zhang }
2504222ddf1SHong Zhang 
2519371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) {
2524222ddf1SHong Zhang   Mat_Product *product = C->product;
25352c5f739Sprj- 
25452c5f739Sprj-   PetscFunctionBegin;
25548a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
25652c5f739Sprj-   PetscFunctionReturn(0);
25752c5f739Sprj- }
2584222ddf1SHong Zhang /* --------------------------------------------------------- */
25952c5f739Sprj- 
2609371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) {
261d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
262207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
263207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
264d8588912SDave May 
265d8588912SDave May   PetscFunctionBegin;
2669566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2679566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
268207556f9SJed Brown   for (j = 0; j < nc; j++) {
2699566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
270609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2716c75ac25SJed Brown       if (!bA->m[i][j]) continue;
272609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2739566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));
274d8588912SDave May     }
275d8588912SDave May   }
2769566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2779566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
278d8588912SDave May   PetscFunctionReturn(0);
279d8588912SDave May }
280d8588912SDave May 
2819371c9d4SSatish Balay static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) {
2829194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
2839194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
2849194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
2859194d70fSJed Brown 
2869194d70fSJed Brown   PetscFunctionBegin;
2879566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2889566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
2899194d70fSJed Brown   for (j = 0; j < nc; j++) {
2909194d70fSJed Brown     if (y != z) {
2919194d70fSJed Brown       Vec by;
2929566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
2939566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
2949566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
2959194d70fSJed Brown     }
2969194d70fSJed Brown     for (i = 0; i < nr; i++) {
2976c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2989194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
2999566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));
3009194d70fSJed Brown     }
3019194d70fSJed Brown   }
3029566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3039566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3049194d70fSJed Brown   PetscFunctionReturn(0);
3059194d70fSJed Brown }
3069194d70fSJed Brown 
3079371c9d4SSatish Balay static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) {
308f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
309f8170845SAlex Fikl   Mat       C;
310f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
311f8170845SAlex Fikl 
312f8170845SAlex Fikl   PetscFunctionBegin;
3137fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
314aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
315f8170845SAlex Fikl 
316cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
317f8170845SAlex Fikl     Mat *subs;
318f8170845SAlex Fikl     IS  *is_row, *is_col;
319f8170845SAlex Fikl 
3209566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3229566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
323cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
324ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
325ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
326ddeb9bd8SAlex Fikl       }
327ddeb9bd8SAlex Fikl     }
328ddeb9bd8SAlex Fikl 
3299566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3309566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3319566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
332f8170845SAlex Fikl   } else {
333f8170845SAlex Fikl     C = *B;
334f8170845SAlex Fikl   }
335f8170845SAlex Fikl 
336f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
337f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
338f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
339f8170845SAlex Fikl       if (bA->m[i][j]) {
3409566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
341f8170845SAlex Fikl       } else {
342f8170845SAlex Fikl         bC->m[j][i] = NULL;
343f8170845SAlex Fikl       }
344f8170845SAlex Fikl     }
345f8170845SAlex Fikl   }
346f8170845SAlex Fikl 
347cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
348f8170845SAlex Fikl     *B = C;
349f8170845SAlex Fikl   } else {
3509566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
351f8170845SAlex Fikl   }
352f8170845SAlex Fikl   PetscFunctionReturn(0);
353f8170845SAlex Fikl }
354f8170845SAlex Fikl 
3559371c9d4SSatish Balay static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) {
356e2d7f03fSJed Brown   IS      *lst = *list;
357e2d7f03fSJed Brown   PetscInt i;
358e2d7f03fSJed Brown 
359e2d7f03fSJed Brown   PetscFunctionBegin;
360e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3619371c9d4SSatish Balay   for (i = 0; i < n; i++)
3629371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3639566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3640298fd71SBarry Smith   *list = NULL;
365e2d7f03fSJed Brown   PetscFunctionReturn(0);
366e2d7f03fSJed Brown }
367e2d7f03fSJed Brown 
3689371c9d4SSatish Balay static PetscErrorCode MatReset_Nest(Mat A) {
369d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
370d8588912SDave May   PetscInt  i, j;
371d8588912SDave May 
372d8588912SDave May   PetscFunctionBegin;
373d8588912SDave May   /* release the matrices and the place holders */
3749566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
3759566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
3769566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
3779566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
378d8588912SDave May 
3799566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
3809566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
3819566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
382d8588912SDave May 
3839566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
384207556f9SJed Brown 
385d8588912SDave May   /* release the matrices and the place holders */
386d8588912SDave May   if (vs->m) {
387d8588912SDave May     for (i = 0; i < vs->nr; i++) {
38848a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
3899566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
390d8588912SDave May     }
3919566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
392d8588912SDave May   }
39306a1af2fSStefano Zampini 
39406a1af2fSStefano Zampini   /* restore defaults */
39506a1af2fSStefano Zampini   vs->nr            = 0;
39606a1af2fSStefano Zampini   vs->nc            = 0;
39706a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
39806a1af2fSStefano Zampini   PetscFunctionReturn(0);
39906a1af2fSStefano Zampini }
40006a1af2fSStefano Zampini 
4019371c9d4SSatish Balay static PetscErrorCode MatDestroy_Nest(Mat A) {
402362febeeSStefano Zampini   PetscFunctionBegin;
4039566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4049566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL));
422d8588912SDave May   PetscFunctionReturn(0);
423d8588912SDave May }
424d8588912SDave May 
4259371c9d4SSatish Balay static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) {
426381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
427381b8e50SStefano Zampini   PetscInt  i;
428381b8e50SStefano Zampini 
429381b8e50SStefano Zampini   PetscFunctionBegin;
430381b8e50SStefano Zampini   if (dd) *dd = 0;
431381b8e50SStefano Zampini   if (!vs->nr) {
432381b8e50SStefano Zampini     *missing = PETSC_TRUE;
433381b8e50SStefano Zampini     PetscFunctionReturn(0);
434381b8e50SStefano Zampini   }
435381b8e50SStefano Zampini   *missing = PETSC_FALSE;
436381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
437381b8e50SStefano Zampini     *missing = PETSC_TRUE;
438381b8e50SStefano Zampini     if (vs->m[i][i]) {
4399566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
44008401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
441381b8e50SStefano Zampini     }
442381b8e50SStefano Zampini   }
443381b8e50SStefano Zampini   PetscFunctionReturn(0);
444381b8e50SStefano Zampini }
445381b8e50SStefano Zampini 
4469371c9d4SSatish Balay static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) {
447d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
448d8588912SDave May   PetscInt  i, j;
44906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
450d8588912SDave May 
451d8588912SDave May   PetscFunctionBegin;
452d8588912SDave May   for (i = 0; i < vs->nr; i++) {
453d8588912SDave May     for (j = 0; j < vs->nc; j++) {
45406a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
455e7c19651SJed Brown       if (vs->m[i][j]) {
4569566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
457e7c19651SJed Brown         if (!vs->splitassembly) {
458e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
459e7c19651SJed 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
460e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
461e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
462e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
463e7c19651SJed Brown            */
4649566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4659566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
466e7c19651SJed Brown         }
467e7c19651SJed Brown       }
46806a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
46906a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
470d8588912SDave May     }
471d8588912SDave May   }
47206a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
473d8588912SDave May   PetscFunctionReturn(0);
474d8588912SDave May }
475d8588912SDave May 
4769371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) {
477d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
478d8588912SDave May   PetscInt  i, j;
479d8588912SDave May 
480d8588912SDave May   PetscFunctionBegin;
481d8588912SDave May   for (i = 0; i < vs->nr; i++) {
482d8588912SDave May     for (j = 0; j < vs->nc; j++) {
483e7c19651SJed Brown       if (vs->m[i][j]) {
48448a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
485e7c19651SJed Brown       }
486d8588912SDave May     }
487d8588912SDave May   }
488d8588912SDave May   PetscFunctionReturn(0);
489d8588912SDave May }
490d8588912SDave May 
4919371c9d4SSatish Balay static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) {
492f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
493f349c1fdSJed Brown   PetscInt  j;
494f349c1fdSJed Brown   Mat       sub;
495d8588912SDave May 
496d8588912SDave May   PetscFunctionBegin;
4970298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
498f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
4999566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
500f349c1fdSJed Brown   *B = sub;
501f349c1fdSJed Brown   PetscFunctionReturn(0);
502d8588912SDave May }
503d8588912SDave May 
5049371c9d4SSatish Balay static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) {
505f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
506f349c1fdSJed Brown   PetscInt  i;
507f349c1fdSJed Brown   Mat       sub;
508f349c1fdSJed Brown 
509f349c1fdSJed Brown   PetscFunctionBegin;
5100298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
511f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5129566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
513f349c1fdSJed Brown   *B = sub;
514f349c1fdSJed Brown   PetscFunctionReturn(0);
515d8588912SDave May }
516d8588912SDave May 
5179371c9d4SSatish Balay static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) {
51818d228c0SPierre Jolivet   PetscInt  i, j, size, m;
519f349c1fdSJed Brown   PetscBool flg;
52018d228c0SPierre Jolivet   IS        out, concatenate[2];
521f349c1fdSJed Brown 
522f349c1fdSJed Brown   PetscFunctionBegin;
523f349c1fdSJed Brown   PetscValidPointer(list, 3);
524f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
52518d228c0SPierre Jolivet   if (begin) {
52618d228c0SPierre Jolivet     PetscValidIntPointer(begin, 5);
52718d228c0SPierre Jolivet     *begin = -1;
52818d228c0SPierre Jolivet   }
52918d228c0SPierre Jolivet   if (end) {
53018d228c0SPierre Jolivet     PetscValidIntPointer(end, 6);
53118d228c0SPierre Jolivet     *end = -1;
53218d228c0SPierre Jolivet   }
533f349c1fdSJed Brown   for (i = 0; i < n; i++) {
534207556f9SJed Brown     if (!list[i]) continue;
5359566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
536f349c1fdSJed Brown     if (flg) {
53718d228c0SPierre Jolivet       if (begin) *begin = i;
53818d228c0SPierre Jolivet       if (end) *end = i + 1;
539f349c1fdSJed Brown       PetscFunctionReturn(0);
540f349c1fdSJed Brown     }
541f349c1fdSJed Brown   }
5429566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
54318d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
54418d228c0SPierre Jolivet     if (!list[i]) continue;
54518d228c0SPierre Jolivet     m = 0;
5469566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5479566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
54818d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
54918d228c0SPierre Jolivet       if (list[j]) {
55018d228c0SPierre Jolivet         concatenate[0] = out;
55118d228c0SPierre Jolivet         concatenate[1] = list[j];
5529566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5539566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5549566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
55518d228c0SPierre Jolivet       }
55618d228c0SPierre Jolivet     }
55718d228c0SPierre Jolivet     if (m == size) {
5589566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
55918d228c0SPierre Jolivet       if (flg) {
56018d228c0SPierre Jolivet         if (begin) *begin = i;
56118d228c0SPierre Jolivet         if (end) *end = j;
5629566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
56318d228c0SPierre Jolivet         PetscFunctionReturn(0);
56418d228c0SPierre Jolivet       }
56518d228c0SPierre Jolivet     }
5669566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
56718d228c0SPierre Jolivet   }
56818d228c0SPierre Jolivet   PetscFunctionReturn(0);
569f349c1fdSJed Brown }
570f349c1fdSJed Brown 
5719371c9d4SSatish Balay static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) {
5728188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
57318d228c0SPierre Jolivet   PetscInt  lr, lc;
57418d228c0SPierre Jolivet 
57518d228c0SPierre Jolivet   PetscFunctionBegin;
5769566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5779566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5789566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
5799566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
5809566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
5819566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
5829566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
5839566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
5849566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
5859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
5869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
58718d228c0SPierre Jolivet   PetscFunctionReturn(0);
58818d228c0SPierre Jolivet }
58918d228c0SPierre Jolivet 
5909371c9d4SSatish Balay static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) {
59118d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
59218d228c0SPierre Jolivet   Mat       *a;
59318d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
5948188e55aSJed Brown   char       keyname[256];
59518d228c0SPierre Jolivet   PetscBool *b;
59618d228c0SPierre Jolivet   PetscBool  flg;
5978188e55aSJed Brown 
5988188e55aSJed Brown   PetscFunctionBegin;
5990298fd71SBarry Smith   *B = NULL;
6009566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6019566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6028188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
6038188e55aSJed Brown 
6049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
60518d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
60618d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
60718d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
60818d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
60918d228c0SPierre Jolivet     }
61018d228c0SPierre Jolivet   }
61118d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
61218d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
61318d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
61418d228c0SPierre Jolivet         flg = PETSC_FALSE;
61518d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
61618d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
61718d228c0SPierre Jolivet         }
61818d228c0SPierre Jolivet         if (flg) {
61918d228c0SPierre Jolivet           flg = PETSC_FALSE;
62018d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
62118d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
62218d228c0SPierre Jolivet           }
62318d228c0SPierre Jolivet         }
62418d228c0SPierre Jolivet         if (!flg) {
62518d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6269566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
62718d228c0SPierre Jolivet         }
62818d228c0SPierre Jolivet       }
62918d228c0SPierre Jolivet     }
63018d228c0SPierre Jolivet   }
6319566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
63218d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
63318d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
63448a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
63518d228c0SPierre Jolivet     }
63618d228c0SPierre Jolivet   }
6379566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6388188e55aSJed Brown   (*B)->assembled = A->assembled;
6399566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6409566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6418188e55aSJed Brown   PetscFunctionReturn(0);
6428188e55aSJed Brown }
6438188e55aSJed Brown 
6449371c9d4SSatish Balay static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) {
645f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
64618d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
647f349c1fdSJed Brown 
648f349c1fdSJed Brown   PetscFunctionBegin;
6499566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6509566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
65118d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
65248a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
65318d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
65418d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6559566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
65618d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
657f349c1fdSJed Brown   PetscFunctionReturn(0);
658f349c1fdSJed Brown }
659f349c1fdSJed Brown 
66006a1af2fSStefano Zampini /*
66106a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
66206a1af2fSStefano Zampini */
6639371c9d4SSatish Balay static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) {
664f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
665f349c1fdSJed Brown   Mat       sub;
666f349c1fdSJed Brown 
667f349c1fdSJed Brown   PetscFunctionBegin;
6689566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
669f349c1fdSJed Brown   switch (reuse) {
670f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6719566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
672f349c1fdSJed Brown     *B = sub;
673f349c1fdSJed Brown     break;
6749371c9d4SSatish Balay   case MAT_REUSE_MATRIX: PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); break;
6759371c9d4SSatish Balay   case MAT_IGNORE_MATRIX: /* Nothing to do */ break;
6769371c9d4SSatish Balay   case MAT_INPLACE_MATRIX: /* Nothing to do */ SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
677f349c1fdSJed Brown   }
678f349c1fdSJed Brown   PetscFunctionReturn(0);
679f349c1fdSJed Brown }
680f349c1fdSJed Brown 
6819371c9d4SSatish Balay PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) {
682f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
683f349c1fdSJed Brown   Mat       sub;
684f349c1fdSJed Brown 
685f349c1fdSJed Brown   PetscFunctionBegin;
6869566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
687f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
6889566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
689f349c1fdSJed Brown   *B = sub;
690d8588912SDave May   PetscFunctionReturn(0);
691d8588912SDave May }
692d8588912SDave May 
6939371c9d4SSatish Balay static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) {
694f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
695f349c1fdSJed Brown   Mat       sub;
696d8588912SDave May 
697d8588912SDave May   PetscFunctionBegin;
6989566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
69908401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
700f349c1fdSJed Brown   if (sub) {
701aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7029566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
703d8588912SDave May   }
704d8588912SDave May   PetscFunctionReturn(0);
705d8588912SDave May }
706d8588912SDave May 
7079371c9d4SSatish Balay static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) {
7087874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7097874fa86SDave May   PetscInt  i;
7107874fa86SDave May 
7117874fa86SDave May   PetscFunctionBegin;
7127874fa86SDave May   for (i = 0; i < bA->nr; i++) {
713429bac76SJed Brown     Vec bv;
7149566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7157874fa86SDave May     if (bA->m[i][i]) {
7169566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7177874fa86SDave May     } else {
7189566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7197874fa86SDave May     }
7209566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7217874fa86SDave May   }
7227874fa86SDave May   PetscFunctionReturn(0);
7237874fa86SDave May }
7247874fa86SDave May 
7259371c9d4SSatish Balay static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) {
7267874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
727429bac76SJed Brown   Vec       bl, *br;
7287874fa86SDave May   PetscInt  i, j;
7297874fa86SDave May 
7307874fa86SDave May   PetscFunctionBegin;
7319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7322e6472ebSElliott Sales de Andrade   if (r) {
7339566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7342e6472ebSElliott Sales de Andrade   }
7352e6472ebSElliott Sales de Andrade   bl = NULL;
7367874fa86SDave May   for (i = 0; i < bA->nr; i++) {
73748a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7387874fa86SDave May     for (j = 0; j < bA->nc; j++) {
73948a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7407874fa86SDave May     }
74148a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7422e6472ebSElliott Sales de Andrade   }
7432e6472ebSElliott Sales de Andrade   if (r) {
7449566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7452e6472ebSElliott Sales de Andrade   }
7469566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7477874fa86SDave May   PetscFunctionReturn(0);
7487874fa86SDave May }
7497874fa86SDave May 
7509371c9d4SSatish Balay static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) {
751a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
752a061e289SJed Brown   PetscInt  i, j;
753a061e289SJed Brown 
754a061e289SJed Brown   PetscFunctionBegin;
755a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
756a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
75748a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
758a061e289SJed Brown     }
759a061e289SJed Brown   }
760a061e289SJed Brown   PetscFunctionReturn(0);
761a061e289SJed Brown }
762a061e289SJed Brown 
7639371c9d4SSatish Balay static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) {
764a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
765a061e289SJed Brown   PetscInt  i;
76606a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
767a061e289SJed Brown 
768a061e289SJed Brown   PetscFunctionBegin;
769a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
77006a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
77108401ef6SPierre 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);
7729566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
7739566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
77406a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
77506a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
776a061e289SJed Brown   }
77706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
778a061e289SJed Brown   PetscFunctionReturn(0);
779a061e289SJed Brown }
780a061e289SJed Brown 
7819371c9d4SSatish Balay static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) {
78213135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
78313135bc6SAlex Fikl   PetscInt  i;
78406a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
78513135bc6SAlex Fikl 
78613135bc6SAlex Fikl   PetscFunctionBegin;
78713135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
78806a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
78913135bc6SAlex Fikl     Vec              bv;
7909566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
79113135bc6SAlex Fikl     if (bA->m[i][i]) {
7929566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
7939566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
79413135bc6SAlex Fikl     }
7959566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
79606a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
79706a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
79813135bc6SAlex Fikl   }
79906a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
80013135bc6SAlex Fikl   PetscFunctionReturn(0);
80113135bc6SAlex Fikl }
80213135bc6SAlex Fikl 
8039371c9d4SSatish Balay static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) {
804f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
805f8170845SAlex Fikl   PetscInt  i, j;
806f8170845SAlex Fikl 
807f8170845SAlex Fikl   PetscFunctionBegin;
808f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
809f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
81048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
811f8170845SAlex Fikl     }
812f8170845SAlex Fikl   }
813f8170845SAlex Fikl   PetscFunctionReturn(0);
814f8170845SAlex Fikl }
815f8170845SAlex Fikl 
8169371c9d4SSatish Balay static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) {
817d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
818d8588912SDave May   Vec      *L, *R;
819d8588912SDave May   MPI_Comm  comm;
820d8588912SDave May   PetscInt  i, j;
821d8588912SDave May 
822d8588912SDave May   PetscFunctionBegin;
8239566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
824d8588912SDave May   if (right) {
825d8588912SDave May     /* allocate R */
8269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
827d8588912SDave May     /* Create the right vectors */
828d8588912SDave May     for (j = 0; j < bA->nc; j++) {
829d8588912SDave May       for (i = 0; i < bA->nr; i++) {
830d8588912SDave May         if (bA->m[i][j]) {
8319566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
832d8588912SDave May           break;
833d8588912SDave May         }
834d8588912SDave May       }
83508401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
836d8588912SDave May     }
8379566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
838d8588912SDave May     /* hand back control to the nest vector */
83948a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8409566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
841d8588912SDave May   }
842d8588912SDave May 
843d8588912SDave May   if (left) {
844d8588912SDave May     /* allocate L */
8459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
846d8588912SDave May     /* Create the left vectors */
847d8588912SDave May     for (i = 0; i < bA->nr; i++) {
848d8588912SDave May       for (j = 0; j < bA->nc; j++) {
849d8588912SDave May         if (bA->m[i][j]) {
8509566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
851d8588912SDave May           break;
852d8588912SDave May         }
853d8588912SDave May       }
85408401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
855d8588912SDave May     }
856d8588912SDave May 
8579566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
85848a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
859d8588912SDave May 
8609566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
861d8588912SDave May   }
862d8588912SDave May   PetscFunctionReturn(0);
863d8588912SDave May }
864d8588912SDave May 
8659371c9d4SSatish Balay static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) {
866d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
86729e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
868d8588912SDave May   PetscInt  i, j;
869d8588912SDave May 
870d8588912SDave May   PetscFunctionBegin;
8719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
872d8588912SDave May   if (isascii) {
8739566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
8749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object: \n"));
8759566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
8769566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n", bA->nr, bA->nc));
877d8588912SDave May 
8789566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure: \n"));
879d8588912SDave May     for (i = 0; i < bA->nr; i++) {
880d8588912SDave May       for (j = 0; j < bA->nc; j++) {
88119fd82e9SBarry Smith         MatType   type;
882270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
883d8588912SDave May         PetscInt  NR, NC;
884d8588912SDave May         PetscBool isNest = PETSC_FALSE;
885d8588912SDave May 
886d8588912SDave May         if (!bA->m[i][j]) {
8879566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n", i, j));
888d8588912SDave May           continue;
889d8588912SDave May         }
8909566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
8919566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
8929566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
8939566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
8949566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
895d8588912SDave May 
8969566063dSJacob 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));
897d8588912SDave May 
89829e60adbSStefano Zampini         if (isNest || viewSub) {
8999566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9009566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9019566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
902d8588912SDave May         }
903d8588912SDave May       }
904d8588912SDave May     }
9059566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
906d8588912SDave May   }
907d8588912SDave May   PetscFunctionReturn(0);
908d8588912SDave May }
909d8588912SDave May 
9109371c9d4SSatish Balay static PetscErrorCode MatZeroEntries_Nest(Mat A) {
911d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
912d8588912SDave May   PetscInt  i, j;
913d8588912SDave May 
914d8588912SDave May   PetscFunctionBegin;
915d8588912SDave May   for (i = 0; i < bA->nr; i++) {
916d8588912SDave May     for (j = 0; j < bA->nc; j++) {
917d8588912SDave May       if (!bA->m[i][j]) continue;
9189566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
919d8588912SDave May     }
920d8588912SDave May   }
921d8588912SDave May   PetscFunctionReturn(0);
922d8588912SDave May }
923d8588912SDave May 
9249371c9d4SSatish Balay static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) {
925c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
926c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
92706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
928c222c20dSDavid Ham 
929c222c20dSDavid Ham   PetscFunctionBegin;
930aed4548fSBarry 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);
931c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
932c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
93306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
93446a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9359566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
93608401ef6SPierre 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);
9379566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
93806a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
93906a1af2fSStefano Zampini       bB->nnzstate[i * nc + j] = subnnzstate;
940c222c20dSDavid Ham     }
941c222c20dSDavid Ham   }
94206a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
943c222c20dSDavid Ham   PetscFunctionReturn(0);
944c222c20dSDavid Ham }
945c222c20dSDavid Ham 
9469371c9d4SSatish Balay static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) {
9476e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
9486e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
94906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
9506e76ffeaSPierre Jolivet 
9516e76ffeaSPierre Jolivet   PetscFunctionBegin;
952aed4548fSBarry 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);
9536e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
9546e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
95506a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9566e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9579566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
958c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
959c066aebcSStefano Zampini         Mat M;
960c066aebcSStefano Zampini 
96108401ef6SPierre 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);
9629566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
9639566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
9649566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
965c066aebcSStefano Zampini       }
9669566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
96706a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
96806a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
9696e76ffeaSPierre Jolivet     }
9706e76ffeaSPierre Jolivet   }
97106a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
9726e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
9736e76ffeaSPierre Jolivet }
9746e76ffeaSPierre Jolivet 
9759371c9d4SSatish Balay static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) {
976d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
977841e96a3SJed Brown   Mat      *b;
978841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
979d8588912SDave May 
980d8588912SDave May   PetscFunctionBegin;
9819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
982841e96a3SJed Brown   for (i = 0; i < nr; i++) {
983841e96a3SJed Brown     for (j = 0; j < nc; j++) {
984841e96a3SJed Brown       if (bA->m[i][j]) {
9859566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
986841e96a3SJed Brown       } else {
9870298fd71SBarry Smith         b[i * nc + j] = NULL;
988d8588912SDave May       }
989d8588912SDave May     }
990d8588912SDave May   }
9919566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
992841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
99348a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
9949566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
995d8588912SDave May 
9969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
9979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
998d8588912SDave May   PetscFunctionReturn(0);
999d8588912SDave May }
1000d8588912SDave May 
1001d8588912SDave May /* nest api */
10029371c9d4SSatish Balay PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) {
1003d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10045fd66863SKarl Rupp 
1005d8588912SDave May   PetscFunctionBegin;
100608401ef6SPierre 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);
100708401ef6SPierre 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);
1008d8588912SDave May   *mat = bA->m[idxm][jdxm];
1009d8588912SDave May   PetscFunctionReturn(0);
1010d8588912SDave May }
1011d8588912SDave May 
10129ba0d327SJed Brown /*@
101311a5261eSBarry Smith  MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1014d8588912SDave May 
1015d8588912SDave May  Not collective
1016d8588912SDave May 
1017d8588912SDave May  Input Parameters:
101811a5261eSBarry Smith +   A  - `MATNEST` matrix
1019d8588912SDave May .   idxm - index of the matrix within the nest matrix
1020629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1021d8588912SDave May 
1022d8588912SDave May  Output Parameter:
1023d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
1024d8588912SDave May 
1025d8588912SDave May  Level: developer
1026d8588912SDave May 
102711a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`,
1028db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1029d8588912SDave May @*/
10309371c9d4SSatish Balay PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) {
1031d8588912SDave May   PetscFunctionBegin;
1032cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
1033d8588912SDave May   PetscFunctionReturn(0);
1034d8588912SDave May }
1035d8588912SDave May 
10369371c9d4SSatish Balay PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) {
10370782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
10380782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
10390782ca92SJed Brown 
10400782ca92SJed Brown   PetscFunctionBegin;
104108401ef6SPierre 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);
104208401ef6SPierre 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);
10439566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
10449566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
10459566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
10469566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
10479566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
10489566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1049aed4548fSBarry 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);
1050aed4548fSBarry 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);
105126fbe8dcSKarl Rupp 
105206a1af2fSStefano Zampini   /* do not increase object state */
105306a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
105406a1af2fSStefano Zampini 
10559566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
10569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
10570782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
10589566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
10599566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
106006a1af2fSStefano Zampini   A->nonzerostate++;
10610782ca92SJed Brown   PetscFunctionReturn(0);
10620782ca92SJed Brown }
10630782ca92SJed Brown 
10649ba0d327SJed Brown /*@
106511a5261eSBarry Smith  MatNestSetSubMat - Set a single submatrix in the `MATNEST`
10660782ca92SJed Brown 
10670782ca92SJed Brown  Logically collective on the submatrix communicator
10680782ca92SJed Brown 
10690782ca92SJed Brown  Input Parameters:
107011a5261eSBarry Smith +   A  - `MATNEST` matrix
10710782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
10720782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
10730782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
10740782ca92SJed Brown 
10750782ca92SJed Brown  Notes:
10760782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
10770782ca92SJed Brown 
10780782ca92SJed Brown  This increments the reference count of the submatrix.
10790782ca92SJed Brown 
10800782ca92SJed Brown  Level: developer
10810782ca92SJed Brown 
108211a5261eSBarry Smith .seealso: `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1083db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
10840782ca92SJed Brown @*/
10859371c9d4SSatish Balay PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) {
10860782ca92SJed Brown   PetscFunctionBegin;
1087cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
10880782ca92SJed Brown   PetscFunctionReturn(0);
10890782ca92SJed Brown }
10900782ca92SJed Brown 
10919371c9d4SSatish Balay PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) {
1092d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10935fd66863SKarl Rupp 
1094d8588912SDave May   PetscFunctionBegin;
109526fbe8dcSKarl Rupp   if (M) *M = bA->nr;
109626fbe8dcSKarl Rupp   if (N) *N = bA->nc;
109726fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1098d8588912SDave May   PetscFunctionReturn(0);
1099d8588912SDave May }
1100d8588912SDave May 
1101d8588912SDave May /*@C
110211a5261eSBarry Smith  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1103d8588912SDave May 
1104d8588912SDave May  Not collective
1105d8588912SDave May 
1106f899ff85SJose E. Roman  Input Parameter:
1107629881c0SJed Brown .   A  - nest matrix
1108d8588912SDave May 
1109d8d19677SJose E. Roman  Output Parameters:
1110629881c0SJed Brown +   M - number of rows in the nest matrix
1111d8588912SDave May .   N - number of cols in the nest matrix
1112629881c0SJed Brown -   mat - 2d array of matrices
1113d8588912SDave May 
111411a5261eSBarry Smith  Note:
1115d8588912SDave May  The user should not free the array mat.
1116d8588912SDave May 
111711a5261eSBarry Smith  Fortran Note:
111811a5261eSBarry Smith  This routine has a calling sequence
1119351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
1120351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1121351962e3SVincent Le Chenadec 
1122d8588912SDave May  Level: developer
1123d8588912SDave May 
112411a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1125db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1126d8588912SDave May @*/
11279371c9d4SSatish Balay PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) {
1128d8588912SDave May   PetscFunctionBegin;
1129cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
1130d8588912SDave May   PetscFunctionReturn(0);
1131d8588912SDave May }
1132d8588912SDave May 
11339371c9d4SSatish Balay PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) {
1134d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1135d8588912SDave May 
1136d8588912SDave May   PetscFunctionBegin;
113726fbe8dcSKarl Rupp   if (M) *M = bA->nr;
113826fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1139d8588912SDave May   PetscFunctionReturn(0);
1140d8588912SDave May }
1141d8588912SDave May 
11429ba0d327SJed Brown /*@
114311a5261eSBarry Smith  MatNestGetSize - Returns the size of the `MATNEST` matrix.
1144d8588912SDave May 
1145d8588912SDave May  Not collective
1146d8588912SDave May 
1147f899ff85SJose E. Roman  Input Parameter:
114811a5261eSBarry Smith .   A  - `MATNEST` matrix
1149d8588912SDave May 
1150d8d19677SJose E. Roman  Output Parameters:
1151629881c0SJed Brown +   M - number of rows in the nested mat
1152629881c0SJed Brown -   N - number of cols in the nested mat
1153d8588912SDave May 
1154d8588912SDave May  Level: developer
1155d8588912SDave May 
115611a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1157db781477SPatrick Sanan           `MatNestGetISs()`
1158d8588912SDave May @*/
11599371c9d4SSatish Balay PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) {
1160d8588912SDave May   PetscFunctionBegin;
1161cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
1162d8588912SDave May   PetscFunctionReturn(0);
1163d8588912SDave May }
1164d8588912SDave May 
11659371c9d4SSatish Balay static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) {
1166900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1167900e7ff2SJed Brown   PetscInt  i;
1168900e7ff2SJed Brown 
1169900e7ff2SJed Brown   PetscFunctionBegin;
11709371c9d4SSatish Balay   if (rows)
11719371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
11729371c9d4SSatish Balay   if (cols)
11739371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
1174900e7ff2SJed Brown   PetscFunctionReturn(0);
1175900e7ff2SJed Brown }
1176900e7ff2SJed Brown 
11773a4d7b9aSSatish Balay /*@C
117811a5261eSBarry Smith  MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1179900e7ff2SJed Brown 
1180900e7ff2SJed Brown  Not collective
1181900e7ff2SJed Brown 
1182f899ff85SJose E. Roman  Input Parameter:
118311a5261eSBarry Smith .   A  - `MATNEST` matrix
1184900e7ff2SJed Brown 
1185d8d19677SJose E. Roman  Output Parameters:
1186900e7ff2SJed Brown +   rows - array of row index sets
1187900e7ff2SJed Brown -   cols - array of column index sets
1188900e7ff2SJed Brown 
1189900e7ff2SJed Brown  Level: advanced
1190900e7ff2SJed Brown 
119111a5261eSBarry Smith  Note:
1192900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1193900e7ff2SJed Brown 
119411a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`,
1195db781477SPatrick Sanan           `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()`
1196900e7ff2SJed Brown @*/
11979371c9d4SSatish Balay PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) {
1198900e7ff2SJed Brown   PetscFunctionBegin;
1199900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1200cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1201900e7ff2SJed Brown   PetscFunctionReturn(0);
1202900e7ff2SJed Brown }
1203900e7ff2SJed Brown 
12049371c9d4SSatish Balay static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) {
1205900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1206900e7ff2SJed Brown   PetscInt  i;
1207900e7ff2SJed Brown 
1208900e7ff2SJed Brown   PetscFunctionBegin;
12099371c9d4SSatish Balay   if (rows)
12109371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12119371c9d4SSatish Balay   if (cols)
12129371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
1213900e7ff2SJed Brown   PetscFunctionReturn(0);
1214900e7ff2SJed Brown }
1215900e7ff2SJed Brown 
1216900e7ff2SJed Brown /*@C
121711a5261eSBarry Smith  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1218900e7ff2SJed Brown 
1219900e7ff2SJed Brown  Not collective
1220900e7ff2SJed Brown 
1221f899ff85SJose E. Roman  Input Parameter:
122211a5261eSBarry Smith .   A  - `MATNEST` matrix
1223900e7ff2SJed Brown 
1224d8d19677SJose E. Roman  Output Parameters:
12250298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
12260298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1227900e7ff2SJed Brown 
1228900e7ff2SJed Brown  Level: advanced
1229900e7ff2SJed Brown 
123011a5261eSBarry Smith  Note:
1231900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1232900e7ff2SJed Brown 
123311a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1234db781477SPatrick Sanan           `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()`
1235900e7ff2SJed Brown @*/
12369371c9d4SSatish Balay PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) {
1237900e7ff2SJed Brown   PetscFunctionBegin;
1238900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1239cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1240900e7ff2SJed Brown   PetscFunctionReturn(0);
1241900e7ff2SJed Brown }
1242900e7ff2SJed Brown 
12439371c9d4SSatish Balay PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) {
1244207556f9SJed Brown   PetscBool flg;
1245207556f9SJed Brown 
1246207556f9SJed Brown   PetscFunctionBegin;
12479566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1248207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
12492a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
125012b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0;
1251207556f9SJed Brown   PetscFunctionReturn(0);
1252207556f9SJed Brown }
1253207556f9SJed Brown 
1254207556f9SJed Brown /*@C
125511a5261eSBarry Smith  MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1256207556f9SJed Brown 
1257207556f9SJed Brown  Not collective
1258207556f9SJed Brown 
1259207556f9SJed Brown  Input Parameters:
126011a5261eSBarry Smith +  A  - `MATNEST` matrix
126111a5261eSBarry Smith -  vtype - `VecType` to use for creating vectors
1262207556f9SJed Brown 
1263207556f9SJed Brown  Level: developer
1264207556f9SJed Brown 
126511a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateVecs()`, `MATNEST`, `MatCreateNest()`, `VecType`
1266207556f9SJed Brown @*/
12679371c9d4SSatish Balay PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) {
1268207556f9SJed Brown   PetscFunctionBegin;
1269cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
1270207556f9SJed Brown   PetscFunctionReturn(0);
1271207556f9SJed Brown }
1272207556f9SJed Brown 
12739371c9d4SSatish Balay PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) {
1274c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1275c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
127688ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
127788ffe2e8SJose E. Roman   VecType   vtype, type;
1278d8588912SDave May 
1279d8588912SDave May   PetscFunctionBegin;
12809566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
128106a1af2fSStefano Zampini 
1282c8883902SJed Brown   s->nr = nr;
1283c8883902SJed Brown   s->nc = nc;
1284d8588912SDave May 
1285c8883902SJed Brown   /* Create space for submatrices */
12869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
128748a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i]));
1288c8883902SJed Brown   for (i = 0; i < nr; i++) {
1289c8883902SJed Brown     for (j = 0; j < nc; j++) {
1290c8883902SJed Brown       s->m[i][j] = a[i * nc + j];
129148a46eb9SPierre Jolivet       if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j]));
1292d8588912SDave May     }
1293d8588912SDave May   }
12949566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
12959566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
129688ffe2e8SJose E. Roman   if (isstd) {
129788ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
129888ffe2e8SJose E. Roman     vtype = NULL;
129988ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
130088ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
130188ffe2e8SJose E. Roman         if (a[i * nc + j]) {
130288ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13039566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &vtype));
130488ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
130588ffe2e8SJose E. Roman           } else if (sametype) {
13069566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i * nc + j], &type));
13079566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
130888ffe2e8SJose E. Roman           }
130988ffe2e8SJose E. Roman         }
131088ffe2e8SJose E. Roman       }
131188ffe2e8SJose E. Roman     }
131288ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
13139566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
131488ffe2e8SJose E. Roman     }
131588ffe2e8SJose E. Roman   }
1316d8588912SDave May 
13179566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1318d8588912SDave May 
13199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
13209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1321c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1322c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1323d8588912SDave May 
13249566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
132506a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
132606a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
132748a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
132806a1af2fSStefano Zampini     }
132906a1af2fSStefano Zampini   }
133006a1af2fSStefano Zampini 
13319566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1332d8588912SDave May 
13339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
13349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
13359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
13369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1337c8883902SJed Brown 
13389566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
13399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1340c8883902SJed Brown 
134106a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
134206a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
13439566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
134406a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
134506a1af2fSStefano Zampini   if (cong) {
134648a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
134706a1af2fSStefano Zampini   }
134806a1af2fSStefano Zampini   if (!cong) {
1349381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
135006a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
135106a1af2fSStefano Zampini     A->ops->shift           = NULL;
135206a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
135306a1af2fSStefano Zampini   }
135406a1af2fSStefano Zampini 
13559566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
13569566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
135706a1af2fSStefano Zampini   A->nonzerostate++;
1358d8588912SDave May   PetscFunctionReturn(0);
1359d8588912SDave May }
1360d8588912SDave May 
1361c8883902SJed Brown /*@
136211a5261eSBarry Smith    MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1363c8883902SJed Brown 
136411a5261eSBarry Smith    Collective on A
1365c8883902SJed Brown 
1366d8d19677SJose E. Roman    Input Parameters:
136711a5261eSBarry Smith +  A - `MATNEST` matrix
1368c8883902SJed Brown .  nr - number of nested row blocks
13690298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1370c8883902SJed Brown .  nc - number of nested column blocks
13710298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
13720298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1373c8883902SJed Brown 
137411a5261eSBarry Smith    Note:
137511a5261eSBarry Smith    This always resets any submatrix information previously set
137606a1af2fSStefano Zampini 
1377c8883902SJed Brown    Level: advanced
1378c8883902SJed Brown 
137911a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1380c8883902SJed Brown @*/
13819371c9d4SSatish Balay PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) {
138206a1af2fSStefano Zampini   PetscInt i;
1383c8883902SJed Brown 
1384c8883902SJed Brown   PetscFunctionBegin;
1385c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
138608401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1387c8883902SJed Brown   if (nr && is_row) {
1388c8883902SJed Brown     PetscValidPointer(is_row, 3);
1389c8883902SJed Brown     for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1390c8883902SJed Brown   }
139108401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
13921664e352SJed Brown   if (nc && is_col) {
1393c8883902SJed Brown     PetscValidPointer(is_col, 5);
13949b30a8f6SBarry Smith     for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1395c8883902SJed Brown   }
139606a1af2fSStefano Zampini   if (nr * nc > 0) PetscValidPointer(a, 6);
1397cac4c232SBarry Smith   PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
1398c8883902SJed Brown   PetscFunctionReturn(0);
1399c8883902SJed Brown }
1400d8588912SDave May 
14019371c9d4SSatish Balay static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) {
140277019fcaSJed Brown   PetscBool flg;
140377019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
140477019fcaSJed Brown 
140577019fcaSJed Brown   PetscFunctionBegin;
1406aea6d515SStefano Zampini   *ltog = NULL;
140777019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
140877019fcaSJed Brown     if (islocal[i]) {
14099566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
141077019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
141177019fcaSJed Brown     } else {
14129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
141377019fcaSJed Brown     }
141477019fcaSJed Brown     m += mi;
141577019fcaSJed Brown   }
1416aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1417aea6d515SStefano Zampini 
14189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1419165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
14200298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1421e108cb99SStefano Zampini     Mat                    sub  = NULL;
1422f6d38dbbSStefano Zampini     PetscSF                sf;
1423f6d38dbbSStefano Zampini     PetscLayout            map;
1424aea6d515SStefano Zampini     const PetscInt        *ix2;
142577019fcaSJed Brown 
1426165cd838SBarry Smith     if (!colflg) {
14279566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
142877019fcaSJed Brown     } else {
14299566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
143077019fcaSJed Brown     }
1431191fd14bSBarry Smith     if (sub) {
1432191fd14bSBarry Smith       if (!colflg) {
14339566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1434191fd14bSBarry Smith       } else {
14359566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1436191fd14bSBarry Smith       }
1437191fd14bSBarry Smith     }
143877019fcaSJed Brown     /*
143977019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
144077019fcaSJed 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.
144177019fcaSJed Brown     */
14429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1443aea6d515SStefano Zampini     if (islocal[i]) {
1444aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1445aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1446aea6d515SStefano Zampini 
14479566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
144828b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1449aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
14509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1451aea6d515SStefano Zampini 
1452aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
14539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1454aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1455aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1456aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1457aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1458aea6d515SStefano Zampini         nleaves++;
1459aea6d515SStefano Zampini       }
14609566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
14619566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
14629566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
14639566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
14649566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
14659566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
14669566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
14679566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
14689566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
14699566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
14709566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1471aea6d515SStefano Zampini     } else {
14729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1473aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1474aea6d515SStefano Zampini     }
14759566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
147677019fcaSJed Brown     m += mi;
147777019fcaSJed Brown   }
14789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
147977019fcaSJed Brown   PetscFunctionReturn(0);
148077019fcaSJed Brown }
148177019fcaSJed Brown 
1482d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1483d8588912SDave May /*
1484d8588912SDave May   nprocessors = NP
1485d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1486d8588912SDave May        proc 0: => (g_0,h_0,)
1487d8588912SDave May        proc 1: => (g_1,h_1,)
1488d8588912SDave May        ...
1489d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1490d8588912SDave May 
1491d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1492d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1493d8588912SDave May 
1494d8588912SDave May             proc 0:
1495d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1496d8588912SDave May             proc 1:
1497d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1498d8588912SDave May 
1499d8588912SDave May             proc NP-1:
1500d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1501d8588912SDave May */
15029371c9d4SSatish Balay static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) {
1503e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
15048188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
15050298fd71SBarry Smith   Mat       sub = NULL;
1506d8588912SDave May 
1507d8588912SDave May   PetscFunctionBegin;
15089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
15099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1510d8588912SDave May   if (is_row) { /* valid IS is passed in */
1511a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1512e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15139566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
151426fbe8dcSKarl Rupp 
1515e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1516d8588912SDave May     }
15172ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
15188188e55aSJed Brown     nsum = 0;
15198188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
15209566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
152128b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
15229566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
152308401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15248188e55aSJed Brown       nsum += n;
15258188e55aSJed Brown     }
15269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
152730bc264bSJed Brown     offset -= nsum;
1528e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
15299566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15309566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
15319566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15329566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
15339566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
15342ae74bdbSJed Brown       offset += n;
1535d8588912SDave May     }
1536d8588912SDave May   }
1537d8588912SDave May 
1538d8588912SDave May   if (is_col) { /* valid IS is passed in */
1539a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1540e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
15419566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
154226fbe8dcSKarl Rupp 
1543e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1544d8588912SDave May     }
15452ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
15462ae74bdbSJed Brown     offset = A->cmap->rstart;
15478188e55aSJed Brown     nsum   = 0;
15488188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
15499566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
155028b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
15519566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
155208401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
15538188e55aSJed Brown       nsum += n;
15548188e55aSJed Brown     }
15559566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
155630bc264bSJed Brown     offset -= nsum;
1557e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
15589566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
15599566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
15609566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
15619566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
15629566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
15632ae74bdbSJed Brown       offset += n;
1564d8588912SDave May     }
1565d8588912SDave May   }
1566e2d7f03fSJed Brown 
1567e2d7f03fSJed Brown   /* Set up the local ISs */
15689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
15699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1570e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1571e2d7f03fSJed Brown     IS                     isloc;
15720298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1573e2d7f03fSJed Brown     PetscInt               nlocal, bs;
15749566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
15759566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1576207556f9SJed Brown     if (rmap) {
15779566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
15789566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
15799566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
15809566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1581207556f9SJed Brown     } else {
1582207556f9SJed Brown       nlocal = 0;
15830298fd71SBarry Smith       isloc  = NULL;
1584207556f9SJed Brown     }
1585e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1586e2d7f03fSJed Brown     offset += nlocal;
1587e2d7f03fSJed Brown   }
15888188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1589e2d7f03fSJed Brown     IS                     isloc;
15900298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1591e2d7f03fSJed Brown     PetscInt               nlocal, bs;
15929566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
15939566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1594207556f9SJed Brown     if (cmap) {
15959566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
15969566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
15979566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
15989566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1599207556f9SJed Brown     } else {
1600207556f9SJed Brown       nlocal = 0;
16010298fd71SBarry Smith       isloc  = NULL;
1602207556f9SJed Brown     }
1603e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1604e2d7f03fSJed Brown     offset += nlocal;
1605e2d7f03fSJed Brown   }
16060189643fSJed Brown 
160777019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
160877019fcaSJed Brown   {
160945b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
16109566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
16119566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
16129566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
16139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
16149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
161577019fcaSJed Brown   }
161677019fcaSJed Brown 
161776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
16180189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
16190189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
16200189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
16210189643fSJed Brown         Mat      B = vs->m[i][j];
16220189643fSJed Brown         if (!B) continue;
16239566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
16249566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
16259566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
16269566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
16279566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
16289566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1629aed4548fSBarry 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);
1630aed4548fSBarry 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);
16310189643fSJed Brown       }
16320189643fSJed Brown     }
163376bd3646SJed Brown   }
1634a061e289SJed Brown 
1635a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1636a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1637a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
1638a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1639a061e289SJed Brown     }
1640a061e289SJed Brown   }
1641a061e289SJed Brown   A->assembled = PETSC_TRUE;
1642d8588912SDave May   PetscFunctionReturn(0);
1643d8588912SDave May }
1644d8588912SDave May 
164545c38901SJed Brown /*@C
164611a5261eSBarry Smith    MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1647659c6bb0SJed Brown 
164811a5261eSBarry Smith    Collective
1649659c6bb0SJed Brown 
1650d8d19677SJose E. Roman    Input Parameters:
165111a5261eSBarry Smith +  comm - Communicator for the new `MATNEST`
1652659c6bb0SJed Brown .  nr - number of nested row blocks
16530298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1654659c6bb0SJed Brown .  nc - number of nested column blocks
16550298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
16560298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1657659c6bb0SJed Brown 
1658659c6bb0SJed Brown    Output Parameter:
1659659c6bb0SJed Brown .  B - new matrix
1660659c6bb0SJed Brown 
1661659c6bb0SJed Brown    Level: advanced
1662659c6bb0SJed Brown 
166311a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MATNEST`, `MatNestSetSubMat()`,
1664db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1665db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1666659c6bb0SJed Brown @*/
16679371c9d4SSatish Balay PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) {
1668d8588912SDave May   Mat A;
1669d8588912SDave May 
1670d8588912SDave May   PetscFunctionBegin;
1671f4259b30SLisandro Dalcin   *B = NULL;
16729566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
16739566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATNEST));
167491a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
16759566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a));
1676d8588912SDave May   *B = A;
1677d8588912SDave May   PetscFunctionReturn(0);
1678d8588912SDave May }
1679659c6bb0SJed Brown 
16809371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
1681b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
168223875855Sstefano_zampini   Mat          *trans;
1683b68353e5Sstefano_zampini   PetscScalar **avv;
1684b68353e5Sstefano_zampini   PetscScalar  *vv;
1685b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1686b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1687b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1688b68353e5Sstefano_zampini   PetscBool     done;
1689b68353e5Sstefano_zampini 
1690b68353e5Sstefano_zampini   PetscFunctionBegin;
16919566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1692b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1693b68353e5Sstefano_zampini     PetscInt rnr;
1694b68353e5Sstefano_zampini 
16959566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
169628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
169708401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
16989566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1699b68353e5Sstefano_zampini   }
1700b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1701b68353e5Sstefano_zampini   nnz = 0;
17029566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1703b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1704b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1705b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1706b68353e5Sstefano_zampini       if (B) {
1707b68353e5Sstefano_zampini         PetscScalar *naa;
1708b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
170923875855Sstefano_zampini         PetscBool    istrans;
1710b68353e5Sstefano_zampini 
1711*013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
171223875855Sstefano_zampini         if (istrans) {
171323875855Sstefano_zampini           Mat Bt;
171423875855Sstefano_zampini 
17159566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
17169566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
171723875855Sstefano_zampini           B = trans[i * nest->nc + j];
1718*013e2dc7SBarry Smith         } else {
1719*013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1720*013e2dc7SBarry Smith           if (istrans) {
1721*013e2dc7SBarry Smith             Mat Bt;
1722*013e2dc7SBarry Smith 
1723*013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1724*013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1725*013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1726*013e2dc7SBarry Smith           }
172723875855Sstefano_zampini         }
17289566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
172928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
17309566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1731b68353e5Sstefano_zampini         nnz += nii[nnr];
1732b68353e5Sstefano_zampini 
1733b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1734b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1735b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1736b68353e5Sstefano_zampini       }
1737b68353e5Sstefano_zampini     }
1738b68353e5Sstefano_zampini   }
1739b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
17409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
17419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
17429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1743b68353e5Sstefano_zampini   } else {
174408401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1745b68353e5Sstefano_zampini   }
1746b68353e5Sstefano_zampini 
1747b68353e5Sstefano_zampini   /* new row pointer */
17489566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1749b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1750b68353e5Sstefano_zampini     PetscInt ncr, rst;
1751b68353e5Sstefano_zampini 
17529566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
17539566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1754b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1755b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1756b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1757b68353e5Sstefano_zampini         PetscInt  ir;
1758b68353e5Sstefano_zampini 
1759b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1760b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1761b68353e5Sstefano_zampini           nii++;
1762b68353e5Sstefano_zampini         }
1763b68353e5Sstefano_zampini       }
1764b68353e5Sstefano_zampini     }
1765b68353e5Sstefano_zampini   }
1766b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1767b68353e5Sstefano_zampini 
1768b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
17699566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1770b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1771b68353e5Sstefano_zampini     PetscInt ncr, rst;
1772b68353e5Sstefano_zampini 
17739566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
17749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1775b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1776b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1777b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i * nest->nc + j];
1778b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1779b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1780b68353e5Sstefano_zampini         PetscInt     ir, cst;
1781b68353e5Sstefano_zampini 
17829566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1783b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1784b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1785b68353e5Sstefano_zampini 
1786b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1787b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1788b68353e5Sstefano_zampini             vv[ist + ij] = *nvv;
1789b68353e5Sstefano_zampini             njj++;
1790b68353e5Sstefano_zampini             nvv++;
1791b68353e5Sstefano_zampini           }
1792b68353e5Sstefano_zampini           ci[ir] += rsize;
1793b68353e5Sstefano_zampini           nii++;
1794b68353e5Sstefano_zampini         }
1795b68353e5Sstefano_zampini       }
1796b68353e5Sstefano_zampini     }
1797b68353e5Sstefano_zampini   }
17989566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1799b68353e5Sstefano_zampini 
1800b68353e5Sstefano_zampini   /* restore info */
1801b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1802b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1803b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1804b68353e5Sstefano_zampini       if (B) {
1805b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
180623875855Sstefano_zampini 
180723875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
18089566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
180928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
18109566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
18119566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1812b68353e5Sstefano_zampini       }
1813b68353e5Sstefano_zampini     }
1814b68353e5Sstefano_zampini   }
18159566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1816b68353e5Sstefano_zampini 
1817b68353e5Sstefano_zampini   /* finalize newmat */
1818b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
18199566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1820b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1821b68353e5Sstefano_zampini     Mat B;
1822b68353e5Sstefano_zampini 
18239566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
18249566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1825b68353e5Sstefano_zampini   }
18269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
18279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1828b68353e5Sstefano_zampini   {
1829b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1830b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1831b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1832b68353e5Sstefano_zampini   }
1833b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1834b68353e5Sstefano_zampini }
1835b68353e5Sstefano_zampini 
18369371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) {
1837be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1838be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1839be705e3aSPierre Jolivet   PetscBool flg;
1840be705e3aSPierre Jolivet 
1841be705e3aSPierre Jolivet   PetscFunctionBegin;
1842be705e3aSPierre Jolivet   /* Fill by row */
1843be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1844be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1845be705e3aSPierre Jolivet     IS              bNis;
1846be705e3aSPierre Jolivet     PetscInt        bN;
1847be705e3aSPierre Jolivet     const PetscInt *bNindices;
18489566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
18499566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
18509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1851be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1852fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1853be705e3aSPierre Jolivet       PetscInt        bm, br;
1854be705e3aSPierre Jolivet       const PetscInt *bmindices;
1855be705e3aSPierre Jolivet       if (!B) continue;
1856*013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1857be705e3aSPierre Jolivet       if (flg) {
1858cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1859cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
18609566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1861be705e3aSPierre Jolivet         B = D;
1862be705e3aSPierre Jolivet       }
18639566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1864be705e3aSPierre Jolivet       if (flg) {
1865fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1866fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1867be705e3aSPierre Jolivet         B = D;
1868be705e3aSPierre Jolivet       }
18699566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
18709566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
18719566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1872be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1873be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1874be705e3aSPierre Jolivet         const PetscInt    *brcols;
1875be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1876be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
18779566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
18789566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1879be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1880be705e3aSPierre Jolivet         /*
1881be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1882be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1883be705e3aSPierre Jolivet          */
1884be705e3aSPierre Jolivet         if (a != 1.0) {
18859566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1886be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
18879566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
18889566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1889be705e3aSPierre Jolivet         } else {
18909566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
1891be705e3aSPierre Jolivet         }
18929566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
18939566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1894be705e3aSPierre Jolivet       }
1895fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
18969566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
1897be705e3aSPierre Jolivet     }
18989566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
18999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1900be705e3aSPierre Jolivet   }
19019566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
19029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
1903be705e3aSPierre Jolivet   PetscFunctionReturn(0);
1904be705e3aSPierre Jolivet }
1905be705e3aSPierre Jolivet 
19069371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
1907629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
1908be705e3aSPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz, rstart, cstart, cend;
1909b68353e5Sstefano_zampini   PetscMPIInt size;
1910629c3df2SDmitry Karpeev   Mat         C;
1911629c3df2SDmitry Karpeev 
1912629c3df2SDmitry Karpeev   PetscFunctionBegin;
19139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1914b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1915b68353e5Sstefano_zampini     PetscInt  nf;
1916b68353e5Sstefano_zampini     PetscBool fast;
1917b68353e5Sstefano_zampini 
19189566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
191948a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
1920b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
1921b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
1922b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1923b68353e5Sstefano_zampini         if (B) {
19249566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
192523875855Sstefano_zampini           if (!fast) {
192623875855Sstefano_zampini             PetscBool istrans;
192723875855Sstefano_zampini 
1928*013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
192923875855Sstefano_zampini             if (istrans) {
193023875855Sstefano_zampini               Mat Bt;
193123875855Sstefano_zampini 
19329566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
19339566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1934*013e2dc7SBarry Smith             } else {
1935*013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1936*013e2dc7SBarry Smith               if (istrans) {
1937*013e2dc7SBarry Smith                 Mat Bt;
1938*013e2dc7SBarry Smith 
1939*013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1940*013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
1941*013e2dc7SBarry Smith               }
194223875855Sstefano_zampini             }
1943b68353e5Sstefano_zampini           }
1944b68353e5Sstefano_zampini         }
1945b68353e5Sstefano_zampini       }
1946b68353e5Sstefano_zampini     }
1947b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
19489566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
1949b68353e5Sstefano_zampini       if (fast) {
1950b68353e5Sstefano_zampini         PetscInt f, s;
1951b68353e5Sstefano_zampini 
19529566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
19539371c9d4SSatish Balay         if (f != nf || s != 1) {
19549371c9d4SSatish Balay           fast = PETSC_FALSE;
19559371c9d4SSatish Balay         } else {
19569566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
1957b68353e5Sstefano_zampini           nf += f;
1958b68353e5Sstefano_zampini         }
1959b68353e5Sstefano_zampini       }
1960b68353e5Sstefano_zampini     }
1961b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
19629566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
1963b68353e5Sstefano_zampini       if (fast) {
1964b68353e5Sstefano_zampini         PetscInt f, s;
1965b68353e5Sstefano_zampini 
19669566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
19679371c9d4SSatish Balay         if (f != nf || s != 1) {
19689371c9d4SSatish Balay           fast = PETSC_FALSE;
19699371c9d4SSatish Balay         } else {
19709566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
1971b68353e5Sstefano_zampini           nf += f;
1972b68353e5Sstefano_zampini         }
1973b68353e5Sstefano_zampini       }
1974b68353e5Sstefano_zampini     }
1975b68353e5Sstefano_zampini     if (fast) {
19769566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
1977b68353e5Sstefano_zampini       PetscFunctionReturn(0);
1978b68353e5Sstefano_zampini     }
1979b68353e5Sstefano_zampini   }
19809566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
19819566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
19829566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
1983d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
1984d1487292SPierre Jolivet   else {
19859566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
19869566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
19879566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1988629c3df2SDmitry Karpeev   }
19899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
1990629c3df2SDmitry Karpeev   onnz = dnnz + m;
1991629c3df2SDmitry Karpeev   for (k = 0; k < m; k++) {
1992629c3df2SDmitry Karpeev     dnnz[k] = 0;
1993629c3df2SDmitry Karpeev     onnz[k] = 0;
1994629c3df2SDmitry Karpeev   }
1995629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
1996629c3df2SDmitry Karpeev     IS              bNis;
1997629c3df2SDmitry Karpeev     PetscInt        bN;
1998629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1999fd8a7442SPierre Jolivet     PetscBool       flg;
2000629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20019566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20029566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20039566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2004629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2005629c3df2SDmitry Karpeev       PetscSF         bmsf;
2006649b366bSFande Kong       PetscSFNode    *iremote;
2007fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2008649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2009629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2010629c3df2SDmitry Karpeev       if (!B) continue;
20119566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20129566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20139566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
20149566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
20159566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
20169566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2017649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2018649b366bSFande Kong         sub_dnnz[k] = 0;
2019649b366bSFande Kong         sub_onnz[k] = 0;
2020649b366bSFande Kong       }
2021*013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &flg));
2022fd8a7442SPierre Jolivet       if (flg) {
2023fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2024fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2025fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2026fd8a7442SPierre Jolivet         B = D;
2027fd8a7442SPierre Jolivet       }
2028fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2029fd8a7442SPierre Jolivet       if (flg) {
2030fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2031fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2032fd8a7442SPierre Jolivet         B = D;
2033fd8a7442SPierre Jolivet       }
2034629c3df2SDmitry Karpeev       /*
2035629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2036629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2037629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2038629c3df2SDmitry Karpeev        */
20399566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2040629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2041131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2042629c3df2SDmitry Karpeev         const PetscInt *brcols;
2043a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2044131c27b5Sprj-         PetscMPIInt     rowowner = 0;
20459566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2046649b366bSFande Kong         /* how many roots  */
20479371c9d4SSatish Balay         iremote[br].rank  = rowowner;
20489371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2049649b366bSFande Kong         /* get nonzero pattern */
20509566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2051629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2052629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2053649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2054649b366bSFande Kong             sub_dnnz[br]++;
2055649b366bSFande Kong           } else {
2056649b366bSFande Kong             sub_onnz[br]++;
2057649b366bSFande Kong           }
2058629c3df2SDmitry Karpeev         }
20599566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2060629c3df2SDmitry Karpeev       }
2061fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
20629566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2063629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
20649566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
20659566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
20669566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
20679566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
20689566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
20699566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
20709566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
20719566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2072629c3df2SDmitry Karpeev     }
20739566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
20749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
207565a4a0a3Sstefano_zampini   }
207665a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
207765a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
207865a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
207965a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2080629c3df2SDmitry Karpeev   }
20819566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
20829566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
20839566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
20849566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2085d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
20869566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2087d1487292SPierre Jolivet   } else *newmat = C;
2088be705e3aSPierre Jolivet   PetscFunctionReturn(0);
2089be705e3aSPierre Jolivet }
2090629c3df2SDmitry Karpeev 
20919371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
2092629c3df2SDmitry Karpeev   Mat      B;
2093be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2094be705e3aSPierre Jolivet 
2095be705e3aSPierre Jolivet   PetscFunctionBegin;
20969566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20979566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2098be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2099be705e3aSPierre Jolivet     B = *newmat;
21009566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2101be705e3aSPierre Jolivet   } else {
21029566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2103629c3df2SDmitry Karpeev   }
21049566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2105be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21069566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2107be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2108629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
2109629c3df2SDmitry Karpeev }
2110629c3df2SDmitry Karpeev 
21119371c9d4SSatish Balay PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) {
21128b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
21133c6db4c4SPierre Jolivet   MatOperation opAdd;
21148b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
21158b7d3b4bSBarry Smith   PetscBool    flg;
211652c5f739Sprj-   PetscFunctionBegin;
21178b7d3b4bSBarry Smith 
211852c5f739Sprj-   *has = PETSC_FALSE;
21193c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21203c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21218b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
21228b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
21238b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21249566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
21258b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
21268b7d3b4bSBarry Smith       }
21278b7d3b4bSBarry Smith     }
21288b7d3b4bSBarry Smith   }
21293c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
21308b7d3b4bSBarry Smith   PetscFunctionReturn(0);
21318b7d3b4bSBarry Smith }
21328b7d3b4bSBarry Smith 
2133659c6bb0SJed Brown /*MC
2134659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2135659c6bb0SJed Brown 
2136659c6bb0SJed Brown   Level: intermediate
2137659c6bb0SJed Brown 
2138659c6bb0SJed Brown   Notes:
213911a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2140659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
214111a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2142659c6bb0SJed Brown 
21438b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
21448b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
21458b7d3b4bSBarry Smith   than the nest matrix.
21468b7d3b4bSBarry Smith 
214711a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2148db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2149db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2150659c6bb0SJed Brown M*/
21519371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) {
2152c8883902SJed Brown   Mat_Nest *s;
2153c8883902SJed Brown 
2154c8883902SJed Brown   PetscFunctionBegin;
21559566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A, &s));
2156c8883902SJed Brown   A->data = (void *)s;
2157e7c19651SJed Brown 
2158e7c19651SJed Brown   s->nr            = -1;
2159e7c19651SJed Brown   s->nc            = -1;
21600298fd71SBarry Smith   s->m             = NULL;
2161e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2162c8883902SJed Brown 
21639566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
216426fbe8dcSKarl Rupp 
2165c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
21669194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2167c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
21689194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2169f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2170c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2171c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2172c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2173c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
21746e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2175c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
21767dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2177c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2178c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2179f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2180c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2181c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2182429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2183429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2184a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2185a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
218613135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2187f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
21888b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2189381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2190c8883902SJed Brown 
2191f4259b30SLisandro Dalcin   A->spptr     = NULL;
2192c8883902SJed Brown   A->assembled = PETSC_FALSE;
2193c8883902SJed Brown 
2194c8883902SJed Brown   /* expose Nest api's */
21959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
21969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
21979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
21989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
21999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
22009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
22019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
22029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
22039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
22049566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
22059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
22069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
22079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
22089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
22099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
22109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
22119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense));
2212c8883902SJed Brown 
22139566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
2214c8883902SJed Brown   PetscFunctionReturn(0);
2215c8883902SJed Brown }
2216