xref: /petsc/src/mat/impls/nest/matnest.c (revision 58ad77e8b9ee6fdbdfef97ebcff79a2d98620aab)
1aaa7dc30SBarry Smith #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
2b68353e5Sstefano_zampini #include <../src/mat/impls/aij/seq/aij.h>
3b22c5e46SPierre Jolivet #include <../src/mat/impls/shell/shell.h>
40c312b8eSJed Brown #include <petscsf.h>
5d8588912SDave May 
6c8883902SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat, PetscInt, const IS[], PetscInt, const IS[]);
706a1af2fSStefano Zampini static PetscErrorCode MatCreateVecs_Nest(Mat, Vec *, Vec *);
806a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat);
906a1af2fSStefano Zampini 
105e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat, MatType, MatReuse, Mat *);
11c8883902SJed Brown 
12d8588912SDave May /* private functions */
13d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N)
14d71ae5a4SJacob Faibussowitsch {
15d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
168188e55aSJed Brown   PetscInt  i, j;
17d8588912SDave May 
18d8588912SDave May   PetscFunctionBegin;
198188e55aSJed Brown   *m = *n = *M = *N = 0;
208188e55aSJed Brown   for (i = 0; i < bA->nr; i++) { /* rows */
218188e55aSJed Brown     PetscInt sm, sM;
229566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm));
239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &sM));
248188e55aSJed Brown     *m += sm;
258188e55aSJed Brown     *M += sM;
26d8588912SDave May   }
278188e55aSJed Brown   for (j = 0; j < bA->nc; j++) { /* cols */
288188e55aSJed Brown     PetscInt sn, sN;
299566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn));
309566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &sN));
318188e55aSJed Brown     *n += sn;
328188e55aSJed Brown     *N += sN;
33d8588912SDave May   }
343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35d8588912SDave May }
36d8588912SDave May 
37d8588912SDave May /* operations */
38d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y)
39d71ae5a4SJacob Faibussowitsch {
40d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
41207556f9SJed Brown   Vec      *bx = bA->right, *by = bA->left;
42207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
43d8588912SDave May 
44d8588912SDave May   PetscFunctionBegin;
459566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i]));
469566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
47207556f9SJed Brown   for (i = 0; i < nr; i++) {
489566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[i]));
49207556f9SJed Brown     for (j = 0; j < nc; j++) {
50207556f9SJed Brown       if (!bA->m[i][j]) continue;
51d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
529566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i]));
53d8588912SDave May     }
54d8588912SDave May   }
559566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i]));
569566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58d8588912SDave May }
59d8588912SDave May 
60d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z)
61d71ae5a4SJacob Faibussowitsch {
629194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
639194d70fSJed Brown   Vec      *bx = bA->right, *bz = bA->left;
649194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
659194d70fSJed Brown 
669194d70fSJed Brown   PetscFunctionBegin;
679566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i]));
689566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
699194d70fSJed Brown   for (i = 0; i < nr; i++) {
709194d70fSJed Brown     if (y != z) {
719194d70fSJed Brown       Vec by;
729566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by));
739566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[i]));
749566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by));
759194d70fSJed Brown     }
769194d70fSJed Brown     for (j = 0; j < nc; j++) {
779194d70fSJed Brown       if (!bA->m[i][j]) continue;
789194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
799566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i]));
809194d70fSJed Brown     }
819194d70fSJed Brown   }
829566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i]));
839566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
859194d70fSJed Brown }
869194d70fSJed Brown 
8752c5f739Sprj- typedef struct {
8852c5f739Sprj-   Mat         *workC;      /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
8952c5f739Sprj-   PetscScalar *tarray;     /* buffer for storing all temporary products A[i][j] B[j] */
9052c5f739Sprj-   PetscInt    *dm, *dn, k; /* displacements and number of submatrices */
9152c5f739Sprj- } Nest_Dense;
9252c5f739Sprj- 
93a678f235SPierre Jolivet static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
94d71ae5a4SJacob Faibussowitsch {
956718818eSStefano Zampini   Mat_Nest          *bA;
9652c5f739Sprj-   Nest_Dense        *contents;
976718818eSStefano Zampini   Mat                viewB, viewC, productB, workC;
9852c5f739Sprj-   const PetscScalar *barray;
9952c5f739Sprj-   PetscScalar       *carray;
1006718818eSStefano Zampini   PetscInt           i, j, M, N, nr, nc, ldb, ldc;
1016718818eSStefano Zampini   Mat                A, B;
10252c5f739Sprj- 
10352c5f739Sprj-   PetscFunctionBegin;
1040d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
1056718818eSStefano Zampini   A = C->product->A;
1066718818eSStefano Zampini   B = C->product->B;
1079566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
1086718818eSStefano Zampini   if (!N) {
1099566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1109566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1126718818eSStefano Zampini   }
1136718818eSStefano Zampini   contents = (Nest_Dense *)C->product->data;
11428b400f6SJacob Faibussowitsch   PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
1156718818eSStefano Zampini   bA = (Mat_Nest *)A->data;
1166718818eSStefano Zampini   nr = bA->nr;
1176718818eSStefano Zampini   nc = bA->nc;
1189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
1199566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(C, &ldc));
1209566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(C));
1219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
1229566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(C, &carray));
12352c5f739Sprj-   for (i = 0; i < nr; i++) {
1249566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i], &M));
1258e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC));
1269566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC, ldc));
12752c5f739Sprj-     for (j = 0; j < nc; j++) {
12852c5f739Sprj-       if (!bA->m[i][j]) continue;
1299566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
1308e3a54c0SPierre Jolivet       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
1319566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB, ldb));
1324222ddf1SHong Zhang 
1334222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1344222ddf1SHong Zhang       workC             = contents->workC[i * nc + j];
1354222ddf1SHong Zhang       productB          = workC->product->B;
1364222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1379566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1389566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1394222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1404222ddf1SHong Zhang 
14152c5f739Sprj-       /* C[i] <- workC + C[i] */
1429566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
14352c5f739Sprj-     }
1449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14552c5f739Sprj-   }
1469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C, &carray));
1479566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
1484222ddf1SHong Zhang 
14967af85e8SPierre Jolivet   PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
1519566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15352c5f739Sprj- }
15452c5f739Sprj- 
15566976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx)
156d71ae5a4SJacob Faibussowitsch {
15752c5f739Sprj-   Nest_Dense *contents = (Nest_Dense *)ctx;
15852c5f739Sprj-   PetscInt    i;
15952c5f739Sprj- 
16052c5f739Sprj-   PetscFunctionBegin;
1619566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16248a46eb9SPierre Jolivet   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
1639566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
1649566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
1653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16652c5f739Sprj- }
16752c5f739Sprj- 
168a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
169d71ae5a4SJacob Faibussowitsch {
1706718818eSStefano Zampini   Mat_Nest          *bA;
1716718818eSStefano Zampini   Mat                viewB, workC;
17252c5f739Sprj-   const PetscScalar *barray;
1736718818eSStefano Zampini   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
1744222ddf1SHong Zhang   Nest_Dense        *contents = NULL;
1756718818eSStefano Zampini   PetscBool          cisdense;
1766718818eSStefano Zampini   Mat                A, B;
1776718818eSStefano Zampini   PetscReal          fill;
17852c5f739Sprj- 
17952c5f739Sprj-   PetscFunctionBegin;
1800d6f747bSJacob Faibussowitsch   MatCheckProduct(C, 1);
18128b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
1826718818eSStefano Zampini   A    = C->product->A;
1836718818eSStefano Zampini   B    = C->product->B;
1846718818eSStefano Zampini   fill = C->product->fill;
1856718818eSStefano Zampini   bA   = (Mat_Nest *)A->data;
1866718818eSStefano Zampini   nr   = bA->nr;
1876718818eSStefano Zampini   nc   = bA->nc;
1889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C, &m, &n));
1899566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C, &M, &N));
1900572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1919566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B, NULL, &n));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B, NULL, &N));
1939566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A, &m, NULL));
1949566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A, &M, NULL));
1959566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
1960572eedcSPierre Jolivet   }
1979566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
19848a46eb9SPierre Jolivet   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
1999566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
2006718818eSStefano Zampini   if (!N) {
2016718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2023ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20352c5f739Sprj-   }
20452c5f739Sprj- 
2059566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2066718818eSStefano Zampini   C->product->data    = contents;
2076718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2089566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
20952c5f739Sprj-   contents->k = nr * nc;
21052c5f739Sprj-   for (i = 0; i < nr; i++) {
2119566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
21252c5f739Sprj-     maxm = PetscMax(maxm, contents->dm[i + 1]);
21352c5f739Sprj-     contents->dm[i + 1] += contents->dm[i];
21452c5f739Sprj-   }
21552c5f739Sprj-   for (i = 0; i < nc; i++) {
2169566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
21752c5f739Sprj-     contents->dn[i + 1] += contents->dn[i];
21852c5f739Sprj-   }
2199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
2209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B, &ldb));
2219566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B, NULL, &N));
2229566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B, &barray));
22352c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22452c5f739Sprj-   for (j = 0; j < nc; j++) {
2259566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
2268e3a54c0SPierre Jolivet     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
2279566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB, ldb));
22852c5f739Sprj-     for (i = 0; i < nr; i++) {
22952c5f739Sprj-       if (!bA->m[i][j]) continue;
23052c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2314222ddf1SHong Zhang 
2329566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
2334222ddf1SHong Zhang       workC = contents->workC[i * nc + j];
2349566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
2359566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC, "default"));
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC, fill));
2379566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2389566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2394222ddf1SHong Zhang 
2406718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2419566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
2429566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
24352c5f739Sprj-     }
2449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24552c5f739Sprj-   }
2469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B, &barray));
24752c5f739Sprj- 
2486718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25052c5f739Sprj- }
25152c5f739Sprj- 
252a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
253d71ae5a4SJacob Faibussowitsch {
2544222ddf1SHong Zhang   Mat_Product *product = C->product;
25552c5f739Sprj- 
25652c5f739Sprj-   PetscFunctionBegin;
257c57d7d18SPierre Jolivet   if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25952c5f739Sprj- }
26052c5f739Sprj- 
2610998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm)
262d71ae5a4SJacob Faibussowitsch {
263d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
264207556f9SJed Brown   Vec      *bx = bA->left, *by = bA->right;
265207556f9SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
266d8588912SDave May 
267d8588912SDave May   PetscFunctionBegin;
2689566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
2699566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
270207556f9SJed Brown   for (j = 0; j < nc; j++) {
2719566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
272609e31cbSJed Brown     for (i = 0; i < nr; i++) {
2736c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2740998551bSBlanca Mellado Pinto       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */
2750998551bSBlanca Mellado Pinto       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));               /* y[j] <- y[j] + (A[i][j])^T * x[i] */
276d8588912SDave May     }
277d8588912SDave May   }
2789566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
2799566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
2803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
281d8588912SDave May }
282d8588912SDave May 
2830998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
2840998551bSBlanca Mellado Pinto {
2850998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2860998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE));
2870998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
2880998551bSBlanca Mellado Pinto }
2890998551bSBlanca Mellado Pinto 
2900998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y)
2910998551bSBlanca Mellado Pinto {
2920998551bSBlanca Mellado Pinto   PetscFunctionBegin;
2930998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE));
2940998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
2950998551bSBlanca Mellado Pinto }
2960998551bSBlanca Mellado Pinto 
2970998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm)
298d71ae5a4SJacob Faibussowitsch {
2999194d70fSJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
3009194d70fSJed Brown   Vec      *bx = bA->left, *bz = bA->right;
3019194d70fSJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
3029194d70fSJed Brown 
3039194d70fSJed Brown   PetscFunctionBegin;
3049566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
3059566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
3069194d70fSJed Brown   for (j = 0; j < nc; j++) {
3079194d70fSJed Brown     if (y != z) {
3089194d70fSJed Brown       Vec by;
3099566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
3109566063dSJacob Faibussowitsch       PetscCall(VecCopy(by, bz[j]));
3119566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
3129194d70fSJed Brown     }
3139194d70fSJed Brown     for (i = 0; i < nr; i++) {
3146c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3150998551bSBlanca Mellado Pinto       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */
3160998551bSBlanca Mellado Pinto       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));               /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3179194d70fSJed Brown     }
3189194d70fSJed Brown   }
3199566063dSJacob Faibussowitsch   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
3209566063dSJacob Faibussowitsch   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
3213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3229194d70fSJed Brown }
3239194d70fSJed Brown 
3240998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
3250998551bSBlanca Mellado Pinto {
3260998551bSBlanca Mellado Pinto   PetscFunctionBegin;
3270998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE));
3280998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3290998551bSBlanca Mellado Pinto }
3300998551bSBlanca Mellado Pinto 
3310998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
3320998551bSBlanca Mellado Pinto {
3330998551bSBlanca Mellado Pinto   PetscFunctionBegin;
3340998551bSBlanca Mellado Pinto   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE));
3350998551bSBlanca Mellado Pinto   PetscFunctionReturn(PETSC_SUCCESS);
3360998551bSBlanca Mellado Pinto }
3370998551bSBlanca Mellado Pinto 
338d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
339d71ae5a4SJacob Faibussowitsch {
340f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
341f8170845SAlex Fikl   Mat       C;
342f8170845SAlex Fikl   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
343f8170845SAlex Fikl 
344f8170845SAlex Fikl   PetscFunctionBegin;
3457fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
346aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
347f8170845SAlex Fikl 
348cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
349f8170845SAlex Fikl     Mat *subs;
350f8170845SAlex Fikl     IS  *is_row, *is_col;
351f8170845SAlex Fikl 
3529566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc, &subs));
3539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
3549566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A, is_row, is_col));
355cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
356ddeb9bd8SAlex Fikl       for (i = 0; i < nr; i++) {
357ad540459SPierre Jolivet         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
358ddeb9bd8SAlex Fikl       }
359ddeb9bd8SAlex Fikl     }
360ddeb9bd8SAlex Fikl 
3619566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
3629566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3639566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row, is_col));
364f8170845SAlex Fikl   } else {
365f8170845SAlex Fikl     C = *B;
366f8170845SAlex Fikl   }
367f8170845SAlex Fikl 
368f8170845SAlex Fikl   bC = (Mat_Nest *)C->data;
369f8170845SAlex Fikl   for (i = 0; i < nr; i++) {
370f8170845SAlex Fikl     for (j = 0; j < nc; j++) {
371f8170845SAlex Fikl       if (bA->m[i][j]) {
372f4f49eeaSPierre Jolivet         PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i]));
373f8170845SAlex Fikl       } else {
374f8170845SAlex Fikl         bC->m[j][i] = NULL;
375f8170845SAlex Fikl       }
376f8170845SAlex Fikl     }
377f8170845SAlex Fikl   }
378f8170845SAlex Fikl 
379cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
380f8170845SAlex Fikl     *B = C;
381f8170845SAlex Fikl   } else {
3829566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
383f8170845SAlex Fikl   }
3843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
385f8170845SAlex Fikl }
386f8170845SAlex Fikl 
387d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
388d71ae5a4SJacob Faibussowitsch {
389e2d7f03fSJed Brown   IS      *lst = *list;
390e2d7f03fSJed Brown   PetscInt i;
391e2d7f03fSJed Brown 
392e2d7f03fSJed Brown   PetscFunctionBegin;
3933ba16761SJacob Faibussowitsch   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
3949371c9d4SSatish Balay   for (i = 0; i < n; i++)
3959371c9d4SSatish Balay     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3969566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3970298fd71SBarry Smith   *list = NULL;
3983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
399e2d7f03fSJed Brown }
400e2d7f03fSJed Brown 
401d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A)
402d71ae5a4SJacob Faibussowitsch {
403d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
404d8588912SDave May   PetscInt  i, j;
405d8588912SDave May 
406d8588912SDave May   PetscFunctionBegin;
407d8588912SDave May   /* release the matrices and the place holders */
4089566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
4099566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
4109566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
4119566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
412d8588912SDave May 
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
416d8588912SDave May 
4179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left, vs->right));
418207556f9SJed Brown 
419d8588912SDave May   /* release the matrices and the place holders */
420d8588912SDave May   if (vs->m) {
421d8588912SDave May     for (i = 0; i < vs->nr; i++) {
42248a46eb9SPierre Jolivet       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
423d8588912SDave May     }
4248068ee9dSPierre Jolivet     PetscCall(PetscFree(vs->m[0]));
4259566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
426d8588912SDave May   }
42706a1af2fSStefano Zampini 
42806a1af2fSStefano Zampini   /* restore defaults */
42906a1af2fSStefano Zampini   vs->nr            = 0;
43006a1af2fSStefano Zampini   vs->nc            = 0;
43106a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
4323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43306a1af2fSStefano Zampini }
43406a1af2fSStefano Zampini 
435d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A)
436d71ae5a4SJacob Faibussowitsch {
437362febeeSStefano Zampini   PetscFunctionBegin;
4389566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4399566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
4429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
4439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
4449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
4459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
4469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
4479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
4489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
4499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
4509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
4519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
4529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
4539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
4549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
4559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
4563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
457d8588912SDave May }
458d8588912SDave May 
459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
460d71ae5a4SJacob Faibussowitsch {
461381b8e50SStefano Zampini   Mat_Nest *vs = (Mat_Nest *)mat->data;
462381b8e50SStefano Zampini   PetscInt  i;
463381b8e50SStefano Zampini 
464381b8e50SStefano Zampini   PetscFunctionBegin;
465381b8e50SStefano Zampini   if (dd) *dd = 0;
466381b8e50SStefano Zampini   if (!vs->nr) {
467381b8e50SStefano Zampini     *missing = PETSC_TRUE;
4683ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
469381b8e50SStefano Zampini   }
470381b8e50SStefano Zampini   *missing = PETSC_FALSE;
47157508eceSPierre Jolivet   for (i = 0; i < vs->nr && !*missing; i++) {
472381b8e50SStefano Zampini     *missing = PETSC_TRUE;
473381b8e50SStefano Zampini     if (vs->m[i][i]) {
4749566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
47508401ef6SPierre Jolivet       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
476381b8e50SStefano Zampini     }
477381b8e50SStefano Zampini   }
4783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
479381b8e50SStefano Zampini }
480381b8e50SStefano Zampini 
481d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
482d71ae5a4SJacob Faibussowitsch {
483d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
484d8588912SDave May   PetscInt  i, j;
48506a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
486d8588912SDave May 
487d8588912SDave May   PetscFunctionBegin;
488d8588912SDave May   for (i = 0; i < vs->nr; i++) {
489d8588912SDave May     for (j = 0; j < vs->nc; j++) {
49006a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
491e7c19651SJed Brown       if (vs->m[i][j]) {
4929566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
493e7c19651SJed Brown         if (!vs->splitassembly) {
494e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
495e7c19651SJed 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
496e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
497e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
498e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
499e7c19651SJed Brown            */
5009566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
5019566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
502e7c19651SJed Brown         }
503e7c19651SJed Brown       }
50406a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
50506a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
506d8588912SDave May     }
507d8588912SDave May   }
50806a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
5093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
510d8588912SDave May }
511d8588912SDave May 
512d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
513d71ae5a4SJacob Faibussowitsch {
514d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
515d8588912SDave May   PetscInt  i, j;
516d8588912SDave May 
517d8588912SDave May   PetscFunctionBegin;
518d8588912SDave May   for (i = 0; i < vs->nr; i++) {
519d8588912SDave May     for (j = 0; j < vs->nc; j++) {
520e7c19651SJed Brown       if (vs->m[i][j]) {
52148a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
522e7c19651SJed Brown       }
523d8588912SDave May     }
524d8588912SDave May   }
5253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
526d8588912SDave May }
527d8588912SDave May 
528d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
529d71ae5a4SJacob Faibussowitsch {
530f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
531f349c1fdSJed Brown   PetscInt  j;
532f349c1fdSJed Brown   Mat       sub;
533d8588912SDave May 
534d8588912SDave May   PetscFunctionBegin;
5350298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
536f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5379566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
538f349c1fdSJed Brown   *B = sub;
5393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
540d8588912SDave May }
541d8588912SDave May 
542d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
543d71ae5a4SJacob Faibussowitsch {
544f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
545f349c1fdSJed Brown   PetscInt  i;
546f349c1fdSJed Brown   Mat       sub;
547f349c1fdSJed Brown 
548f349c1fdSJed Brown   PetscFunctionBegin;
5490298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
550f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5519566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
552f349c1fdSJed Brown   *B = sub;
5533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
554d8588912SDave May }
555d8588912SDave May 
556d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
557d71ae5a4SJacob Faibussowitsch {
55818d228c0SPierre Jolivet   PetscInt  i, j, size, m;
559f349c1fdSJed Brown   PetscBool flg;
56018d228c0SPierre Jolivet   IS        out, concatenate[2];
561f349c1fdSJed Brown 
562f349c1fdSJed Brown   PetscFunctionBegin;
5634f572ea9SToby Isaac   PetscAssertPointer(list, 3);
564f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
56518d228c0SPierre Jolivet   if (begin) {
5664f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
56718d228c0SPierre Jolivet     *begin = -1;
56818d228c0SPierre Jolivet   }
56918d228c0SPierre Jolivet   if (end) {
5704f572ea9SToby Isaac     PetscAssertPointer(end, 6);
57118d228c0SPierre Jolivet     *end = -1;
57218d228c0SPierre Jolivet   }
573f349c1fdSJed Brown   for (i = 0; i < n; i++) {
574207556f9SJed Brown     if (!list[i]) continue;
5759566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
576f349c1fdSJed Brown     if (flg) {
57718d228c0SPierre Jolivet       if (begin) *begin = i;
57818d228c0SPierre Jolivet       if (end) *end = i + 1;
5793ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
580f349c1fdSJed Brown     }
581f349c1fdSJed Brown   }
5829566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
58318d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
58418d228c0SPierre Jolivet     if (!list[i]) continue;
58518d228c0SPierre Jolivet     m = 0;
5869566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5879566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
58818d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
58918d228c0SPierre Jolivet       if (list[j]) {
59018d228c0SPierre Jolivet         concatenate[0] = out;
59118d228c0SPierre Jolivet         concatenate[1] = list[j];
5929566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5939566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5949566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
59518d228c0SPierre Jolivet       }
59618d228c0SPierre Jolivet     }
59718d228c0SPierre Jolivet     if (m == size) {
5989566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
59918d228c0SPierre Jolivet       if (flg) {
60018d228c0SPierre Jolivet         if (begin) *begin = i;
60118d228c0SPierre Jolivet         if (end) *end = j;
6029566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
6033ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
60418d228c0SPierre Jolivet       }
60518d228c0SPierre Jolivet     }
6069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
60718d228c0SPierre Jolivet   }
6083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
609f349c1fdSJed Brown }
610f349c1fdSJed Brown 
611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
612d71ae5a4SJacob Faibussowitsch {
6138188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
61418d228c0SPierre Jolivet   PetscInt  lr, lc;
61518d228c0SPierre Jolivet 
61618d228c0SPierre Jolivet   PetscFunctionBegin;
6179566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
6189566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
6199566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
6209566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
6219566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6229566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6239566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6249566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6259566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62918d228c0SPierre Jolivet }
63018d228c0SPierre Jolivet 
631d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
632d71ae5a4SJacob Faibussowitsch {
63318d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
63418d228c0SPierre Jolivet   Mat       *a;
63518d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6368188e55aSJed Brown   char       keyname[256];
63718d228c0SPierre Jolivet   PetscBool *b;
63818d228c0SPierre Jolivet   PetscBool  flg;
6398188e55aSJed Brown 
6408188e55aSJed Brown   PetscFunctionBegin;
6410298fd71SBarry Smith   *B = NULL;
6429566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6439566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6443ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6458188e55aSJed Brown 
6469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
64718d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
64818d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
64918d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
65018d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
65118d228c0SPierre Jolivet     }
65218d228c0SPierre Jolivet   }
65318d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
65418d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
65518d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
65618d228c0SPierre Jolivet         flg = PETSC_FALSE;
65718d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
65818d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
65918d228c0SPierre Jolivet         }
66018d228c0SPierre Jolivet         if (flg) {
66118d228c0SPierre Jolivet           flg = PETSC_FALSE;
66218d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
66318d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
66418d228c0SPierre Jolivet           }
66518d228c0SPierre Jolivet         }
66618d228c0SPierre Jolivet         if (!flg) {
66718d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6689566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
66918d228c0SPierre Jolivet         }
67018d228c0SPierre Jolivet       }
67118d228c0SPierre Jolivet     }
67218d228c0SPierre Jolivet   }
6739566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
67418d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
67518d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
67648a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
67718d228c0SPierre Jolivet     }
67818d228c0SPierre Jolivet   }
6799566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6808188e55aSJed Brown   (*B)->assembled = A->assembled;
6819566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6829566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6848188e55aSJed Brown }
6858188e55aSJed Brown 
686d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
687d71ae5a4SJacob Faibussowitsch {
688f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
68918d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
690f349c1fdSJed Brown 
691f349c1fdSJed Brown   PetscFunctionBegin;
6929566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6939566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
69418d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
69548a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
69618d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
69718d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6989566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
69918d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
7003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
701f349c1fdSJed Brown }
702f349c1fdSJed Brown 
70306a1af2fSStefano Zampini /*
70406a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
70506a1af2fSStefano Zampini */
706d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
707d71ae5a4SJacob Faibussowitsch {
708f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
709f349c1fdSJed Brown   Mat       sub;
710f349c1fdSJed Brown 
711f349c1fdSJed Brown   PetscFunctionBegin;
7129566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
713f349c1fdSJed Brown   switch (reuse) {
714f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
7159566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
716f349c1fdSJed Brown     *B = sub;
717f349c1fdSJed Brown     break;
718d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
719d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
720d71ae5a4SJacob Faibussowitsch     break;
721d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_MATRIX: /* Nothing to do */
722d71ae5a4SJacob Faibussowitsch     break;
723d71ae5a4SJacob Faibussowitsch   case MAT_INPLACE_MATRIX: /* Nothing to do */
724d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
725f349c1fdSJed Brown   }
7263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
727f349c1fdSJed Brown }
728f349c1fdSJed Brown 
72966976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
730d71ae5a4SJacob Faibussowitsch {
731f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
732f349c1fdSJed Brown   Mat       sub;
733f349c1fdSJed Brown 
734f349c1fdSJed Brown   PetscFunctionBegin;
7359566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
736f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7379566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
738f349c1fdSJed Brown   *B = sub;
7393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
740d8588912SDave May }
741d8588912SDave May 
742d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
743d71ae5a4SJacob Faibussowitsch {
744f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
745f349c1fdSJed Brown   Mat       sub;
746d8588912SDave May 
747d8588912SDave May   PetscFunctionBegin;
7489566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
74908401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
750f349c1fdSJed Brown   if (sub) {
751aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7529566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
753d8588912SDave May   }
7543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
755d8588912SDave May }
756d8588912SDave May 
757d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
758d71ae5a4SJacob Faibussowitsch {
7597874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7607874fa86SDave May   PetscInt  i;
7617874fa86SDave May 
7627874fa86SDave May   PetscFunctionBegin;
7637874fa86SDave May   for (i = 0; i < bA->nr; i++) {
764429bac76SJed Brown     Vec bv;
7659566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7667874fa86SDave May     if (bA->m[i][i]) {
7679566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7687874fa86SDave May     } else {
7699566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7707874fa86SDave May     }
7719566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7727874fa86SDave May   }
7733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7747874fa86SDave May }
7757874fa86SDave May 
776d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
777d71ae5a4SJacob Faibussowitsch {
7787874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
779429bac76SJed Brown   Vec       bl, *br;
7807874fa86SDave May   PetscInt  i, j;
7817874fa86SDave May 
7827874fa86SDave May   PetscFunctionBegin;
7839566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7842e6472ebSElliott Sales de Andrade   if (r) {
7859566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7862e6472ebSElliott Sales de Andrade   }
7872e6472ebSElliott Sales de Andrade   bl = NULL;
7887874fa86SDave May   for (i = 0; i < bA->nr; i++) {
78948a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7907874fa86SDave May     for (j = 0; j < bA->nc; j++) {
79148a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7927874fa86SDave May     }
79348a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7942e6472ebSElliott Sales de Andrade   }
7952e6472ebSElliott Sales de Andrade   if (r) {
7969566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7972e6472ebSElliott Sales de Andrade   }
7989566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8007874fa86SDave May }
8017874fa86SDave May 
802d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
803d71ae5a4SJacob Faibussowitsch {
804a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
805a061e289SJed Brown   PetscInt  i, j;
806a061e289SJed Brown 
807a061e289SJed Brown   PetscFunctionBegin;
808a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
809a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
81048a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
811a061e289SJed Brown     }
812a061e289SJed Brown   }
8133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
814a061e289SJed Brown }
815a061e289SJed Brown 
816d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
817d71ae5a4SJacob Faibussowitsch {
818a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
819a061e289SJed Brown   PetscInt  i;
82006a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
821a061e289SJed Brown 
822a061e289SJed Brown   PetscFunctionBegin;
823a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
82406a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82508401ef6SPierre 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);
8269566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8279566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82806a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
82906a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
830a061e289SJed Brown   }
83106a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
833a061e289SJed Brown }
834a061e289SJed Brown 
835d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
836d71ae5a4SJacob Faibussowitsch {
83713135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
83813135bc6SAlex Fikl   PetscInt  i;
83906a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
84013135bc6SAlex Fikl 
84113135bc6SAlex Fikl   PetscFunctionBegin;
84213135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
84306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
84413135bc6SAlex Fikl     Vec              bv;
8459566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
84613135bc6SAlex Fikl     if (bA->m[i][i]) {
8479566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8489566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
84913135bc6SAlex Fikl     }
8509566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
85106a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
85206a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
85313135bc6SAlex Fikl   }
85406a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85613135bc6SAlex Fikl }
85713135bc6SAlex Fikl 
858d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
859d71ae5a4SJacob Faibussowitsch {
860f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
861f8170845SAlex Fikl   PetscInt  i, j;
862f8170845SAlex Fikl 
863f8170845SAlex Fikl   PetscFunctionBegin;
864f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
865f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
86648a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
867f8170845SAlex Fikl     }
868f8170845SAlex Fikl   }
8693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
870f8170845SAlex Fikl }
871f8170845SAlex Fikl 
872d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
873d71ae5a4SJacob Faibussowitsch {
874d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
875d8588912SDave May   Vec      *L, *R;
876d8588912SDave May   MPI_Comm  comm;
877d8588912SDave May   PetscInt  i, j;
878d8588912SDave May 
879d8588912SDave May   PetscFunctionBegin;
8809566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
881d8588912SDave May   if (right) {
882d8588912SDave May     /* allocate R */
8839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
884d8588912SDave May     /* Create the right vectors */
885d8588912SDave May     for (j = 0; j < bA->nc; j++) {
886d8588912SDave May       for (i = 0; i < bA->nr; i++) {
887d8588912SDave May         if (bA->m[i][j]) {
8889566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
889d8588912SDave May           break;
890d8588912SDave May         }
891d8588912SDave May       }
89208401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
893d8588912SDave May     }
8949566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
895d8588912SDave May     /* hand back control to the nest vector */
89648a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8979566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
898d8588912SDave May   }
899d8588912SDave May 
900d8588912SDave May   if (left) {
901d8588912SDave May     /* allocate L */
9029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
903d8588912SDave May     /* Create the left vectors */
904d8588912SDave May     for (i = 0; i < bA->nr; i++) {
905d8588912SDave May       for (j = 0; j < bA->nc; j++) {
906d8588912SDave May         if (bA->m[i][j]) {
9079566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
908d8588912SDave May           break;
909d8588912SDave May         }
910d8588912SDave May       }
91108401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
912d8588912SDave May     }
913d8588912SDave May 
9149566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
91548a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
916d8588912SDave May 
9179566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
918d8588912SDave May   }
9193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
920d8588912SDave May }
921d8588912SDave May 
922d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
923d71ae5a4SJacob Faibussowitsch {
924d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
92529e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
926d8588912SDave May   PetscInt  i, j;
927d8588912SDave May 
928d8588912SDave May   PetscFunctionBegin;
9299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
930d8588912SDave May   if (isascii) {
93130924786SStefano Zampini     PetscViewerFormat format;
93230924786SStefano Zampini 
93330924786SStefano Zampini     PetscCall(PetscViewerGetFormat(viewer, &format));
93430924786SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
93530924786SStefano Zampini       Mat T;
93630924786SStefano Zampini 
93730924786SStefano Zampini       PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &T));
93830924786SStefano Zampini       PetscCall(MatView(T, viewer));
93930924786SStefano Zampini       PetscCall(MatDestroy(&T));
94030924786SStefano Zampini       PetscFunctionReturn(PETSC_SUCCESS);
94130924786SStefano Zampini     }
9429566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
9449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9459566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
946d8588912SDave May 
9479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
948d8588912SDave May     for (i = 0; i < bA->nr; i++) {
949d8588912SDave May       for (j = 0; j < bA->nc; j++) {
95019fd82e9SBarry Smith         MatType   type;
951270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
952d8588912SDave May         PetscInt  NR, NC;
953d8588912SDave May         PetscBool isNest = PETSC_FALSE;
954d8588912SDave May 
955d8588912SDave May         if (!bA->m[i][j]) {
9569566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
957d8588912SDave May           continue;
958d8588912SDave May         }
9599566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9609566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9619566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9629566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9639566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
964d8588912SDave May 
9659566063dSJacob 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));
966d8588912SDave May 
96729e60adbSStefano Zampini         if (isNest || viewSub) {
9689566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9699566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9709566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
971d8588912SDave May         }
972d8588912SDave May       }
973d8588912SDave May     }
9749566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
975d8588912SDave May   }
9763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
977d8588912SDave May }
978d8588912SDave May 
979d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
980d71ae5a4SJacob Faibussowitsch {
981d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
982d8588912SDave May   PetscInt  i, j;
983d8588912SDave May 
984d8588912SDave May   PetscFunctionBegin;
985d8588912SDave May   for (i = 0; i < bA->nr; i++) {
986d8588912SDave May     for (j = 0; j < bA->nc; j++) {
987d8588912SDave May       if (!bA->m[i][j]) continue;
9889566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
989d8588912SDave May     }
990d8588912SDave May   }
9913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
992d8588912SDave May }
993d8588912SDave May 
994d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
995d71ae5a4SJacob Faibussowitsch {
996c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
997c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
99806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
999c222c20dSDavid Ham 
1000c222c20dSDavid Ham   PetscFunctionBegin;
1001aed4548fSBarry 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);
1002c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
1003c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
100406a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
100546a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
10069566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
10079566063dSJacob Faibussowitsch         PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
100806a1af2fSStefano Zampini         nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
100906a1af2fSStefano Zampini         bB->nnzstate[i * nc + j] = subnnzstate;
1010ea6db252SJose E. Roman       } else if (bA->m[i][j]) { // bB->m[i][j] is NULL
1011ea6db252SJose E. Roman         Mat M;
1012ea6db252SJose E. Roman 
1013ea6db252SJose E. Roman         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1014ea6db252SJose E. Roman         PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M));
1015ea6db252SJose E. Roman         PetscCall(MatNestSetSubMat(B, i, j, M));
1016ea6db252SJose E. Roman         PetscCall(MatDestroy(&M));
1017ea6db252SJose E. Roman       } else if (bB->m[i][j]) { // bA->m[i][j] is NULL
1018ea6db252SJose E. Roman         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == SUBSET_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN, SUBSET_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1019ea6db252SJose E. Roman         PetscCall(MatNestSetSubMat(B, i, j, NULL));
1020ea6db252SJose E. Roman       }
1021c222c20dSDavid Ham     }
1022c222c20dSDavid Ham   }
102306a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
10243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1025c222c20dSDavid Ham }
1026c222c20dSDavid Ham 
1027d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1028d71ae5a4SJacob Faibussowitsch {
10296e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
10306e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
103106a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
10326e76ffeaSPierre Jolivet 
10336e76ffeaSPierre Jolivet   PetscFunctionBegin;
1034aed4548fSBarry 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);
10356e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
10366e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
103706a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10386e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10399566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1040c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1041c066aebcSStefano Zampini         Mat M;
1042c066aebcSStefano Zampini 
1043e75569e9SPierre Jolivet         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
10449566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10459566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10469566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1047c066aebcSStefano Zampini       }
10489566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
104906a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
105006a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10516e76ffeaSPierre Jolivet     }
10526e76ffeaSPierre Jolivet   }
105306a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10556e76ffeaSPierre Jolivet }
10566e76ffeaSPierre Jolivet 
1057d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1058d71ae5a4SJacob Faibussowitsch {
1059d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1060841e96a3SJed Brown   Mat      *b;
1061841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1062d8588912SDave May 
1063d8588912SDave May   PetscFunctionBegin;
10649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1065841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1066841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1067841e96a3SJed Brown       if (bA->m[i][j]) {
10689566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1069841e96a3SJed Brown       } else {
10700298fd71SBarry Smith         b[i * nc + j] = NULL;
1071d8588912SDave May       }
1072d8588912SDave May     }
1073d8588912SDave May   }
10749566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1075841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
107648a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10779566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1078d8588912SDave May 
10799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1082d8588912SDave May }
1083d8588912SDave May 
1084d8588912SDave May /* nest api */
108566976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1086d71ae5a4SJacob Faibussowitsch {
1087d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10885fd66863SKarl Rupp 
1089d8588912SDave May   PetscFunctionBegin;
109008401ef6SPierre 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);
109108401ef6SPierre 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);
1092d8588912SDave May   *mat = bA->m[idxm][jdxm];
10933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1094d8588912SDave May }
1095d8588912SDave May 
10969ba0d327SJed Brown /*@
109711a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1098d8588912SDave May 
10992ef1f0ffSBarry Smith   Not Collective
1100d8588912SDave May 
1101d8588912SDave May   Input Parameters:
110211a5261eSBarry Smith + A    - `MATNEST` matrix
1103d8588912SDave May . idxm - index of the matrix within the nest matrix
1104629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1105d8588912SDave May 
1106d8588912SDave May   Output Parameter:
11072ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1108d8588912SDave May 
1109d8588912SDave May   Level: developer
1110d8588912SDave May 
1111fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1112db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1113d8588912SDave May @*/
1114d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1115d71ae5a4SJacob Faibussowitsch {
1116d8588912SDave May   PetscFunctionBegin;
11173536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11183536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
11193536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
11203536838dSStefano Zampini   PetscAssertPointer(sub, 4);
1121cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
11223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1123d8588912SDave May }
1124d8588912SDave May 
112566976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1126d71ae5a4SJacob Faibussowitsch {
11270782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
11280782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
11290782ca92SJed Brown 
11300782ca92SJed Brown   PetscFunctionBegin;
113108401ef6SPierre 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);
113208401ef6SPierre 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);
11333536838dSStefano Zampini   if (mat) {
11349566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mat, &m, &n));
11359566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &M, &N));
11369566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
11379566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
11389566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
11399566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1140aed4548fSBarry 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);
1141aed4548fSBarry 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);
11423536838dSStefano Zampini   }
114326fbe8dcSKarl Rupp 
114406a1af2fSStefano Zampini   /* do not increase object state */
11453ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
114606a1af2fSStefano Zampini 
11479566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11490782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11509566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11513536838dSStefano Zampini   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
11523536838dSStefano Zampini   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
115306a1af2fSStefano Zampini   A->nonzerostate++;
11543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11550782ca92SJed Brown }
11560782ca92SJed Brown 
11579ba0d327SJed Brown /*@
115811a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11590782ca92SJed Brown 
11602ef1f0ffSBarry Smith   Logically Collective
11610782ca92SJed Brown 
11620782ca92SJed Brown   Input Parameters:
116311a5261eSBarry Smith + A    - `MATNEST` matrix
11640782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11650782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11662ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11672ef1f0ffSBarry Smith 
11682ef1f0ffSBarry Smith   Level: developer
11690782ca92SJed Brown 
11700782ca92SJed Brown   Notes:
11710782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11720782ca92SJed Brown 
11730782ca92SJed Brown   This increments the reference count of the submatrix.
11740782ca92SJed Brown 
1175fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1176db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11770782ca92SJed Brown @*/
1178d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1179d71ae5a4SJacob Faibussowitsch {
11800782ca92SJed Brown   PetscFunctionBegin;
11813536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11823536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
11833536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
11843536838dSStefano Zampini   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
11853536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11870782ca92SJed Brown }
11880782ca92SJed Brown 
118966976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1190d71ae5a4SJacob Faibussowitsch {
1191d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11925fd66863SKarl Rupp 
1193d8588912SDave May   PetscFunctionBegin;
119426fbe8dcSKarl Rupp   if (M) *M = bA->nr;
119526fbe8dcSKarl Rupp   if (N) *N = bA->nc;
119626fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1198d8588912SDave May }
1199d8588912SDave May 
1200d8588912SDave May /*@C
120111a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1202d8588912SDave May 
12032ef1f0ffSBarry Smith   Not Collective
1204d8588912SDave May 
1205f899ff85SJose E. Roman   Input Parameter:
1206629881c0SJed Brown . A - nest matrix
1207d8588912SDave May 
1208d8d19677SJose E. Roman   Output Parameters:
1209a3b724e8SBarry Smith + M   - number of submatrix rows in the nest matrix
1210a3b724e8SBarry Smith . N   - number of submatrix columns in the nest matrix
1211e9d3347aSJose E. Roman - mat - array of matrices
1212d8588912SDave May 
12132ef1f0ffSBarry Smith   Level: developer
12142ef1f0ffSBarry Smith 
121511a5261eSBarry Smith   Note:
12162ef1f0ffSBarry Smith   The user should not free the array `mat`.
1217d8588912SDave May 
1218fe59aa6dSJacob Faibussowitsch   Fortran Notes:
1219a3b724e8SBarry Smith   This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)`
122020f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1221e9d3347aSJose E. Roman   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1222351962e3SVincent Le Chenadec 
1223fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1224db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1225d8588912SDave May @*/
1226d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1227d71ae5a4SJacob Faibussowitsch {
1228d8588912SDave May   PetscFunctionBegin;
12293536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1230cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
12313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1232d8588912SDave May }
1233d8588912SDave May 
123466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1235d71ae5a4SJacob Faibussowitsch {
1236d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1237d8588912SDave May 
1238d8588912SDave May   PetscFunctionBegin;
123926fbe8dcSKarl Rupp   if (M) *M = bA->nr;
124026fbe8dcSKarl Rupp   if (N) *N = bA->nc;
12413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1242d8588912SDave May }
1243d8588912SDave May 
12449ba0d327SJed Brown /*@
124511a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1246d8588912SDave May 
12472ef1f0ffSBarry Smith   Not Collective
1248d8588912SDave May 
1249f899ff85SJose E. Roman   Input Parameter:
125011a5261eSBarry Smith . A - `MATNEST` matrix
1251d8588912SDave May 
1252d8d19677SJose E. Roman   Output Parameters:
1253629881c0SJed Brown + M - number of rows in the nested mat
1254629881c0SJed Brown - N - number of cols in the nested mat
1255d8588912SDave May 
1256d8588912SDave May   Level: developer
1257d8588912SDave May 
125880670ca5SBarry Smith   Note:
125980670ca5SBarry Smith   `size` refers to the number of submatrices in the row and column directions of the nested matrix
126080670ca5SBarry Smith 
1261fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1262db781477SPatrick Sanan           `MatNestGetISs()`
1263d8588912SDave May @*/
1264d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1265d71ae5a4SJacob Faibussowitsch {
1266d8588912SDave May   PetscFunctionBegin;
12673536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1268cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1270d8588912SDave May }
1271d8588912SDave May 
1272d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1273d71ae5a4SJacob Faibussowitsch {
1274900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1275900e7ff2SJed Brown   PetscInt  i;
1276900e7ff2SJed Brown 
1277900e7ff2SJed Brown   PetscFunctionBegin;
12789371c9d4SSatish Balay   if (rows)
12799371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12809371c9d4SSatish Balay   if (cols)
12819371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1283900e7ff2SJed Brown }
1284900e7ff2SJed Brown 
1285664df05cSJose E. Roman /*@
128611a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1287900e7ff2SJed Brown 
12882ef1f0ffSBarry Smith   Not Collective
1289900e7ff2SJed Brown 
1290f899ff85SJose E. Roman   Input Parameter:
129111a5261eSBarry Smith . A - `MATNEST` matrix
1292900e7ff2SJed Brown 
1293d8d19677SJose E. Roman   Output Parameters:
1294a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore)
1295a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore)
1296900e7ff2SJed Brown 
1297900e7ff2SJed Brown   Level: advanced
1298900e7ff2SJed Brown 
129911a5261eSBarry Smith   Note:
13002ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1301900e7ff2SJed Brown 
1302fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1303fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1304900e7ff2SJed Brown @*/
1305d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1306d71ae5a4SJacob Faibussowitsch {
1307900e7ff2SJed Brown   PetscFunctionBegin;
1308900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1309cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
13103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1311900e7ff2SJed Brown }
1312900e7ff2SJed Brown 
1313d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1314d71ae5a4SJacob Faibussowitsch {
1315900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1316900e7ff2SJed Brown   PetscInt  i;
1317900e7ff2SJed Brown 
1318900e7ff2SJed Brown   PetscFunctionBegin;
13199371c9d4SSatish Balay   if (rows)
13209371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
13219371c9d4SSatish Balay   if (cols)
13229371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
13233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1324900e7ff2SJed Brown }
1325900e7ff2SJed Brown 
13265d83a8b1SBarry Smith /*@
132711a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1328900e7ff2SJed Brown 
13292ef1f0ffSBarry Smith   Not Collective
1330900e7ff2SJed Brown 
1331f899ff85SJose E. Roman   Input Parameter:
133211a5261eSBarry Smith . A - `MATNEST` matrix
1333900e7ff2SJed Brown 
1334d8d19677SJose E. Roman   Output Parameters:
1335a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore)
1336a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore)
1337900e7ff2SJed Brown 
1338900e7ff2SJed Brown   Level: advanced
1339900e7ff2SJed Brown 
134011a5261eSBarry Smith   Note:
13412ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1342900e7ff2SJed Brown 
13431cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1344fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1345900e7ff2SJed Brown @*/
1346d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1347d71ae5a4SJacob Faibussowitsch {
1348900e7ff2SJed Brown   PetscFunctionBegin;
1349900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1350cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
13513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1352900e7ff2SJed Brown }
1353900e7ff2SJed Brown 
135466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1355d71ae5a4SJacob Faibussowitsch {
1356207556f9SJed Brown   PetscBool flg;
1357207556f9SJed Brown 
1358207556f9SJed Brown   PetscFunctionBegin;
13599566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1360207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13612a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
13620d5ef98aSSatish Balay   else A->ops->getvecs = NULL;
13633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1364207556f9SJed Brown }
1365207556f9SJed Brown 
13665d83a8b1SBarry Smith /*@
136711a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1368207556f9SJed Brown 
13692ef1f0ffSBarry Smith   Not Collective
1370207556f9SJed Brown 
1371207556f9SJed Brown   Input Parameters:
137211a5261eSBarry Smith + A     - `MATNEST` matrix
137311a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1374207556f9SJed Brown 
1375207556f9SJed Brown   Level: developer
1376207556f9SJed Brown 
1377fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1378207556f9SJed Brown @*/
1379d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1380d71ae5a4SJacob Faibussowitsch {
1381207556f9SJed Brown   PetscFunctionBegin;
13823536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1383cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1385207556f9SJed Brown }
1386207556f9SJed Brown 
138766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1388d71ae5a4SJacob Faibussowitsch {
1389c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1390c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
139188ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
139288ffe2e8SJose E. Roman   VecType   vtype, type;
1393d8588912SDave May 
1394d8588912SDave May   PetscFunctionBegin;
13959566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
139606a1af2fSStefano Zampini 
1397c8883902SJed Brown   s->nr = nr;
1398c8883902SJed Brown   s->nc = nc;
1399d8588912SDave May 
1400c8883902SJed Brown   /* Create space for submatrices */
14019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
14028068ee9dSPierre Jolivet   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1403c8883902SJed Brown   for (i = 0; i < nr; i++) {
14048068ee9dSPierre Jolivet     s->m[i] = s->m[0] + i * nc;
1405c8883902SJed Brown     for (j = 0; j < nc; j++) {
14063536838dSStefano Zampini       s->m[i][j] = a ? a[i * nc + j] : NULL;
14073536838dSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1408d8588912SDave May     }
1409d8588912SDave May   }
14109566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
14119566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
141288ffe2e8SJose E. Roman   if (isstd) {
141388ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
141488ffe2e8SJose E. Roman     vtype = NULL;
141588ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
141688ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
14173536838dSStefano Zampini         if (s->m[i][j]) {
141888ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
14193536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &vtype));
142088ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
142188ffe2e8SJose E. Roman           } else if (sametype) {
14223536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &type));
14239566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
142488ffe2e8SJose E. Roman           }
142588ffe2e8SJose E. Roman         }
142688ffe2e8SJose E. Roman       }
142788ffe2e8SJose E. Roman     }
142888ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
14299566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
143088ffe2e8SJose E. Roman     }
143188ffe2e8SJose E. Roman   }
1432d8588912SDave May 
14339566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1434d8588912SDave May 
14359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
14369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1437c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1438c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1439d8588912SDave May 
14409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
144106a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
144206a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
144348a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
144406a1af2fSStefano Zampini     }
144506a1af2fSStefano Zampini   }
144606a1af2fSStefano Zampini 
14479566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1448d8588912SDave May 
14499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
14509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
14519566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
14529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1453c8883902SJed Brown 
14549566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
14559566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1456c8883902SJed Brown 
145706a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
145806a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14599566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
146006a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
146106a1af2fSStefano Zampini   if (cong) {
146248a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
146306a1af2fSStefano Zampini   }
146406a1af2fSStefano Zampini   if (!cong) {
1465381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
146606a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
146706a1af2fSStefano Zampini     A->ops->shift           = NULL;
146806a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
146906a1af2fSStefano Zampini   }
147006a1af2fSStefano Zampini 
14719566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14729566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
147306a1af2fSStefano Zampini   A->nonzerostate++;
14743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1475d8588912SDave May }
1476d8588912SDave May 
1477c8883902SJed Brown /*@
147811a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1479c8883902SJed Brown 
1480c3339decSBarry Smith   Collective
1481c8883902SJed Brown 
1482d8d19677SJose E. Roman   Input Parameters:
148311a5261eSBarry Smith + A      - `MATNEST` matrix
1484c8883902SJed Brown . nr     - number of nested row blocks
14852ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1486c8883902SJed Brown . nc     - number of nested column blocks
14872ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1488*58ad77e8SBarry Smith - a      - array of $ nr \times nc$ submatrices, or `NULL`
14892ef1f0ffSBarry Smith 
14902ef1f0ffSBarry Smith   Level: advanced
1491c8883902SJed Brown 
1492e9d3347aSJose E. Roman   Notes:
14933536838dSStefano Zampini   This always resets any block matrix information previously set.
1494ce78bad3SBarry Smith 
1495d8b4a066SPierre Jolivet   Pass `NULL` in the corresponding entry of `a` for an empty block.
149606a1af2fSStefano Zampini 
1497*58ad77e8SBarry Smith   In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array containing the matrices. See
1498e9d3347aSJose E. Roman   `MatCreateNest()` for an example.
1499e9d3347aSJose E. Roman 
1500*58ad77e8SBarry Smith   Fortran Note:
1501*58ad77e8SBarry Smith   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
1502*58ad77e8SBarry Smith 
15031cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1504c8883902SJed Brown @*/
1505*58ad77e8SBarry Smith PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) PeNSS
1506d71ae5a4SJacob Faibussowitsch {
1507c8883902SJed Brown   PetscFunctionBegin;
1508c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15093536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nr, 2);
151008401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1511c8883902SJed Brown   if (nr && is_row) {
15124f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
15133536838dSStefano Zampini     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1514c8883902SJed Brown   }
15153536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nc, 4);
151608401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
15171664e352SJed Brown   if (nc && is_col) {
15184f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
15193536838dSStefano Zampini     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1520c8883902SJed Brown   }
15213536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
15223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1523c8883902SJed Brown }
1524d8588912SDave May 
1525d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1526d71ae5a4SJacob Faibussowitsch {
152777019fcaSJed Brown   PetscBool flg;
152877019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
152977019fcaSJed Brown 
153077019fcaSJed Brown   PetscFunctionBegin;
1531aea6d515SStefano Zampini   *ltog = NULL;
153277019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
153377019fcaSJed Brown     if (islocal[i]) {
15349566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
153577019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
153677019fcaSJed Brown     } else {
15379566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
153877019fcaSJed Brown     }
153977019fcaSJed Brown     m += mi;
154077019fcaSJed Brown   }
15413ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1542aea6d515SStefano Zampini 
15439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1544165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
15450298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1546e108cb99SStefano Zampini     Mat                    sub  = NULL;
1547f6d38dbbSStefano Zampini     PetscSF                sf;
1548f6d38dbbSStefano Zampini     PetscLayout            map;
1549aea6d515SStefano Zampini     const PetscInt        *ix2;
155077019fcaSJed Brown 
1551165cd838SBarry Smith     if (!colflg) {
15529566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
155377019fcaSJed Brown     } else {
15549566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
155577019fcaSJed Brown     }
1556191fd14bSBarry Smith     if (sub) {
1557191fd14bSBarry Smith       if (!colflg) {
15589566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1559191fd14bSBarry Smith       } else {
15609566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1561191fd14bSBarry Smith       }
1562191fd14bSBarry Smith     }
156377019fcaSJed Brown     /*
156477019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
156577019fcaSJed 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.
156677019fcaSJed Brown     */
15679566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1568aea6d515SStefano Zampini     if (islocal[i]) {
1569aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1570aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1571aea6d515SStefano Zampini 
15729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
157328b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1574aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15759566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1576aea6d515SStefano Zampini 
1577aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1579aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1580aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1581aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1582aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1583aea6d515SStefano Zampini         nleaves++;
1584aea6d515SStefano Zampini       }
15859566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15869566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15879566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15889566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15899566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15909566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15919566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15929566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15939566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15949566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15959566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1596aea6d515SStefano Zampini     } else {
15979566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1598aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1599aea6d515SStefano Zampini     }
16009566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
160177019fcaSJed Brown     m += mi;
160277019fcaSJed Brown   }
16039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
16043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160577019fcaSJed Brown }
160677019fcaSJed Brown 
1607d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1608d8588912SDave May /*
1609d8588912SDave May   nprocessors = NP
1610d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1611d8588912SDave May        proc 0: => (g_0,h_0,)
1612d8588912SDave May        proc 1: => (g_1,h_1,)
1613d8588912SDave May        ...
1614d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1615d8588912SDave May 
1616d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1617d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1618d8588912SDave May 
1619d8588912SDave May             proc 0:
1620d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1621d8588912SDave May             proc 1:
1622d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1623d8588912SDave May 
1624d8588912SDave May             proc NP-1:
1625d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1626d8588912SDave May */
1627d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1628d71ae5a4SJacob Faibussowitsch {
1629e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
16308188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
16310298fd71SBarry Smith   Mat       sub = NULL;
1632d8588912SDave May 
1633d8588912SDave May   PetscFunctionBegin;
16349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
16359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1636d8588912SDave May   if (is_row) { /* valid IS is passed in */
1637a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1638e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16399566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1640e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1641d8588912SDave May     }
16422ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
16438188e55aSJed Brown     nsum = 0;
16448188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
16459566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
164628b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
16479566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
164808401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16498188e55aSJed Brown       nsum += n;
16508188e55aSJed Brown     }
16519566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
165230bc264bSJed Brown     offset -= nsum;
1653e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16549566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16559566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
16569566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16579566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
16589566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
16592ae74bdbSJed Brown       offset += n;
1660d8588912SDave May     }
1661d8588912SDave May   }
1662d8588912SDave May 
1663d8588912SDave May   if (is_col) { /* valid IS is passed in */
1664a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1665e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16669566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1667e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1668d8588912SDave May     }
16692ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16702ae74bdbSJed Brown     offset = A->cmap->rstart;
16718188e55aSJed Brown     nsum   = 0;
16728188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16739566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
167428b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16759566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
167608401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16778188e55aSJed Brown       nsum += n;
16788188e55aSJed Brown     }
16799566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
168030bc264bSJed Brown     offset -= nsum;
1681e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16829566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16839566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16849566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16859566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16869566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16872ae74bdbSJed Brown       offset += n;
1688d8588912SDave May     }
1689d8588912SDave May   }
1690e2d7f03fSJed Brown 
1691e2d7f03fSJed Brown   /* Set up the local ISs */
16929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1694e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1695e2d7f03fSJed Brown     IS                     isloc;
16960298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1697e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16989566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16999566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1700207556f9SJed Brown     if (rmap) {
17019566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
17029566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
17039566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
17049566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1705207556f9SJed Brown     } else {
1706207556f9SJed Brown       nlocal = 0;
17070298fd71SBarry Smith       isloc  = NULL;
1708207556f9SJed Brown     }
1709e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1710e2d7f03fSJed Brown     offset += nlocal;
1711e2d7f03fSJed Brown   }
17128188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1713e2d7f03fSJed Brown     IS                     isloc;
17140298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1715e2d7f03fSJed Brown     PetscInt               nlocal, bs;
17169566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
17179566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1718207556f9SJed Brown     if (cmap) {
17199566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
17209566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
17219566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
17229566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1723207556f9SJed Brown     } else {
1724207556f9SJed Brown       nlocal = 0;
17250298fd71SBarry Smith       isloc  = NULL;
1726207556f9SJed Brown     }
1727e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1728e2d7f03fSJed Brown     offset += nlocal;
1729e2d7f03fSJed Brown   }
17300189643fSJed Brown 
173177019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
173277019fcaSJed Brown   {
173345b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
17349566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
17359566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
17369566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
17379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
17389566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
173977019fcaSJed Brown   }
174077019fcaSJed Brown 
174176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17420189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
17430189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
17440189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
17450189643fSJed Brown         Mat      B = vs->m[i][j];
17460189643fSJed Brown         if (!B) continue;
17479566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
17489566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
17499566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
17509566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
17519566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
17529566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1753aed4548fSBarry 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);
1754aed4548fSBarry 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);
17550189643fSJed Brown       }
17560189643fSJed Brown     }
175776bd3646SJed Brown   }
1758a061e289SJed Brown 
1759a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1760a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1761a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
17623ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1763a061e289SJed Brown     }
1764a061e289SJed Brown   }
1765a061e289SJed Brown   A->assembled = PETSC_TRUE;
17663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1767d8588912SDave May }
1768d8588912SDave May 
176945c38901SJed Brown /*@C
177011a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1771659c6bb0SJed Brown 
177211a5261eSBarry Smith   Collective
1773659c6bb0SJed Brown 
1774d8d19677SJose E. Roman   Input Parameters:
177511a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1776659c6bb0SJed Brown . nr     - number of nested row blocks
17772ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1778659c6bb0SJed Brown . nc     - number of nested column blocks
17792ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
1780*58ad77e8SBarry Smith - a      - array of $nr \times nc$ submatrices, empty submatrices can be passed using `NULL`
1781659c6bb0SJed Brown 
1782659c6bb0SJed Brown   Output Parameter:
1783659c6bb0SJed Brown . B - new matrix
1784659c6bb0SJed Brown 
1785*58ad77e8SBarry Smith   Level: advanced
1786*58ad77e8SBarry Smith 
1787e9d3347aSJose E. Roman   Note:
1788*58ad77e8SBarry Smith   In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array holding references to the matrices.
1789e9d3347aSJose E. Roman   For instance, to represent the matrix
1790e9d3347aSJose E. Roman   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1791e9d3347aSJose E. Roman   one should use `Mat a[4]={A11,A12,A21,A22}`.
1792e9d3347aSJose E. Roman 
1793*58ad77e8SBarry Smith   Fortran Note:
1794*58ad77e8SBarry Smith   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
1795659c6bb0SJed Brown 
17961cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1797db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1798db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1799659c6bb0SJed Brown @*/
1800030363d8SJose E. Roman PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS
1801d71ae5a4SJacob Faibussowitsch {
1802d8588912SDave May   PetscFunctionBegin;
18033536838dSStefano Zampini   PetscCall(MatCreate(comm, B));
18043536838dSStefano Zampini   PetscCall(MatSetType(*B, MATNEST));
18053536838dSStefano Zampini   (*B)->preallocated = PETSC_TRUE;
18063536838dSStefano Zampini   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
18073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1808d8588912SDave May }
1809659c6bb0SJed Brown 
181066976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1811d71ae5a4SJacob Faibussowitsch {
1812b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
181323875855Sstefano_zampini   Mat          *trans;
1814b68353e5Sstefano_zampini   PetscScalar **avv;
1815b68353e5Sstefano_zampini   PetscScalar  *vv;
1816b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1817b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1818b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1819b68353e5Sstefano_zampini   PetscBool     done;
1820b68353e5Sstefano_zampini 
1821b68353e5Sstefano_zampini   PetscFunctionBegin;
18229566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1823b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1824b68353e5Sstefano_zampini     PetscInt rnr;
1825b68353e5Sstefano_zampini 
18269566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
182728b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
182808401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
18299566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1830b68353e5Sstefano_zampini   }
1831b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1832b68353e5Sstefano_zampini   nnz = 0;
18339566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1834b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1835b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1836b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1837b68353e5Sstefano_zampini       if (B) {
1838b68353e5Sstefano_zampini         PetscScalar *naa;
1839b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
184023875855Sstefano_zampini         PetscBool    istrans;
1841b68353e5Sstefano_zampini 
1842013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
184323875855Sstefano_zampini         if (istrans) {
184423875855Sstefano_zampini           Mat Bt;
184523875855Sstefano_zampini 
18469566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
18479566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
184823875855Sstefano_zampini           B = trans[i * nest->nc + j];
1849013e2dc7SBarry Smith         } else {
1850013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1851013e2dc7SBarry Smith           if (istrans) {
1852013e2dc7SBarry Smith             Mat Bt;
1853013e2dc7SBarry Smith 
1854013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1855013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1856013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1857013e2dc7SBarry Smith           }
185823875855Sstefano_zampini         }
18599566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
186028b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
18619566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1862b68353e5Sstefano_zampini         nnz += nii[nnr];
1863b68353e5Sstefano_zampini 
1864b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1865b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1866b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1867b68353e5Sstefano_zampini       }
1868b68353e5Sstefano_zampini     }
1869b68353e5Sstefano_zampini   }
1870b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18719566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1874b68353e5Sstefano_zampini   } else {
187508401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1876b68353e5Sstefano_zampini   }
1877b68353e5Sstefano_zampini 
1878b68353e5Sstefano_zampini   /* new row pointer */
18799566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1880b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1881b68353e5Sstefano_zampini     PetscInt ncr, rst;
1882b68353e5Sstefano_zampini 
18839566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18849566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1885b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1886b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1887b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1888b68353e5Sstefano_zampini         PetscInt  ir;
1889b68353e5Sstefano_zampini 
1890b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1891b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1892b68353e5Sstefano_zampini           nii++;
1893b68353e5Sstefano_zampini         }
1894b68353e5Sstefano_zampini       }
1895b68353e5Sstefano_zampini     }
1896b68353e5Sstefano_zampini   }
1897b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1898b68353e5Sstefano_zampini 
1899b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
19009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1901b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1902b68353e5Sstefano_zampini     PetscInt ncr, rst;
1903b68353e5Sstefano_zampini 
19049566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
19059566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1906b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1907b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1908b22c5e46SPierre Jolivet         PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0;
1909b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1910b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1911b68353e5Sstefano_zampini         PetscInt     ir, cst;
1912b68353e5Sstefano_zampini 
1913b22c5e46SPierre Jolivet         if (trans[i * nest->nc + j]) {
1914b22c5e46SPierre Jolivet           vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale;
1915b22c5e46SPierre Jolivet           vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift;
1916b22c5e46SPierre Jolivet         }
19179566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1918b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1919b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1920b68353e5Sstefano_zampini 
1921b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1922b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1923b22c5e46SPierre Jolivet             vv[ist + ij] = vscale * *nvv;
1924b22c5e46SPierre Jolivet             if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift;
1925b68353e5Sstefano_zampini             njj++;
1926b68353e5Sstefano_zampini             nvv++;
1927b68353e5Sstefano_zampini           }
1928b68353e5Sstefano_zampini           ci[ir] += rsize;
1929b68353e5Sstefano_zampini           nii++;
1930b68353e5Sstefano_zampini         }
1931b68353e5Sstefano_zampini       }
1932b68353e5Sstefano_zampini     }
1933b68353e5Sstefano_zampini   }
19349566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1935b68353e5Sstefano_zampini 
1936b68353e5Sstefano_zampini   /* restore info */
1937b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1938b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1939b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1940b68353e5Sstefano_zampini       if (B) {
1941b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
194223875855Sstefano_zampini 
194323875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
19449566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
194528b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
19469566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
19479566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1948b68353e5Sstefano_zampini       }
1949b68353e5Sstefano_zampini     }
1950b68353e5Sstefano_zampini   }
19519566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1952b68353e5Sstefano_zampini 
1953b68353e5Sstefano_zampini   /* finalize newmat */
1954b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
19559566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1956b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1957b68353e5Sstefano_zampini     Mat B;
1958b68353e5Sstefano_zampini 
19599566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
19609566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1961b68353e5Sstefano_zampini   }
19629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
19639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1964b68353e5Sstefano_zampini   {
1965b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1966b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1967b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1968b68353e5Sstefano_zampini   }
19693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1970b68353e5Sstefano_zampini }
1971b68353e5Sstefano_zampini 
1972d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1973d71ae5a4SJacob Faibussowitsch {
1974be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1975be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1976be705e3aSPierre Jolivet   PetscBool flg;
1977be705e3aSPierre Jolivet 
1978be705e3aSPierre Jolivet   PetscFunctionBegin;
1979be705e3aSPierre Jolivet   /* Fill by row */
1980be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1981be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1982be705e3aSPierre Jolivet     IS              bNis;
1983be705e3aSPierre Jolivet     PetscInt        bN;
1984be705e3aSPierre Jolivet     const PetscInt *bNindices;
19859566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19869566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19879566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1988be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1989fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1990be705e3aSPierre Jolivet       PetscInt        bm, br;
1991be705e3aSPierre Jolivet       const PetscInt *bmindices;
1992be705e3aSPierre Jolivet       if (!B) continue;
1993013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1994be705e3aSPierre Jolivet       if (flg) {
1995cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1996cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19979566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1998be705e3aSPierre Jolivet         B = D;
1999be705e3aSPierre Jolivet       }
20009566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2001be705e3aSPierre Jolivet       if (flg) {
2002fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2003fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2004be705e3aSPierre Jolivet         B = D;
2005be705e3aSPierre Jolivet       }
20069566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
20079566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
20089566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2009be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
2010be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
2011be705e3aSPierre Jolivet         const PetscInt    *brcols;
2012be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
2013be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
20149566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
20159566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
2016be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
2017be705e3aSPierre Jolivet         /*
2018be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
2019be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
2020be705e3aSPierre Jolivet          */
2021be705e3aSPierre Jolivet         if (a != 1.0) {
20229566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
2023be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
20249566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
20259566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
2026be705e3aSPierre Jolivet         } else {
20279566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
2028be705e3aSPierre Jolivet         }
20299566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
20309566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
2031be705e3aSPierre Jolivet       }
2032fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
20339566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2034be705e3aSPierre Jolivet     }
20359566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
20369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
2037be705e3aSPierre Jolivet   }
20389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
20399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
20403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2041be705e3aSPierre Jolivet }
2042be705e3aSPierre Jolivet 
204366976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2044d71ae5a4SJacob Faibussowitsch {
2045629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
2046e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2047b68353e5Sstefano_zampini   PetscMPIInt size;
2048629c3df2SDmitry Karpeev   Mat         C;
2049629c3df2SDmitry Karpeev 
2050629c3df2SDmitry Karpeev   PetscFunctionBegin;
20519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2052b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2053b68353e5Sstefano_zampini     PetscInt  nf;
2054b68353e5Sstefano_zampini     PetscBool fast;
2055b68353e5Sstefano_zampini 
20569566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
205748a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2058b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
2059b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
2060b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
2061b68353e5Sstefano_zampini         if (B) {
20629566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
206323875855Sstefano_zampini           if (!fast) {
206423875855Sstefano_zampini             PetscBool istrans;
206523875855Sstefano_zampini 
2066013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
206723875855Sstefano_zampini             if (istrans) {
206823875855Sstefano_zampini               Mat Bt;
206923875855Sstefano_zampini 
20709566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
20719566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2072013e2dc7SBarry Smith             } else {
2073013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2074013e2dc7SBarry Smith               if (istrans) {
2075013e2dc7SBarry Smith                 Mat Bt;
2076013e2dc7SBarry Smith 
2077013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2078013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2079013e2dc7SBarry Smith               }
208023875855Sstefano_zampini             }
2081b22c5e46SPierre Jolivet             if (fast) fast = (PetscBool)(!((Mat_Shell *)B->data)->zrows && !((Mat_Shell *)B->data)->zcols && !((Mat_Shell *)B->data)->axpy && !((Mat_Shell *)B->data)->left && !((Mat_Shell *)B->data)->right && !((Mat_Shell *)B->data)->dshift);
2082b68353e5Sstefano_zampini           }
2083b68353e5Sstefano_zampini         }
2084b68353e5Sstefano_zampini       }
2085b68353e5Sstefano_zampini     }
2086b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20879566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2088b68353e5Sstefano_zampini       if (fast) {
2089b68353e5Sstefano_zampini         PetscInt f, s;
2090b68353e5Sstefano_zampini 
20919566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20929371c9d4SSatish Balay         if (f != nf || s != 1) {
20939371c9d4SSatish Balay           fast = PETSC_FALSE;
20949371c9d4SSatish Balay         } else {
20959566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2096b68353e5Sstefano_zampini           nf += f;
2097b68353e5Sstefano_zampini         }
2098b68353e5Sstefano_zampini       }
2099b68353e5Sstefano_zampini     }
2100b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
21019566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2102b68353e5Sstefano_zampini       if (fast) {
2103b68353e5Sstefano_zampini         PetscInt f, s;
2104b68353e5Sstefano_zampini 
21059566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
21069371c9d4SSatish Balay         if (f != nf || s != 1) {
21079371c9d4SSatish Balay           fast = PETSC_FALSE;
21089371c9d4SSatish Balay         } else {
21099566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2110b68353e5Sstefano_zampini           nf += f;
2111b68353e5Sstefano_zampini         }
2112b68353e5Sstefano_zampini       }
2113b68353e5Sstefano_zampini     }
2114b68353e5Sstefano_zampini     if (fast) {
21159566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
21163ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2117b68353e5Sstefano_zampini     }
2118b68353e5Sstefano_zampini   }
21199566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
21209566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
21219566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2122d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2123d1487292SPierre Jolivet   else {
21249566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
21259566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
21269566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2127629c3df2SDmitry Karpeev   }
21289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2129e30678d3SPierre Jolivet   if (m) {
2130629c3df2SDmitry Karpeev     onnz = dnnz + m;
2131629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2132629c3df2SDmitry Karpeev       dnnz[k] = 0;
2133629c3df2SDmitry Karpeev       onnz[k] = 0;
2134629c3df2SDmitry Karpeev     }
2135e30678d3SPierre Jolivet   }
2136629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2137629c3df2SDmitry Karpeev     IS              bNis;
2138629c3df2SDmitry Karpeev     PetscInt        bN;
2139629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2140fd8a7442SPierre Jolivet     PetscBool       flg;
2141629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
21429566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
21439566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
21449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2145629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2146629c3df2SDmitry Karpeev       PetscSF         bmsf;
2147649b366bSFande Kong       PetscSFNode    *iremote;
2148fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2149649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2150629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2151629c3df2SDmitry Karpeev       if (!B) continue;
21529566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
21539566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
21549566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
21559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
21569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
21579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2158649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2159649b366bSFande Kong         sub_dnnz[k] = 0;
2160649b366bSFande Kong         sub_onnz[k] = 0;
2161649b366bSFande Kong       }
2162dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2163fd8a7442SPierre Jolivet       if (flg) {
2164fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2165fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2166fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2167fd8a7442SPierre Jolivet         B = D;
2168fd8a7442SPierre Jolivet       }
2169fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2170fd8a7442SPierre Jolivet       if (flg) {
2171fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2172fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2173fd8a7442SPierre Jolivet         B = D;
2174fd8a7442SPierre Jolivet       }
2175629c3df2SDmitry Karpeev       /*
2176629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2177629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2178629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2179629c3df2SDmitry Karpeev        */
21809566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2181629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2182131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2183629c3df2SDmitry Karpeev         const PetscInt *brcols;
2184a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2185131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21869566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2187649b366bSFande Kong         /* how many roots  */
21889371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21899371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2190649b366bSFande Kong         /* get nonzero pattern */
21919566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2192629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2193629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2194649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2195649b366bSFande Kong             sub_dnnz[br]++;
2196649b366bSFande Kong           } else {
2197649b366bSFande Kong             sub_onnz[br]++;
2198649b366bSFande Kong           }
2199629c3df2SDmitry Karpeev         }
22009566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2201629c3df2SDmitry Karpeev       }
2202fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
22039566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2204629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
22059566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
22069566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
22079566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
22089566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
22099566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
22109566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
22119566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
22129566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2213629c3df2SDmitry Karpeev     }
22149566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
22159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
221665a4a0a3Sstefano_zampini   }
221765a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
221865a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
221965a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
222065a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2221629c3df2SDmitry Karpeev   }
22229566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
22239566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
22249566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
22259566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2226d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
22279566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &C));
2228d1487292SPierre Jolivet   } else *newmat = C;
22293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2230be705e3aSPierre Jolivet }
2231629c3df2SDmitry Karpeev 
223266976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2233d71ae5a4SJacob Faibussowitsch {
2234629c3df2SDmitry Karpeev   Mat      B;
2235be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2236be705e3aSPierre Jolivet 
2237be705e3aSPierre Jolivet   PetscFunctionBegin;
22389566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
22399566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2240be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2241be705e3aSPierre Jolivet     B = *newmat;
22429566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2243be705e3aSPierre Jolivet   } else {
22449566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2245629c3df2SDmitry Karpeev   }
22469566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2247be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
22489566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
2249be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
22503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2251629c3df2SDmitry Karpeev }
2252629c3df2SDmitry Karpeev 
225366976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2254d71ae5a4SJacob Faibussowitsch {
22558b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
22563c6db4c4SPierre Jolivet   MatOperation opAdd;
22578b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
22588b7d3b4bSBarry Smith   PetscBool    flg;
22598b7d3b4bSBarry Smith 
22604d86920dSPierre Jolivet   PetscFunctionBegin;
226152c5f739Sprj-   *has = PETSC_FALSE;
22623c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
22633c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
22648b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
22658b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
22668b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
22679566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
22683ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
22698b7d3b4bSBarry Smith       }
22708b7d3b4bSBarry Smith     }
22718b7d3b4bSBarry Smith   }
22723c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
22733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22748b7d3b4bSBarry Smith }
22758b7d3b4bSBarry Smith 
2276659c6bb0SJed Brown /*MC
22772ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2278659c6bb0SJed Brown 
2279659c6bb0SJed Brown   Level: intermediate
2280659c6bb0SJed Brown 
2281659c6bb0SJed Brown   Notes:
228211a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2283659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
228411a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2285659c6bb0SJed Brown 
22868b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22878b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22888b7d3b4bSBarry Smith   than the nest matrix.
22898b7d3b4bSBarry Smith 
22901cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2291db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2292db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2293659c6bb0SJed Brown M*/
2294d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2295d71ae5a4SJacob Faibussowitsch {
2296c8883902SJed Brown   Mat_Nest *s;
2297c8883902SJed Brown 
2298c8883902SJed Brown   PetscFunctionBegin;
22994dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2300c8883902SJed Brown   A->data = (void *)s;
2301e7c19651SJed Brown 
2302e7c19651SJed Brown   s->nr            = -1;
2303e7c19651SJed Brown   s->nc            = -1;
23040298fd71SBarry Smith   s->m             = NULL;
2305e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2306c8883902SJed Brown 
23079566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
230826fbe8dcSKarl Rupp 
2309c8883902SJed Brown   A->ops->mult                      = MatMult_Nest;
23109194d70fSJed Brown   A->ops->multadd                   = MatMultAdd_Nest;
2311c8883902SJed Brown   A->ops->multtranspose             = MatMultTranspose_Nest;
23129194d70fSJed Brown   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2313f8170845SAlex Fikl   A->ops->transpose                 = MatTranspose_Nest;
23140998551bSBlanca Mellado Pinto   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
23150998551bSBlanca Mellado Pinto   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2316c8883902SJed Brown   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2317c8883902SJed Brown   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2318c8883902SJed Brown   A->ops->zeroentries               = MatZeroEntries_Nest;
2319c222c20dSDavid Ham   A->ops->copy                      = MatCopy_Nest;
23206e76ffeaSPierre Jolivet   A->ops->axpy                      = MatAXPY_Nest;
2321c8883902SJed Brown   A->ops->duplicate                 = MatDuplicate_Nest;
23227dae84e0SHong Zhang   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2323c8883902SJed Brown   A->ops->destroy                   = MatDestroy_Nest;
2324c8883902SJed Brown   A->ops->view                      = MatView_Nest;
2325f4259b30SLisandro Dalcin   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2326c8883902SJed Brown   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2327c8883902SJed Brown   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2328429bac76SJed Brown   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2329429bac76SJed Brown   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2330a061e289SJed Brown   A->ops->scale                     = MatScale_Nest;
2331a061e289SJed Brown   A->ops->shift                     = MatShift_Nest;
233213135bc6SAlex Fikl   A->ops->diagonalset               = MatDiagonalSet_Nest;
2333f8170845SAlex Fikl   A->ops->setrandom                 = MatSetRandom_Nest;
23348b7d3b4bSBarry Smith   A->ops->hasoperation              = MatHasOperation_Nest;
2335381b8e50SStefano Zampini   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2336c8883902SJed Brown 
2337f4259b30SLisandro Dalcin   A->spptr     = NULL;
2338c8883902SJed Brown   A->assembled = PETSC_FALSE;
2339c8883902SJed Brown 
2340c8883902SJed Brown   /* expose Nest api's */
23419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
23429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
23439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
23449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
23459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
23469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
23479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
23489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
23499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
23509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
23519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
23529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
23539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
23549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
23559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
23569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2357c8883902SJed Brown 
23589566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
23593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2360c8883902SJed Brown }
2361