xref: /petsc/src/mat/impls/nest/matnest.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
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 */
MatNestGetSizes_Private(Mat A,PetscInt * m,PetscInt * n,PetscInt * M,PetscInt * N)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 */
MatMult_Nest(Mat A,Vec x,Vec y)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 
MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)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- 
MatProductNumeric_Nest_Dense(Mat C)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- 
MatNest_DenseDestroy(PetscCtxRt ctx)155*2a8381b2SBarry Smith static PetscErrorCode MatNest_DenseDestroy(PetscCtxRt ctx)
156d71ae5a4SJacob Faibussowitsch {
157cc1eb50dSBarry Smith   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- 
MatProductSymbolic_Nest_Dense(Mat C)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- 
MatProductSetFromOptions_Nest_Dense(Mat C)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- 
MatMultTransposeKernel_Nest(Mat A,Vec x,Vec y,PetscBool herm)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 
MatMultTranspose_Nest(Mat A,Vec x,Vec y)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 
MatMultHermitianTranspose_Nest(Mat A,Vec x,Vec y)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 
MatMultTransposeAddKernel_Nest(Mat A,Vec x,Vec y,Vec z,PetscBool herm)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 
MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)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 
MatMultHermitianTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)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 
MatTranspose_Nest(Mat A,MatReuse reuse,Mat * B)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 
MatNestDestroyISList(PetscInt n,IS ** list)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 
MatReset_Nest(Mat A)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 
MatDestroy_Nest(Mat A)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 
MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
460d71ae5a4SJacob Faibussowitsch {
461d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
462d8588912SDave May   PetscInt  i, j;
46306a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
464d8588912SDave May 
465d8588912SDave May   PetscFunctionBegin;
466d8588912SDave May   for (i = 0; i < vs->nr; i++) {
467d8588912SDave May     for (j = 0; j < vs->nc; j++) {
46806a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
469e7c19651SJed Brown       if (vs->m[i][j]) {
4709566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
471e7c19651SJed Brown         if (!vs->splitassembly) {
472e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
473e7c19651SJed Brown            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
474e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
475e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
476e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
477e7c19651SJed Brown            */
4789566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
4799566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
480e7c19651SJed Brown         }
481e7c19651SJed Brown       }
48206a1af2fSStefano Zampini       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
48306a1af2fSStefano Zampini       vs->nnzstate[i * vs->nc + j] = subnnzstate;
484d8588912SDave May     }
485d8588912SDave May   }
48606a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
4873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
488d8588912SDave May }
489d8588912SDave May 
MatAssemblyEnd_Nest(Mat A,MatAssemblyType type)490d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
491d71ae5a4SJacob Faibussowitsch {
492d8588912SDave May   Mat_Nest *vs = (Mat_Nest *)A->data;
493d8588912SDave May   PetscInt  i, j;
494d8588912SDave May 
495d8588912SDave May   PetscFunctionBegin;
496d8588912SDave May   for (i = 0; i < vs->nr; i++) {
497d8588912SDave May     for (j = 0; j < vs->nc; j++) {
498e7c19651SJed Brown       if (vs->m[i][j]) {
49948a46eb9SPierre Jolivet         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
500e7c19651SJed Brown       }
501d8588912SDave May     }
502d8588912SDave May   }
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
504d8588912SDave May }
505d8588912SDave May 
MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat * B)506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
507d71ae5a4SJacob Faibussowitsch {
508f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
509f349c1fdSJed Brown   PetscInt  j;
510f349c1fdSJed Brown   Mat       sub;
511d8588912SDave May 
512d8588912SDave May   PetscFunctionBegin;
5130298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
514f349c1fdSJed Brown   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
5159566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
516f349c1fdSJed Brown   *B = sub;
5173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
518d8588912SDave May }
519d8588912SDave May 
MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat * B)520d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
521d71ae5a4SJacob Faibussowitsch {
522f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
523f349c1fdSJed Brown   PetscInt  i;
524f349c1fdSJed Brown   Mat       sub;
525f349c1fdSJed Brown 
526f349c1fdSJed Brown   PetscFunctionBegin;
5270298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
528f349c1fdSJed Brown   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
5299566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
530f349c1fdSJed Brown   *B = sub;
5313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
532d8588912SDave May }
533d8588912SDave May 
MatNestFindISRange(Mat A,PetscInt n,const IS list[],IS is,PetscInt * begin,PetscInt * end)534d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
535d71ae5a4SJacob Faibussowitsch {
53618d228c0SPierre Jolivet   PetscInt  i, j, size, m;
537f349c1fdSJed Brown   PetscBool flg;
53818d228c0SPierre Jolivet   IS        out, concatenate[2];
539f349c1fdSJed Brown 
540f349c1fdSJed Brown   PetscFunctionBegin;
5414f572ea9SToby Isaac   PetscAssertPointer(list, 3);
542f349c1fdSJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
54318d228c0SPierre Jolivet   if (begin) {
5444f572ea9SToby Isaac     PetscAssertPointer(begin, 5);
54518d228c0SPierre Jolivet     *begin = -1;
54618d228c0SPierre Jolivet   }
54718d228c0SPierre Jolivet   if (end) {
5484f572ea9SToby Isaac     PetscAssertPointer(end, 6);
54918d228c0SPierre Jolivet     *end = -1;
55018d228c0SPierre Jolivet   }
551f349c1fdSJed Brown   for (i = 0; i < n; i++) {
552207556f9SJed Brown     if (!list[i]) continue;
5539566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i], is, &flg));
554f349c1fdSJed Brown     if (flg) {
55518d228c0SPierre Jolivet       if (begin) *begin = i;
55618d228c0SPierre Jolivet       if (end) *end = i + 1;
5573ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
558f349c1fdSJed Brown     }
559f349c1fdSJed Brown   }
5609566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is, &size));
56118d228c0SPierre Jolivet   for (i = 0; i < n - 1; i++) {
56218d228c0SPierre Jolivet     if (!list[i]) continue;
56318d228c0SPierre Jolivet     m = 0;
5649566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
5659566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out, &m));
56618d228c0SPierre Jolivet     for (j = i + 2; j < n && m < size; j++) {
56718d228c0SPierre Jolivet       if (list[j]) {
56818d228c0SPierre Jolivet         concatenate[0] = out;
56918d228c0SPierre Jolivet         concatenate[1] = list[j];
5709566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
5719566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5729566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out, &m));
57318d228c0SPierre Jolivet       }
57418d228c0SPierre Jolivet     }
57518d228c0SPierre Jolivet     if (m == size) {
5769566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out, is, &flg));
57718d228c0SPierre Jolivet       if (flg) {
57818d228c0SPierre Jolivet         if (begin) *begin = i;
57918d228c0SPierre Jolivet         if (end) *end = j;
5809566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
5813ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
58218d228c0SPierre Jolivet       }
58318d228c0SPierre Jolivet     }
5849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
58518d228c0SPierre Jolivet   }
5863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
587f349c1fdSJed Brown }
588f349c1fdSJed Brown 
MatNestFillEmptyMat_Private(Mat A,PetscInt i,PetscInt j,Mat * B)589d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
590d71ae5a4SJacob Faibussowitsch {
5918188e55aSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
59218d228c0SPierre Jolivet   PetscInt  lr, lc;
59318d228c0SPierre Jolivet 
59418d228c0SPierre Jolivet   PetscFunctionBegin;
5959566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5969566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
5979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
5989566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
5999566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B, MATAIJ));
6009566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
6019566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
6029566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6039566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
6049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
6059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60718d228c0SPierre Jolivet }
60818d228c0SPierre Jolivet 
MatNestGetBlock_Private(Mat A,PetscInt rbegin,PetscInt rend,PetscInt cbegin,PetscInt cend,Mat * B)609d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
610d71ae5a4SJacob Faibussowitsch {
61118d228c0SPierre Jolivet   Mat_Nest  *vs = (Mat_Nest *)A->data;
61218d228c0SPierre Jolivet   Mat       *a;
61318d228c0SPierre Jolivet   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
6148188e55aSJed Brown   char       keyname[256];
61518d228c0SPierre Jolivet   PetscBool *b;
61618d228c0SPierre Jolivet   PetscBool  flg;
6178188e55aSJed Brown 
6188188e55aSJed Brown   PetscFunctionBegin;
6190298fd71SBarry Smith   *B = NULL;
6209566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
6219566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
6223ba16761SJacob Faibussowitsch   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
6238188e55aSJed Brown 
6249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
62518d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
62618d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
62718d228c0SPierre Jolivet       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
62818d228c0SPierre Jolivet       b[i * nc + j] = PETSC_FALSE;
62918d228c0SPierre Jolivet     }
63018d228c0SPierre Jolivet   }
63118d228c0SPierre Jolivet   if (nc != vs->nc && nr != vs->nr) {
63218d228c0SPierre Jolivet     for (i = 0; i < nr; i++) {
63318d228c0SPierre Jolivet       for (j = 0; j < nc; j++) {
63418d228c0SPierre Jolivet         flg = PETSC_FALSE;
63518d228c0SPierre Jolivet         for (k = 0; (k < nr && !flg); k++) {
63618d228c0SPierre Jolivet           if (a[j + k * nc]) flg = PETSC_TRUE;
63718d228c0SPierre Jolivet         }
63818d228c0SPierre Jolivet         if (flg) {
63918d228c0SPierre Jolivet           flg = PETSC_FALSE;
64018d228c0SPierre Jolivet           for (l = 0; (l < nc && !flg); l++) {
64118d228c0SPierre Jolivet             if (a[i * nc + l]) flg = PETSC_TRUE;
64218d228c0SPierre Jolivet           }
64318d228c0SPierre Jolivet         }
64418d228c0SPierre Jolivet         if (!flg) {
64518d228c0SPierre Jolivet           b[i * nc + j] = PETSC_TRUE;
6469566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
64718d228c0SPierre Jolivet         }
64818d228c0SPierre Jolivet       }
64918d228c0SPierre Jolivet     }
65018d228c0SPierre Jolivet   }
6519566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
65218d228c0SPierre Jolivet   for (i = 0; i < nr; i++) {
65318d228c0SPierre Jolivet     for (j = 0; j < nc; j++) {
65448a46eb9SPierre Jolivet       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
65518d228c0SPierre Jolivet     }
65618d228c0SPierre Jolivet   }
6579566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a, b));
6588188e55aSJed Brown   (*B)->assembled = A->assembled;
6599566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
6609566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6628188e55aSJed Brown }
6638188e55aSJed Brown 
MatNestFindSubMat(Mat A,struct MatNestISPair * is,IS isrow,IS iscol,Mat * B)664d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
665d71ae5a4SJacob Faibussowitsch {
666f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
66718d228c0SPierre Jolivet   PetscInt  rbegin, rend, cbegin, cend;
668f349c1fdSJed Brown 
669f349c1fdSJed Brown   PetscFunctionBegin;
6709566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
6719566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
67218d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
67348a46eb9SPierre Jolivet     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
67418d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
67518d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6769566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
67718d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
6783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
679f349c1fdSJed Brown }
680f349c1fdSJed Brown 
68106a1af2fSStefano Zampini /*
68206a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
68306a1af2fSStefano Zampini */
MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat * B)684d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
685d71ae5a4SJacob Faibussowitsch {
686f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
687f349c1fdSJed Brown   Mat       sub;
688f349c1fdSJed Brown 
689f349c1fdSJed Brown   PetscFunctionBegin;
6909566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
691f349c1fdSJed Brown   switch (reuse) {
692f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
693768f1002SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)sub));
694768f1002SStefano Zampini     if (sub) PetscCall(PetscObjectStateIncrease((PetscObject)sub));
695f349c1fdSJed Brown     *B = sub;
696f349c1fdSJed Brown     break;
697d71ae5a4SJacob Faibussowitsch   case MAT_REUSE_MATRIX:
698d71ae5a4SJacob Faibussowitsch     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
699768f1002SStefano Zampini     if (sub) PetscCall(PetscObjectStateIncrease((PetscObject)sub));
700d71ae5a4SJacob Faibussowitsch     break;
701768f1002SStefano Zampini   default:
702d71ae5a4SJacob Faibussowitsch     break;
703f349c1fdSJed Brown   }
7043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
705f349c1fdSJed Brown }
706f349c1fdSJed Brown 
MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat * B)70766976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
708d71ae5a4SJacob Faibussowitsch {
709f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
710f349c1fdSJed Brown   Mat       sub;
711f349c1fdSJed Brown 
712f349c1fdSJed Brown   PetscFunctionBegin;
7139566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
714f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7159566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
716f349c1fdSJed Brown   *B = sub;
7173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
718d8588912SDave May }
719d8588912SDave May 
MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat * B)720d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
721d71ae5a4SJacob Faibussowitsch {
722f349c1fdSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
723f349c1fdSJed Brown   Mat       sub;
724d8588912SDave May 
725d8588912SDave May   PetscFunctionBegin;
7269566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
72708401ef6SPierre Jolivet   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
728f349c1fdSJed Brown   if (sub) {
729aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
7309566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
731d8588912SDave May   }
7323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
733d8588912SDave May }
734d8588912SDave May 
MatGetDiagonal_Nest(Mat A,Vec v)735d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
736d71ae5a4SJacob Faibussowitsch {
7377874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
7387874fa86SDave May   PetscInt  i;
7397874fa86SDave May 
7407874fa86SDave May   PetscFunctionBegin;
7417874fa86SDave May   for (i = 0; i < bA->nr; i++) {
742429bac76SJed Brown     Vec bv;
7439566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
7447874fa86SDave May     if (bA->m[i][i]) {
7459566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
7467874fa86SDave May     } else {
7479566063dSJacob Faibussowitsch       PetscCall(VecSet(bv, 0.0));
7487874fa86SDave May     }
7499566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
7507874fa86SDave May   }
7513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7527874fa86SDave May }
7537874fa86SDave May 
MatDiagonalScale_Nest(Mat A,Vec l,Vec r)754d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
755d71ae5a4SJacob Faibussowitsch {
7567874fa86SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
757429bac76SJed Brown   Vec       bl, *br;
7587874fa86SDave May   PetscInt  i, j;
7597874fa86SDave May 
7607874fa86SDave May   PetscFunctionBegin;
7619566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc, &br));
7622e6472ebSElliott Sales de Andrade   if (r) {
7639566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
7642e6472ebSElliott Sales de Andrade   }
7652e6472ebSElliott Sales de Andrade   bl = NULL;
7667874fa86SDave May   for (i = 0; i < bA->nr; i++) {
76748a46eb9SPierre Jolivet     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
7687874fa86SDave May     for (j = 0; j < bA->nc; j++) {
76948a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
7707874fa86SDave May     }
77148a46eb9SPierre Jolivet     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
7722e6472ebSElliott Sales de Andrade   }
7732e6472ebSElliott Sales de Andrade   if (r) {
7749566063dSJacob Faibussowitsch     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
7752e6472ebSElliott Sales de Andrade   }
7769566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
7773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7787874fa86SDave May }
7797874fa86SDave May 
MatScale_Nest(Mat A,PetscScalar a)780d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
781d71ae5a4SJacob Faibussowitsch {
782a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
783a061e289SJed Brown   PetscInt  i, j;
784a061e289SJed Brown 
785a061e289SJed Brown   PetscFunctionBegin;
786a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
787a061e289SJed Brown     for (j = 0; j < bA->nc; j++) {
78848a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
789a061e289SJed Brown     }
790a061e289SJed Brown   }
7913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
792a061e289SJed Brown }
793a061e289SJed Brown 
MatShift_Nest(Mat A,PetscScalar a)794d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
795d71ae5a4SJacob Faibussowitsch {
796a061e289SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
797a061e289SJed Brown   PetscInt  i;
79806a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
799a061e289SJed Brown 
800a061e289SJed Brown   PetscFunctionBegin;
801a061e289SJed Brown   for (i = 0; i < bA->nr; i++) {
80206a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
80308401ef6SPierre Jolivet     PetscCheck(bA->m[i][i], PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for shifting an empty diagonal block, insert a matrix in block (%" PetscInt_FMT ",%" PetscInt_FMT ")", i, i);
8049566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i], a));
8059566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
80606a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
80706a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
808a061e289SJed Brown   }
80906a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
811a061e289SJed Brown }
812a061e289SJed Brown 
MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)813d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
814d71ae5a4SJacob Faibussowitsch {
81513135bc6SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
81613135bc6SAlex Fikl   PetscInt  i;
81706a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
81813135bc6SAlex Fikl 
81913135bc6SAlex Fikl   PetscFunctionBegin;
82013135bc6SAlex Fikl   for (i = 0; i < bA->nr; i++) {
82106a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82213135bc6SAlex Fikl     Vec              bv;
8239566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
82413135bc6SAlex Fikl     if (bA->m[i][i]) {
8259566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
8269566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
82713135bc6SAlex Fikl     }
8289566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
82906a1af2fSStefano Zampini     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
83006a1af2fSStefano Zampini     bA->nnzstate[i * bA->nc + i] = subnnzstate;
83113135bc6SAlex Fikl   }
83206a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
8333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83413135bc6SAlex Fikl }
83513135bc6SAlex Fikl 
MatSetRandom_Nest(Mat A,PetscRandom rctx)836d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
837d71ae5a4SJacob Faibussowitsch {
838f8170845SAlex Fikl   Mat_Nest *bA = (Mat_Nest *)A->data;
839f8170845SAlex Fikl   PetscInt  i, j;
840f8170845SAlex Fikl 
841f8170845SAlex Fikl   PetscFunctionBegin;
842f8170845SAlex Fikl   for (i = 0; i < bA->nr; i++) {
843f8170845SAlex Fikl     for (j = 0; j < bA->nc; j++) {
84448a46eb9SPierre Jolivet       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
845f8170845SAlex Fikl     }
846f8170845SAlex Fikl   }
8473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
848f8170845SAlex Fikl }
849f8170845SAlex Fikl 
MatCreateVecs_Nest(Mat A,Vec * right,Vec * left)850d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
851d71ae5a4SJacob Faibussowitsch {
852d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
853d8588912SDave May   Vec      *L, *R;
854d8588912SDave May   MPI_Comm  comm;
855d8588912SDave May   PetscInt  i, j;
856d8588912SDave May 
857d8588912SDave May   PetscFunctionBegin;
8589566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
859d8588912SDave May   if (right) {
860d8588912SDave May     /* allocate R */
8619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
862d8588912SDave May     /* Create the right vectors */
863d8588912SDave May     for (j = 0; j < bA->nc; j++) {
864d8588912SDave May       for (i = 0; i < bA->nr; i++) {
865d8588912SDave May         if (bA->m[i][j]) {
8669566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
867d8588912SDave May           break;
868d8588912SDave May         }
869d8588912SDave May       }
87008401ef6SPierre Jolivet       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
871d8588912SDave May     }
8729566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
873d8588912SDave May     /* hand back control to the nest vector */
87448a46eb9SPierre Jolivet     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
8759566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
876d8588912SDave May   }
877d8588912SDave May 
878d8588912SDave May   if (left) {
879d8588912SDave May     /* allocate L */
8809566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
881d8588912SDave May     /* Create the left vectors */
882d8588912SDave May     for (i = 0; i < bA->nr; i++) {
883d8588912SDave May       for (j = 0; j < bA->nc; j++) {
884d8588912SDave May         if (bA->m[i][j]) {
8859566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
886d8588912SDave May           break;
887d8588912SDave May         }
888d8588912SDave May       }
88908401ef6SPierre Jolivet       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
890d8588912SDave May     }
891d8588912SDave May 
8929566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
89348a46eb9SPierre Jolivet     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
894d8588912SDave May 
8959566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
896d8588912SDave May   }
8973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
898d8588912SDave May }
899d8588912SDave May 
MatView_Nest(Mat A,PetscViewer viewer)900d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
901d71ae5a4SJacob Faibussowitsch {
902d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
90329e60adbSStefano Zampini   PetscBool isascii, viewSub = PETSC_FALSE;
904d8588912SDave May   PetscInt  i, j;
905d8588912SDave May 
906d8588912SDave May   PetscFunctionBegin;
9079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
908d8588912SDave May   if (isascii) {
90930924786SStefano Zampini     PetscViewerFormat format;
91030924786SStefano Zampini 
91130924786SStefano Zampini     PetscCall(PetscViewerGetFormat(viewer, &format));
91230924786SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
91330924786SStefano Zampini       Mat T;
91430924786SStefano Zampini 
91530924786SStefano Zampini       PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &T));
91630924786SStefano Zampini       PetscCall(MatView(T, viewer));
91730924786SStefano Zampini       PetscCall(MatDestroy(&T));
91830924786SStefano Zampini       PetscFunctionReturn(PETSC_SUCCESS);
91930924786SStefano Zampini     }
9209566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
9219566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9227e1a0bbeSBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", structure:\n", bA->nr, bA->nc));
923d8588912SDave May     for (i = 0; i < bA->nr; i++) {
924d8588912SDave May       for (j = 0; j < bA->nc; j++) {
92519fd82e9SBarry Smith         MatType   type;
926270f95d7SJed Brown         char      name[256] = "", prefix[256] = "";
927d8588912SDave May         PetscInt  NR, NC;
928d8588912SDave May         PetscBool isNest = PETSC_FALSE;
929d8588912SDave May 
930d8588912SDave May         if (!bA->m[i][j]) {
9319566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
932d8588912SDave May           continue;
933d8588912SDave May         }
9349566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
9359566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9369566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
9379566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
9389566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
939d8588912SDave May 
9409566063dSJacob 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));
941d8588912SDave May 
94229e60adbSStefano Zampini         if (isNest || viewSub) {
9439566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
9449566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j], viewer));
9459566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
946d8588912SDave May         }
947d8588912SDave May       }
948d8588912SDave May     }
9499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
950d8588912SDave May   }
9513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
952d8588912SDave May }
953d8588912SDave May 
MatZeroEntries_Nest(Mat A)954d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A)
955d71ae5a4SJacob Faibussowitsch {
956d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
957d8588912SDave May   PetscInt  i, j;
958d8588912SDave May 
959d8588912SDave May   PetscFunctionBegin;
960d8588912SDave May   for (i = 0; i < bA->nr; i++) {
961d8588912SDave May     for (j = 0; j < bA->nc; j++) {
962d8588912SDave May       if (!bA->m[i][j]) continue;
9639566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
964d8588912SDave May     }
965d8588912SDave May   }
9663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
967d8588912SDave May }
968d8588912SDave May 
MatCopy_Nest(Mat A,Mat B,MatStructure str)969d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
970d71ae5a4SJacob Faibussowitsch {
971c222c20dSDavid Ham   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
972c222c20dSDavid Ham   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
97306a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
974c222c20dSDavid Ham 
975c222c20dSDavid Ham   PetscFunctionBegin;
976aed4548fSBarry 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);
977c222c20dSDavid Ham   for (i = 0; i < nr; i++) {
978c222c20dSDavid Ham     for (j = 0; j < nc; j++) {
97906a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
98046a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
9819566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
9829566063dSJacob Faibussowitsch         PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
98306a1af2fSStefano Zampini         nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
98406a1af2fSStefano Zampini         bB->nnzstate[i * nc + j] = subnnzstate;
985ea6db252SJose E. Roman       } else if (bA->m[i][j]) { // bB->m[i][j] is NULL
986ea6db252SJose E. Roman         Mat M;
987ea6db252SJose E. Roman 
988ea6db252SJose 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);
989ea6db252SJose E. Roman         PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M));
990ea6db252SJose E. Roman         PetscCall(MatNestSetSubMat(B, i, j, M));
991ea6db252SJose E. Roman         PetscCall(MatDestroy(&M));
992ea6db252SJose E. Roman       } else if (bB->m[i][j]) { // bA->m[i][j] is NULL
993ea6db252SJose 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);
994ea6db252SJose E. Roman         PetscCall(MatNestSetSubMat(B, i, j, NULL));
995ea6db252SJose E. Roman       }
996c222c20dSDavid Ham     }
997c222c20dSDavid Ham   }
99806a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
9993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1000c222c20dSDavid Ham }
1001c222c20dSDavid Ham 
MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)1002d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1003d71ae5a4SJacob Faibussowitsch {
10046e76ffeaSPierre Jolivet   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
10056e76ffeaSPierre Jolivet   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
100606a1af2fSStefano Zampini   PetscBool nnzstate = PETSC_FALSE;
10076e76ffeaSPierre Jolivet 
10086e76ffeaSPierre Jolivet   PetscFunctionBegin;
1009aed4548fSBarry 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);
10106e76ffeaSPierre Jolivet   for (i = 0; i < nr; i++) {
10116e76ffeaSPierre Jolivet     for (j = 0; j < nc; j++) {
101206a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10136e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10149566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1015c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1016c066aebcSStefano Zampini         Mat M;
1017c066aebcSStefano Zampini 
1018e75569e9SPierre 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);
10199566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
10209566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y, i, j, M));
10219566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1022c066aebcSStefano Zampini       }
10239566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
102406a1af2fSStefano Zampini       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
102506a1af2fSStefano Zampini       bY->nnzstate[i * nc + j] = subnnzstate;
10266e76ffeaSPierre Jolivet     }
10276e76ffeaSPierre Jolivet   }
102806a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10306e76ffeaSPierre Jolivet }
10316e76ffeaSPierre Jolivet 
MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat * B)1032d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1033d71ae5a4SJacob Faibussowitsch {
1034d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1035841e96a3SJed Brown   Mat      *b;
1036841e96a3SJed Brown   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1037d8588912SDave May 
1038d8588912SDave May   PetscFunctionBegin;
10399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr * nc, &b));
1040841e96a3SJed Brown   for (i = 0; i < nr; i++) {
1041841e96a3SJed Brown     for (j = 0; j < nc; j++) {
1042841e96a3SJed Brown       if (bA->m[i][j]) {
10439566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1044841e96a3SJed Brown       } else {
10450298fd71SBarry Smith         b[i * nc + j] = NULL;
1046d8588912SDave May       }
1047d8588912SDave May     }
1048d8588912SDave May   }
10499566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1050841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
105148a46eb9SPierre Jolivet   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
10529566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1053d8588912SDave May 
10549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
10559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
10563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1057d8588912SDave May }
1058d8588912SDave May 
1059d8588912SDave May /* nest api */
MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat * mat)106066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1061d71ae5a4SJacob Faibussowitsch {
1062d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
10635fd66863SKarl Rupp 
1064d8588912SDave May   PetscFunctionBegin;
106508401ef6SPierre 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);
106608401ef6SPierre 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);
1067d8588912SDave May   *mat = bA->m[idxm][jdxm];
10683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1069d8588912SDave May }
1070d8588912SDave May 
10719ba0d327SJed Brown /*@
107211a5261eSBarry Smith   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1073d8588912SDave May 
10742ef1f0ffSBarry Smith   Not Collective
1075d8588912SDave May 
1076d8588912SDave May   Input Parameters:
107711a5261eSBarry Smith + A    - `MATNEST` matrix
1078d8588912SDave May . idxm - index of the matrix within the nest matrix
1079629881c0SJed Brown - jdxm - index of the matrix within the nest matrix
1080d8588912SDave May 
1081d8588912SDave May   Output Parameter:
10822ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1083d8588912SDave May 
1084d8588912SDave May   Level: developer
1085d8588912SDave May 
1086fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1087db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1088d8588912SDave May @*/
MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat * sub)1089d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1090d71ae5a4SJacob Faibussowitsch {
1091d8588912SDave May   PetscFunctionBegin;
10923536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
10933536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
10943536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
10953536838dSStefano Zampini   PetscAssertPointer(sub, 4);
1096cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
10973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1098d8588912SDave May }
1099d8588912SDave May 
MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)110066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1101d71ae5a4SJacob Faibussowitsch {
11020782ca92SJed Brown   Mat_Nest *bA = (Mat_Nest *)A->data;
11030782ca92SJed Brown   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
11040782ca92SJed Brown 
11050782ca92SJed Brown   PetscFunctionBegin;
110608401ef6SPierre 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);
110708401ef6SPierre 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);
11083536838dSStefano Zampini   if (mat) {
11099566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(mat, &m, &n));
11109566063dSJacob Faibussowitsch     PetscCall(MatGetSize(mat, &M, &N));
11119566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
11129566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
11139566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
11149566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1115aed4548fSBarry 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);
1116aed4548fSBarry 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);
11173536838dSStefano Zampini   }
111826fbe8dcSKarl Rupp 
111906a1af2fSStefano Zampini   /* do not increase object state */
11203ba16761SJacob Faibussowitsch   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
112106a1af2fSStefano Zampini 
11229566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11240782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11259566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11263536838dSStefano Zampini   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
11273536838dSStefano Zampini   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
112806a1af2fSStefano Zampini   A->nonzerostate++;
11293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11300782ca92SJed Brown }
11310782ca92SJed Brown 
11329ba0d327SJed Brown /*@
113311a5261eSBarry Smith   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
11340782ca92SJed Brown 
11352ef1f0ffSBarry Smith   Logically Collective
11360782ca92SJed Brown 
11370782ca92SJed Brown   Input Parameters:
113811a5261eSBarry Smith + A    - `MATNEST` matrix
11390782ca92SJed Brown . idxm - index of the matrix within the nest matrix
11400782ca92SJed Brown . jdxm - index of the matrix within the nest matrix
11412ef1f0ffSBarry Smith - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
11422ef1f0ffSBarry Smith 
11432ef1f0ffSBarry Smith   Level: developer
11440782ca92SJed Brown 
11450782ca92SJed Brown   Notes:
11460782ca92SJed Brown   The new submatrix must have the same size and communicator as that block of the nest.
11470782ca92SJed Brown 
11480782ca92SJed Brown   This increments the reference count of the submatrix.
11490782ca92SJed Brown 
1150fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1151db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11520782ca92SJed Brown @*/
MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)1153d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1154d71ae5a4SJacob Faibussowitsch {
11550782ca92SJed Brown   PetscFunctionBegin;
11563536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11573536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, idxm, 2);
11583536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, jdxm, 3);
11593536838dSStefano Zampini   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
11603536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
11613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11620782ca92SJed Brown }
11630782ca92SJed Brown 
MatNestGetSubMats_Nest(Mat A,PetscInt * M,PetscInt * N,Mat *** mat)116466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1165d71ae5a4SJacob Faibussowitsch {
1166d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
11675fd66863SKarl Rupp 
1168d8588912SDave May   PetscFunctionBegin;
116926fbe8dcSKarl Rupp   if (M) *M = bA->nr;
117026fbe8dcSKarl Rupp   if (N) *N = bA->nc;
117126fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
11723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1173d8588912SDave May }
1174d8588912SDave May 
1175d8588912SDave May /*@C
117611a5261eSBarry Smith   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1177d8588912SDave May 
11782ef1f0ffSBarry Smith   Not Collective
1179d8588912SDave May 
1180f899ff85SJose E. Roman   Input Parameter:
1181629881c0SJed Brown . A - nest matrix
1182d8588912SDave May 
1183d8d19677SJose E. Roman   Output Parameters:
1184a3b724e8SBarry Smith + M   - number of submatrix rows in the nest matrix
1185a3b724e8SBarry Smith . N   - number of submatrix columns in the nest matrix
1186e9d3347aSJose E. Roman - mat - array of matrices
1187d8588912SDave May 
11882ef1f0ffSBarry Smith   Level: developer
11892ef1f0ffSBarry Smith 
119011a5261eSBarry Smith   Note:
11912ef1f0ffSBarry Smith   The user should not free the array `mat`.
1192d8588912SDave May 
1193fe59aa6dSJacob Faibussowitsch   Fortran Notes:
1194a3b724e8SBarry Smith   This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)`
119520f4b53cSBarry Smith   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1196e9d3347aSJose E. Roman   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1197351962e3SVincent Le Chenadec 
1198fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1199db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1200d8588912SDave May @*/
MatNestGetSubMats(Mat A,PetscInt * M,PetscInt * N,Mat *** mat)1201d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1202d71ae5a4SJacob Faibussowitsch {
1203d8588912SDave May   PetscFunctionBegin;
12043536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1205cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
12063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1207d8588912SDave May }
1208d8588912SDave May 
MatNestGetSize_Nest(Mat A,PetscInt * M,PetscInt * N)120966976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1210d71ae5a4SJacob Faibussowitsch {
1211d8588912SDave May   Mat_Nest *bA = (Mat_Nest *)A->data;
1212d8588912SDave May 
1213d8588912SDave May   PetscFunctionBegin;
121426fbe8dcSKarl Rupp   if (M) *M = bA->nr;
121526fbe8dcSKarl Rupp   if (N) *N = bA->nc;
12163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1217d8588912SDave May }
1218d8588912SDave May 
12199ba0d327SJed Brown /*@
122011a5261eSBarry Smith   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1221d8588912SDave May 
12222ef1f0ffSBarry Smith   Not Collective
1223d8588912SDave May 
1224f899ff85SJose E. Roman   Input Parameter:
122511a5261eSBarry Smith . A - `MATNEST` matrix
1226d8588912SDave May 
1227d8d19677SJose E. Roman   Output Parameters:
1228629881c0SJed Brown + M - number of rows in the nested mat
1229629881c0SJed Brown - N - number of cols in the nested mat
1230d8588912SDave May 
1231d8588912SDave May   Level: developer
1232d8588912SDave May 
123380670ca5SBarry Smith   Note:
123480670ca5SBarry Smith   `size` refers to the number of submatrices in the row and column directions of the nested matrix
123580670ca5SBarry Smith 
1236fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1237db781477SPatrick Sanan           `MatNestGetISs()`
1238d8588912SDave May @*/
MatNestGetSize(Mat A,PetscInt * M,PetscInt * N)1239d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1240d71ae5a4SJacob Faibussowitsch {
1241d8588912SDave May   PetscFunctionBegin;
12423536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1243cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
12443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1245d8588912SDave May }
1246d8588912SDave May 
MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])1247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1248d71ae5a4SJacob Faibussowitsch {
1249900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1250900e7ff2SJed Brown   PetscInt  i;
1251900e7ff2SJed Brown 
1252900e7ff2SJed Brown   PetscFunctionBegin;
12539371c9d4SSatish Balay   if (rows)
12549371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
12559371c9d4SSatish Balay   if (cols)
12569371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
12573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1258900e7ff2SJed Brown }
1259900e7ff2SJed Brown 
1260664df05cSJose E. Roman /*@
126111a5261eSBarry Smith   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1262900e7ff2SJed Brown 
12632ef1f0ffSBarry Smith   Not Collective
1264900e7ff2SJed Brown 
1265f899ff85SJose E. Roman   Input Parameter:
126611a5261eSBarry Smith . A - `MATNEST` matrix
1267900e7ff2SJed Brown 
1268d8d19677SJose E. Roman   Output Parameters:
1269a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore)
1270a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore)
1271900e7ff2SJed Brown 
1272900e7ff2SJed Brown   Level: advanced
1273900e7ff2SJed Brown 
127411a5261eSBarry Smith   Note:
12752ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1276900e7ff2SJed Brown 
1277fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1278fe59aa6dSJacob Faibussowitsch           `MatCreateNest()`, `MatNestSetSubMats()`
1279900e7ff2SJed Brown @*/
MatNestGetISs(Mat A,IS rows[],IS cols[])1280d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1281d71ae5a4SJacob Faibussowitsch {
1282900e7ff2SJed Brown   PetscFunctionBegin;
1283900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1284cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
12853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1286900e7ff2SJed Brown }
1287900e7ff2SJed Brown 
MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])1288d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1289d71ae5a4SJacob Faibussowitsch {
1290900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
1291900e7ff2SJed Brown   PetscInt  i;
1292900e7ff2SJed Brown 
1293900e7ff2SJed Brown   PetscFunctionBegin;
12949371c9d4SSatish Balay   if (rows)
12959371c9d4SSatish Balay     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
12969371c9d4SSatish Balay   if (cols)
12979371c9d4SSatish Balay     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
12983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1299900e7ff2SJed Brown }
1300900e7ff2SJed Brown 
13015d83a8b1SBarry Smith /*@
130211a5261eSBarry Smith   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1303900e7ff2SJed Brown 
13042ef1f0ffSBarry Smith   Not Collective
1305900e7ff2SJed Brown 
1306f899ff85SJose E. Roman   Input Parameter:
130711a5261eSBarry Smith . A - `MATNEST` matrix
1308900e7ff2SJed Brown 
1309d8d19677SJose E. Roman   Output Parameters:
1310a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore)
1311a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore)
1312900e7ff2SJed Brown 
1313900e7ff2SJed Brown   Level: advanced
1314900e7ff2SJed Brown 
131511a5261eSBarry Smith   Note:
13162ef1f0ffSBarry Smith   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1317900e7ff2SJed Brown 
13181cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1319fe59aa6dSJacob Faibussowitsch           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1320900e7ff2SJed Brown @*/
MatNestGetLocalISs(Mat A,IS rows[],IS cols[])1321d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1322d71ae5a4SJacob Faibussowitsch {
1323900e7ff2SJed Brown   PetscFunctionBegin;
1324900e7ff2SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1325cac4c232SBarry Smith   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
13263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1327900e7ff2SJed Brown }
1328900e7ff2SJed Brown 
MatNestSetVecType_Nest(Mat A,VecType vtype)132966976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1330d71ae5a4SJacob Faibussowitsch {
1331207556f9SJed Brown   PetscBool flg;
1332207556f9SJed Brown 
1333207556f9SJed Brown   PetscFunctionBegin;
13349566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1335207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13362a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
13370d5ef98aSSatish Balay   else A->ops->getvecs = NULL;
13383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1339207556f9SJed Brown }
1340207556f9SJed Brown 
13415d83a8b1SBarry Smith /*@
134211a5261eSBarry Smith   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1343207556f9SJed Brown 
13442ef1f0ffSBarry Smith   Not Collective
1345207556f9SJed Brown 
1346207556f9SJed Brown   Input Parameters:
134711a5261eSBarry Smith + A     - `MATNEST` matrix
134811a5261eSBarry Smith - vtype - `VecType` to use for creating vectors
1349207556f9SJed Brown 
1350207556f9SJed Brown   Level: developer
1351207556f9SJed Brown 
1352fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1353207556f9SJed Brown @*/
MatNestSetVecType(Mat A,VecType vtype)1354d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1355d71ae5a4SJacob Faibussowitsch {
1356207556f9SJed Brown   PetscFunctionBegin;
13573536838dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1358cac4c232SBarry Smith   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
13593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1360207556f9SJed Brown }
1361207556f9SJed Brown 
MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])136266976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1363d71ae5a4SJacob Faibussowitsch {
1364c8883902SJed Brown   Mat_Nest *s = (Mat_Nest *)A->data;
1365c8883902SJed Brown   PetscInt  i, j, m, n, M, N;
136688ffe2e8SJose E. Roman   PetscBool cong, isstd, sametype = PETSC_FALSE;
136788ffe2e8SJose E. Roman   VecType   vtype, type;
1368d8588912SDave May 
1369d8588912SDave May   PetscFunctionBegin;
13709566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
137106a1af2fSStefano Zampini 
1372c8883902SJed Brown   s->nr = nr;
1373c8883902SJed Brown   s->nc = nc;
1374d8588912SDave May 
1375c8883902SJed Brown   /* Create space for submatrices */
13769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->m));
13778068ee9dSPierre Jolivet   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1378c8883902SJed Brown   for (i = 0; i < nr; i++) {
13798068ee9dSPierre Jolivet     s->m[i] = s->m[0] + i * nc;
1380c8883902SJed Brown     for (j = 0; j < nc; j++) {
13813536838dSStefano Zampini       s->m[i][j] = a ? a[i * nc + j] : NULL;
13823536838dSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1383d8588912SDave May     }
1384d8588912SDave May   }
13859566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
13869566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
138788ffe2e8SJose E. Roman   if (isstd) {
138888ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
138988ffe2e8SJose E. Roman     vtype = NULL;
139088ffe2e8SJose E. Roman     for (i = 0; i < nr; i++) {
139188ffe2e8SJose E. Roman       for (j = 0; j < nc; j++) {
13923536838dSStefano Zampini         if (s->m[i][j]) {
139388ffe2e8SJose E. Roman           if (!vtype) { /* first visited block */
13943536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &vtype));
139588ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
139688ffe2e8SJose E. Roman           } else if (sametype) {
13973536838dSStefano Zampini             PetscCall(MatGetVecType(s->m[i][j], &type));
13989566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype, type, &sametype));
139988ffe2e8SJose E. Roman           }
140088ffe2e8SJose E. Roman         }
140188ffe2e8SJose E. Roman       }
140288ffe2e8SJose E. Roman     }
140388ffe2e8SJose E. Roman     if (sametype) { /* propagate vectype */
14049566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A, vtype));
140588ffe2e8SJose E. Roman     }
140688ffe2e8SJose E. Roman   }
1407d8588912SDave May 
14089566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1409d8588912SDave May 
14109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &s->row_len));
14119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &s->col_len));
1412c8883902SJed Brown   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1413c8883902SJed Brown   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1414d8588912SDave May 
14159566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
141606a1af2fSStefano Zampini   for (i = 0; i < nr; i++) {
141706a1af2fSStefano Zampini     for (j = 0; j < nc; j++) {
141848a46eb9SPierre Jolivet       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
141906a1af2fSStefano Zampini     }
142006a1af2fSStefano Zampini   }
142106a1af2fSStefano Zampini 
14229566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1423d8588912SDave May 
14249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap, M));
14259566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
14269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap, N));
14279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1428c8883902SJed Brown 
14299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
14309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1431c8883902SJed Brown 
143206a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
143306a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14349566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
143506a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
143606a1af2fSStefano Zampini   if (cong) {
143748a46eb9SPierre Jolivet     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
143806a1af2fSStefano Zampini   }
143906a1af2fSStefano Zampini   if (!cong) {
144006a1af2fSStefano Zampini     A->ops->getdiagonal = NULL;
144106a1af2fSStefano Zampini     A->ops->shift       = NULL;
144206a1af2fSStefano Zampini     A->ops->diagonalset = NULL;
144306a1af2fSStefano Zampini   }
144406a1af2fSStefano Zampini 
14459566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
14469566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
144706a1af2fSStefano Zampini   A->nonzerostate++;
14483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1449d8588912SDave May }
1450d8588912SDave May 
1451c8883902SJed Brown /*@
145211a5261eSBarry Smith   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1453c8883902SJed Brown 
1454c3339decSBarry Smith   Collective
1455c8883902SJed Brown 
1456d8d19677SJose E. Roman   Input Parameters:
145711a5261eSBarry Smith + A      - `MATNEST` matrix
1458c8883902SJed Brown . nr     - number of nested row blocks
14592ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1460c8883902SJed Brown . nc     - number of nested column blocks
14612ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
146258ad77e8SBarry Smith - a      - array of $ nr \times nc$ submatrices, or `NULL`
14632ef1f0ffSBarry Smith 
14642ef1f0ffSBarry Smith   Level: advanced
1465c8883902SJed Brown 
1466e9d3347aSJose E. Roman   Notes:
14673536838dSStefano Zampini   This always resets any block matrix information previously set.
1468ce78bad3SBarry Smith 
1469d8b4a066SPierre Jolivet   Pass `NULL` in the corresponding entry of `a` for an empty block.
147006a1af2fSStefano Zampini 
147158ad77e8SBarry 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
1472e9d3347aSJose E. Roman   `MatCreateNest()` for an example.
1473e9d3347aSJose E. Roman 
147458ad77e8SBarry Smith   Fortran Note:
147558ad77e8SBarry Smith   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
147658ad77e8SBarry Smith 
14771cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1478c8883902SJed Brown @*/
MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])147958ad77e8SBarry Smith PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) PeNSS
1480d71ae5a4SJacob Faibussowitsch {
1481c8883902SJed Brown   PetscFunctionBegin;
1482c8883902SJed Brown   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
14833536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nr, 2);
148408401ef6SPierre Jolivet   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1485c8883902SJed Brown   if (nr && is_row) {
14864f572ea9SToby Isaac     PetscAssertPointer(is_row, 3);
14873536838dSStefano Zampini     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1488c8883902SJed Brown   }
14893536838dSStefano Zampini   PetscValidLogicalCollectiveInt(A, nc, 4);
149008401ef6SPierre Jolivet   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
14911664e352SJed Brown   if (nc && is_col) {
14924f572ea9SToby Isaac     PetscAssertPointer(is_col, 5);
14933536838dSStefano Zampini     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1494c8883902SJed Brown   }
14953536838dSStefano Zampini   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
14963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1497c8883902SJed Brown }
1498d8588912SDave May 
MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping * ltog)1499d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1500d71ae5a4SJacob Faibussowitsch {
150177019fcaSJed Brown   PetscBool flg;
150277019fcaSJed Brown   PetscInt  i, j, m, mi, *ix;
150377019fcaSJed Brown 
150477019fcaSJed Brown   PetscFunctionBegin;
1505aea6d515SStefano Zampini   *ltog = NULL;
150677019fcaSJed Brown   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
150777019fcaSJed Brown     if (islocal[i]) {
15089566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
150977019fcaSJed Brown       flg = PETSC_TRUE; /* We found a non-trivial entry */
151077019fcaSJed Brown     } else {
15119566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
151277019fcaSJed Brown     }
151377019fcaSJed Brown     m += mi;
151477019fcaSJed Brown   }
15153ba16761SJacob Faibussowitsch   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1516aea6d515SStefano Zampini 
15179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &ix));
1518165cd838SBarry Smith   for (i = 0, m = 0; i < n; i++) {
15190298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1520e108cb99SStefano Zampini     Mat                    sub  = NULL;
1521f6d38dbbSStefano Zampini     PetscSF                sf;
1522f6d38dbbSStefano Zampini     PetscLayout            map;
1523aea6d515SStefano Zampini     const PetscInt        *ix2;
152477019fcaSJed Brown 
1525165cd838SBarry Smith     if (!colflg) {
15269566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
152777019fcaSJed Brown     } else {
15289566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
152977019fcaSJed Brown     }
1530191fd14bSBarry Smith     if (sub) {
1531191fd14bSBarry Smith       if (!colflg) {
15329566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1533191fd14bSBarry Smith       } else {
15349566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1535191fd14bSBarry Smith       }
1536191fd14bSBarry Smith     }
153777019fcaSJed Brown     /*
153877019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
153977019fcaSJed 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.
154077019fcaSJed Brown     */
15419566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i], &ix2));
1542aea6d515SStefano Zampini     if (islocal[i]) {
1543aea6d515SStefano Zampini       PetscInt *ilocal, *iremote;
1544aea6d515SStefano Zampini       PetscInt  mil, nleaves;
1545aea6d515SStefano Zampini 
15469566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i], &mi));
154728b400f6SJacob Faibussowitsch       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1548aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = j;
15499566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1550aea6d515SStefano Zampini 
1551aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1553aea6d515SStefano Zampini       for (j = 0, nleaves = 0; j < mi; j++) {
1554aea6d515SStefano Zampini         if (ix[m + j] < 0) continue;
1555aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1556aea6d515SStefano Zampini         iremote[nleaves] = ix[m + j];
1557aea6d515SStefano Zampini         nleaves++;
1558aea6d515SStefano Zampini       }
15599566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mil));
15609566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
15619566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
15629566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map, mil));
15639566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15649566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
15659566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15669566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15679566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
15689566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15699566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal, iremote));
1570aea6d515SStefano Zampini     } else {
15719566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1572aea6d515SStefano Zampini       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1573aea6d515SStefano Zampini     }
15749566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
157577019fcaSJed Brown     m += mi;
157677019fcaSJed Brown   }
15779566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
15783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
157977019fcaSJed Brown }
158077019fcaSJed Brown 
1581d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1582d8588912SDave May /*
1583d8588912SDave May   nprocessors = NP
1584d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1585d8588912SDave May        proc 0: => (g_0,h_0,)
1586d8588912SDave May        proc 1: => (g_1,h_1,)
1587d8588912SDave May        ...
1588d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1589d8588912SDave May 
1590d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1591d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1592d8588912SDave May 
1593d8588912SDave May             proc 0:
1594d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1595d8588912SDave May             proc 1:
1596d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1597d8588912SDave May 
1598d8588912SDave May             proc NP-1:
1599d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1600d8588912SDave May */
MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])1601d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1602d71ae5a4SJacob Faibussowitsch {
1603e2d7f03fSJed Brown   Mat_Nest *vs = (Mat_Nest *)A->data;
16048188e55aSJed Brown   PetscInt  i, j, offset, n, nsum, bs;
16050298fd71SBarry Smith   Mat       sub = NULL;
1606d8588912SDave May 
1607d8588912SDave May   PetscFunctionBegin;
16089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
16099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1610d8588912SDave May   if (is_row) { /* valid IS is passed in */
1611a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1612e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16139566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1614e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1615d8588912SDave May     }
16162ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
16178188e55aSJed Brown     nsum = 0;
16188188e55aSJed Brown     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
16199566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
162028b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
16219566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
162208401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16238188e55aSJed Brown       nsum += n;
16248188e55aSJed Brown     }
16259566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
162630bc264bSJed Brown     offset -= nsum;
1627e2d7f03fSJed Brown     for (i = 0; i < vs->nr; i++) {
16289566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16299566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, &n, NULL));
16309566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
16329566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
16332ae74bdbSJed Brown       offset += n;
1634d8588912SDave May     }
1635d8588912SDave May   }
1636d8588912SDave May 
1637d8588912SDave May   if (is_col) { /* valid IS is passed in */
1638a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1639e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16409566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1641e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1642d8588912SDave May     }
16432ae74bdbSJed Brown   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
16442ae74bdbSJed Brown     offset = A->cmap->rstart;
16458188e55aSJed Brown     nsum   = 0;
16468188e55aSJed Brown     for (j = 0; j < vs->nc; j++) {
16479566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
164828b400f6SJacob Faibussowitsch       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
16499566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
165008401ef6SPierre Jolivet       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
16518188e55aSJed Brown       nsum += n;
16528188e55aSJed Brown     }
16539566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
165430bc264bSJed Brown     offset -= nsum;
1655e2d7f03fSJed Brown     for (j = 0; j < vs->nc; j++) {
16569566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
16579566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub, NULL, &n));
16589566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16599566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
16609566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
16612ae74bdbSJed Brown       offset += n;
1662d8588912SDave May     }
1663d8588912SDave May   }
1664e2d7f03fSJed Brown 
1665e2d7f03fSJed Brown   /* Set up the local ISs */
16669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
16679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1668e2d7f03fSJed Brown   for (i = 0, offset = 0; i < vs->nr; i++) {
1669e2d7f03fSJed Brown     IS                     isloc;
16700298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1671e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16729566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
16739566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1674207556f9SJed Brown     if (rmap) {
16759566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
16769566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
16779566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16789566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1679207556f9SJed Brown     } else {
1680207556f9SJed Brown       nlocal = 0;
16810298fd71SBarry Smith       isloc  = NULL;
1682207556f9SJed Brown     }
1683e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1684e2d7f03fSJed Brown     offset += nlocal;
1685e2d7f03fSJed Brown   }
16868188e55aSJed Brown   for (i = 0, offset = 0; i < vs->nc; i++) {
1687e2d7f03fSJed Brown     IS                     isloc;
16880298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1689e2d7f03fSJed Brown     PetscInt               nlocal, bs;
16909566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
16919566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1692207556f9SJed Brown     if (cmap) {
16939566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
16949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
16959566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
16969566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc, bs));
1697207556f9SJed Brown     } else {
1698207556f9SJed Brown       nlocal = 0;
16990298fd71SBarry Smith       isloc  = NULL;
1700207556f9SJed Brown     }
1701e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1702e2d7f03fSJed Brown     offset += nlocal;
1703e2d7f03fSJed Brown   }
17040189643fSJed Brown 
170577019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
170677019fcaSJed Brown   {
170745b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap, cmap;
17089566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
17099566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
17109566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
17119566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
17129566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
171377019fcaSJed Brown   }
171477019fcaSJed Brown 
171576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17160189643fSJed Brown     for (i = 0; i < vs->nr; i++) {
17170189643fSJed Brown       for (j = 0; j < vs->nc; j++) {
17180189643fSJed Brown         PetscInt m, n, M, N, mi, ni, Mi, Ni;
17190189643fSJed Brown         Mat      B = vs->m[i][j];
17200189643fSJed Brown         if (!B) continue;
17219566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B, &M, &N));
17229566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B, &m, &n));
17239566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
17249566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
17259566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
17269566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1727aed4548fSBarry 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);
1728aed4548fSBarry 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);
17290189643fSJed Brown       }
17300189643fSJed Brown     }
173176bd3646SJed Brown   }
1732a061e289SJed Brown 
1733a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1734a061e289SJed Brown   for (i = 0; i < vs->nr; i++) {
1735a061e289SJed Brown     for (j = 0; j < vs->nc; j++) {
17363ba16761SJacob Faibussowitsch       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1737a061e289SJed Brown     }
1738a061e289SJed Brown   }
1739a061e289SJed Brown   A->assembled = PETSC_TRUE;
17403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1741d8588912SDave May }
1742d8588912SDave May 
174345c38901SJed Brown /*@C
174411a5261eSBarry Smith   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1745659c6bb0SJed Brown 
174611a5261eSBarry Smith   Collective
1747659c6bb0SJed Brown 
1748d8d19677SJose E. Roman   Input Parameters:
174911a5261eSBarry Smith + comm   - Communicator for the new `MATNEST`
1750659c6bb0SJed Brown . nr     - number of nested row blocks
17512ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous
1752659c6bb0SJed Brown . nc     - number of nested column blocks
17532ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous
175458ad77e8SBarry Smith - a      - array of $nr \times nc$ submatrices, empty submatrices can be passed using `NULL`
1755659c6bb0SJed Brown 
1756659c6bb0SJed Brown   Output Parameter:
1757659c6bb0SJed Brown . B - new matrix
1758659c6bb0SJed Brown 
175958ad77e8SBarry Smith   Level: advanced
176058ad77e8SBarry Smith 
1761e9d3347aSJose E. Roman   Note:
176258ad77e8SBarry 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.
1763e9d3347aSJose E. Roman   For instance, to represent the matrix
1764e9d3347aSJose E. Roman   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1765e9d3347aSJose E. Roman   one should use `Mat a[4]={A11,A12,A21,A22}`.
1766e9d3347aSJose E. Roman 
176758ad77e8SBarry Smith   Fortran Note:
176858ad77e8SBarry Smith   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
1769659c6bb0SJed Brown 
17701cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1771db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1772db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1773659c6bb0SJed Brown @*/
MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat * B)1774030363d8SJose 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
1775d71ae5a4SJacob Faibussowitsch {
1776d8588912SDave May   PetscFunctionBegin;
17773536838dSStefano Zampini   PetscCall(MatCreate(comm, B));
17783536838dSStefano Zampini   PetscCall(MatSetType(*B, MATNEST));
17793536838dSStefano Zampini   (*B)->preallocated = PETSC_TRUE;
17803536838dSStefano Zampini   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
17813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1782d8588912SDave May }
1783659c6bb0SJed Brown 
MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat * newmat)178466976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1785d71ae5a4SJacob Faibussowitsch {
1786b68353e5Sstefano_zampini   Mat_Nest     *nest = (Mat_Nest *)A->data;
178723875855Sstefano_zampini   Mat          *trans;
1788b68353e5Sstefano_zampini   PetscScalar **avv;
1789b68353e5Sstefano_zampini   PetscScalar  *vv;
1790b68353e5Sstefano_zampini   PetscInt    **aii, **ajj;
1791b68353e5Sstefano_zampini   PetscInt     *ii, *jj, *ci;
1792b68353e5Sstefano_zampini   PetscInt      nr, nc, nnz, i, j;
1793b68353e5Sstefano_zampini   PetscBool     done;
1794b68353e5Sstefano_zampini 
1795b68353e5Sstefano_zampini   PetscFunctionBegin;
17969566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &nr, &nc));
1797b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1798b68353e5Sstefano_zampini     PetscInt rnr;
1799b68353e5Sstefano_zampini 
18009566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
180128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
180208401ef6SPierre Jolivet     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
18039566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1804b68353e5Sstefano_zampini   }
1805b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1806b68353e5Sstefano_zampini   nnz = 0;
18079566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1808b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1809b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1810b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1811b68353e5Sstefano_zampini       if (B) {
1812b68353e5Sstefano_zampini         PetscScalar *naa;
1813b68353e5Sstefano_zampini         PetscInt    *nii, *njj, nnr;
181423875855Sstefano_zampini         PetscBool    istrans;
1815b68353e5Sstefano_zampini 
1816013e2dc7SBarry Smith         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
181723875855Sstefano_zampini         if (istrans) {
181823875855Sstefano_zampini           Mat Bt;
181923875855Sstefano_zampini 
18209566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B, &Bt));
18219566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
182223875855Sstefano_zampini           B = trans[i * nest->nc + j];
1823013e2dc7SBarry Smith         } else {
1824013e2dc7SBarry Smith           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1825013e2dc7SBarry Smith           if (istrans) {
1826013e2dc7SBarry Smith             Mat Bt;
1827013e2dc7SBarry Smith 
1828013e2dc7SBarry Smith             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1829013e2dc7SBarry Smith             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1830013e2dc7SBarry Smith             B = trans[i * nest->nc + j];
1831013e2dc7SBarry Smith           }
183223875855Sstefano_zampini         }
18339566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
183428b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
18359566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B, &naa));
1836b68353e5Sstefano_zampini         nnz += nii[nnr];
1837b68353e5Sstefano_zampini 
1838b68353e5Sstefano_zampini         aii[i * nest->nc + j] = nii;
1839b68353e5Sstefano_zampini         ajj[i * nest->nc + j] = njj;
1840b68353e5Sstefano_zampini         avv[i * nest->nc + j] = naa;
1841b68353e5Sstefano_zampini       }
1842b68353e5Sstefano_zampini     }
1843b68353e5Sstefano_zampini   }
1844b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr + 1, &ii));
18469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &jj));
18479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz, &vv));
1848b68353e5Sstefano_zampini   } else {
184908401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1850b68353e5Sstefano_zampini   }
1851b68353e5Sstefano_zampini 
1852b68353e5Sstefano_zampini   /* new row pointer */
18539566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii, nr + 1));
1854b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1855b68353e5Sstefano_zampini     PetscInt ncr, rst;
1856b68353e5Sstefano_zampini 
18579566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18589566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1859b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1860b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1861b68353e5Sstefano_zampini         PetscInt *nii = aii[i * nest->nc + j];
1862b68353e5Sstefano_zampini         PetscInt  ir;
1863b68353e5Sstefano_zampini 
1864b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1865b68353e5Sstefano_zampini           ii[ir + 1] += nii[1] - nii[0];
1866b68353e5Sstefano_zampini           nii++;
1867b68353e5Sstefano_zampini         }
1868b68353e5Sstefano_zampini       }
1869b68353e5Sstefano_zampini     }
1870b68353e5Sstefano_zampini   }
1871b68353e5Sstefano_zampini   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1872b68353e5Sstefano_zampini 
1873b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18749566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr, &ci));
1875b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1876b68353e5Sstefano_zampini     PetscInt ncr, rst;
1877b68353e5Sstefano_zampini 
18789566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
18799566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1880b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1881b68353e5Sstefano_zampini       if (aii[i * nest->nc + j]) {
1882b22c5e46SPierre Jolivet         PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0;
1883b68353e5Sstefano_zampini         PetscInt    *nii = aii[i * nest->nc + j];
1884b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i * nest->nc + j];
1885b68353e5Sstefano_zampini         PetscInt     ir, cst;
1886b68353e5Sstefano_zampini 
1887b22c5e46SPierre Jolivet         if (trans[i * nest->nc + j]) {
1888b22c5e46SPierre Jolivet           vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale;
1889b22c5e46SPierre Jolivet           vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift;
1890b22c5e46SPierre Jolivet         }
18919566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1892b68353e5Sstefano_zampini         for (ir = rst; ir < ncr + rst; ++ir) {
1893b68353e5Sstefano_zampini           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1894b68353e5Sstefano_zampini 
1895b68353e5Sstefano_zampini           for (ij = 0; ij < rsize; ij++) {
1896b68353e5Sstefano_zampini             jj[ist + ij] = *njj + cst;
1897b22c5e46SPierre Jolivet             vv[ist + ij] = vscale * *nvv;
1898b22c5e46SPierre Jolivet             if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift;
1899b68353e5Sstefano_zampini             njj++;
1900b68353e5Sstefano_zampini             nvv++;
1901b68353e5Sstefano_zampini           }
1902b68353e5Sstefano_zampini           ci[ir] += rsize;
1903b68353e5Sstefano_zampini           nii++;
1904b68353e5Sstefano_zampini         }
1905b68353e5Sstefano_zampini       }
1906b68353e5Sstefano_zampini     }
1907b68353e5Sstefano_zampini   }
19089566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1909b68353e5Sstefano_zampini 
1910b68353e5Sstefano_zampini   /* restore info */
1911b68353e5Sstefano_zampini   for (i = 0; i < nest->nr; ++i) {
1912b68353e5Sstefano_zampini     for (j = 0; j < nest->nc; ++j) {
1913b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1914b68353e5Sstefano_zampini       if (B) {
1915b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i * nest->nc + j;
191623875855Sstefano_zampini 
191723875855Sstefano_zampini         B = (trans[k] ? trans[k] : B);
19189566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
191928b400f6SJacob Faibussowitsch         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
19209566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
19219566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1922b68353e5Sstefano_zampini       }
1923b68353e5Sstefano_zampini     }
1924b68353e5Sstefano_zampini   }
19259566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii, ajj, avv, trans));
1926b68353e5Sstefano_zampini 
1927b68353e5Sstefano_zampini   /* finalize newmat */
1928b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
19299566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1930b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1931b68353e5Sstefano_zampini     Mat B;
1932b68353e5Sstefano_zampini 
19339566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
19349566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1935b68353e5Sstefano_zampini   }
19369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
19379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1938b68353e5Sstefano_zampini   {
1939b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1940b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1941b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1942b68353e5Sstefano_zampini   }
19433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1944b68353e5Sstefano_zampini }
1945b68353e5Sstefano_zampini 
MatAXPY_Dense_Nest(Mat Y,PetscScalar a,Mat X)1946d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1947d71ae5a4SJacob Faibussowitsch {
1948be705e3aSPierre Jolivet   Mat_Nest *nest = (Mat_Nest *)X->data;
1949be705e3aSPierre Jolivet   PetscInt  i, j, k, rstart;
1950be705e3aSPierre Jolivet   PetscBool flg;
1951be705e3aSPierre Jolivet 
1952be705e3aSPierre Jolivet   PetscFunctionBegin;
1953be705e3aSPierre Jolivet   /* Fill by row */
1954be705e3aSPierre Jolivet   for (j = 0; j < nest->nc; ++j) {
1955be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1956be705e3aSPierre Jolivet     IS              bNis;
1957be705e3aSPierre Jolivet     PetscInt        bN;
1958be705e3aSPierre Jolivet     const PetscInt *bNindices;
19599566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19609566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
19619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
1962be705e3aSPierre Jolivet     for (i = 0; i < nest->nr; ++i) {
1963fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
1964be705e3aSPierre Jolivet       PetscInt        bm, br;
1965be705e3aSPierre Jolivet       const PetscInt *bmindices;
1966be705e3aSPierre Jolivet       if (!B) continue;
1967013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1968be705e3aSPierre Jolivet       if (flg) {
1969cac4c232SBarry Smith         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1970cac4c232SBarry Smith         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
19719566063dSJacob Faibussowitsch         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1972be705e3aSPierre Jolivet         B = D;
1973be705e3aSPierre Jolivet       }
19749566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1975be705e3aSPierre Jolivet       if (flg) {
1976fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1977fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1978be705e3aSPierre Jolivet         B = D;
1979be705e3aSPierre Jolivet       }
19809566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
19819566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
19829566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1983be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1984be705e3aSPierre Jolivet         PetscInt           row = bmindices[br], brncols, *cols;
1985be705e3aSPierre Jolivet         const PetscInt    *brcols;
1986be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1987be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19889566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
19899566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols, &cols));
1990be705e3aSPierre Jolivet         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1991be705e3aSPierre Jolivet         /*
1992be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1993be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1994be705e3aSPierre Jolivet          */
1995be705e3aSPierre Jolivet         if (a != 1.0) {
19969566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols, &vals));
1997be705e3aSPierre Jolivet           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
19989566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
19999566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
2000be705e3aSPierre Jolivet         } else {
20019566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
2002be705e3aSPierre Jolivet         }
20039566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
20049566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
2005be705e3aSPierre Jolivet       }
2006fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
20079566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2008be705e3aSPierre Jolivet     }
20099566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
20109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
2011be705e3aSPierre Jolivet   }
20129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
20139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
20143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2015be705e3aSPierre Jolivet }
2016be705e3aSPierre Jolivet 
MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat * newmat)201766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2018d71ae5a4SJacob Faibussowitsch {
2019629c3df2SDmitry Karpeev   Mat_Nest   *nest = (Mat_Nest *)A->data;
2020e30678d3SPierre Jolivet   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2021b68353e5Sstefano_zampini   PetscMPIInt size;
2022629c3df2SDmitry Karpeev   Mat         C;
2023629c3df2SDmitry Karpeev 
2024629c3df2SDmitry Karpeev   PetscFunctionBegin;
20259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2026b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2027b68353e5Sstefano_zampini     PetscInt  nf;
2028b68353e5Sstefano_zampini     PetscBool fast;
2029b68353e5Sstefano_zampini 
20309566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
203148a46eb9SPierre Jolivet     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2032b68353e5Sstefano_zampini     for (i = 0; i < nest->nr && fast; ++i) {
2033b68353e5Sstefano_zampini       for (j = 0; j < nest->nc && fast; ++j) {
2034b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
2035b68353e5Sstefano_zampini         if (B) {
20369566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
203723875855Sstefano_zampini           if (!fast) {
203823875855Sstefano_zampini             PetscBool istrans;
203923875855Sstefano_zampini 
2040013e2dc7SBarry Smith             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
204123875855Sstefano_zampini             if (istrans) {
204223875855Sstefano_zampini               Mat Bt;
204323875855Sstefano_zampini 
20449566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B, &Bt));
20459566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2046013e2dc7SBarry Smith             } else {
2047013e2dc7SBarry Smith               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2048013e2dc7SBarry Smith               if (istrans) {
2049013e2dc7SBarry Smith                 Mat Bt;
2050013e2dc7SBarry Smith 
2051013e2dc7SBarry Smith                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2052013e2dc7SBarry Smith                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2053013e2dc7SBarry Smith               }
205423875855Sstefano_zampini             }
2055b22c5e46SPierre 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);
2056b68353e5Sstefano_zampini           }
2057b68353e5Sstefano_zampini         }
2058b68353e5Sstefano_zampini       }
2059b68353e5Sstefano_zampini     }
2060b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
20619566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2062b68353e5Sstefano_zampini       if (fast) {
2063b68353e5Sstefano_zampini         PetscInt f, s;
2064b68353e5Sstefano_zampini 
20659566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
20669371c9d4SSatish Balay         if (f != nf || s != 1) {
20679371c9d4SSatish Balay           fast = PETSC_FALSE;
20689371c9d4SSatish Balay         } else {
20699566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2070b68353e5Sstefano_zampini           nf += f;
2071b68353e5Sstefano_zampini         }
2072b68353e5Sstefano_zampini       }
2073b68353e5Sstefano_zampini     }
2074b68353e5Sstefano_zampini     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
20759566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2076b68353e5Sstefano_zampini       if (fast) {
2077b68353e5Sstefano_zampini         PetscInt f, s;
2078b68353e5Sstefano_zampini 
20799566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
20809371c9d4SSatish Balay         if (f != nf || s != 1) {
20819371c9d4SSatish Balay           fast = PETSC_FALSE;
20829371c9d4SSatish Balay         } else {
20839566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2084b68353e5Sstefano_zampini           nf += f;
2085b68353e5Sstefano_zampini         }
2086b68353e5Sstefano_zampini       }
2087b68353e5Sstefano_zampini     }
2088b68353e5Sstefano_zampini     if (fast) {
20899566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
20903ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
2091b68353e5Sstefano_zampini     }
2092b68353e5Sstefano_zampini   }
20939566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
20949566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
20959566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2096d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2097d1487292SPierre Jolivet   else {
20989566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
20999566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, newtype));
21009566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, m, n, M, N));
2101629c3df2SDmitry Karpeev   }
21029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * m, &dnnz));
2103e30678d3SPierre Jolivet   if (m) {
2104629c3df2SDmitry Karpeev     onnz = dnnz + m;
2105629c3df2SDmitry Karpeev     for (k = 0; k < m; k++) {
2106629c3df2SDmitry Karpeev       dnnz[k] = 0;
2107629c3df2SDmitry Karpeev       onnz[k] = 0;
2108629c3df2SDmitry Karpeev     }
2109e30678d3SPierre Jolivet   }
2110629c3df2SDmitry Karpeev   for (j = 0; j < nest->nc; ++j) {
2111629c3df2SDmitry Karpeev     IS              bNis;
2112629c3df2SDmitry Karpeev     PetscInt        bN;
2113629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2114fd8a7442SPierre Jolivet     PetscBool       flg;
2115629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
21169566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
21179566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
21189566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis, &bNindices));
2119629c3df2SDmitry Karpeev     for (i = 0; i < nest->nr; ++i) {
2120629c3df2SDmitry Karpeev       PetscSF         bmsf;
2121649b366bSFande Kong       PetscSFNode    *iremote;
2122fd8a7442SPierre Jolivet       Mat             B = nest->m[i][j], D = NULL;
2123649b366bSFande Kong       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2124629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2125629c3df2SDmitry Karpeev       if (!B) continue;
21269566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
21279566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
21289566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
21299566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &iremote));
21309566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_dnnz));
21319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm, &sub_onnz));
2132649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2133649b366bSFande Kong         sub_dnnz[k] = 0;
2134649b366bSFande Kong         sub_onnz[k] = 0;
2135649b366bSFande Kong       }
2136dead4d76SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2137fd8a7442SPierre Jolivet       if (flg) {
2138fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2139fd8a7442SPierre Jolivet         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2140fd8a7442SPierre Jolivet         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2141fd8a7442SPierre Jolivet         B = D;
2142fd8a7442SPierre Jolivet       }
2143fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2144fd8a7442SPierre Jolivet       if (flg) {
2145fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2146fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2147fd8a7442SPierre Jolivet         B = D;
2148fd8a7442SPierre Jolivet       }
2149629c3df2SDmitry Karpeev       /*
2150629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2151629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2152629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2153629c3df2SDmitry Karpeev        */
21549566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2155629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2156131c27b5Sprj-         PetscInt        row = bmindices[br], brncols, col;
2157629c3df2SDmitry Karpeev         const PetscInt *brcols;
2158a4b3d3acSMatthew G Knepley         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2159131c27b5Sprj-         PetscMPIInt     rowowner = 0;
21609566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2161649b366bSFande Kong         /* how many roots  */
21629371c9d4SSatish Balay         iremote[br].rank  = rowowner;
21639371c9d4SSatish Balay         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2164649b366bSFande Kong         /* get nonzero pattern */
21659566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2166629c3df2SDmitry Karpeev         for (k = 0; k < brncols; k++) {
2167629c3df2SDmitry Karpeev           col = bNindices[brcols[k]];
2168649b366bSFande Kong           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2169649b366bSFande Kong             sub_dnnz[br]++;
2170649b366bSFande Kong           } else {
2171649b366bSFande Kong             sub_onnz[br]++;
2172649b366bSFande Kong           }
2173629c3df2SDmitry Karpeev         }
21749566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2175629c3df2SDmitry Karpeev       }
2176fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21779566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2178629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21799566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
21809566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21819566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
21829566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21839566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
21849566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21859566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21869566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2187629c3df2SDmitry Karpeev     }
21889566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis, &bNindices));
21899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
219065a4a0a3Sstefano_zampini   }
219165a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
219265a4a0a3Sstefano_zampini   for (i = 0; i < m; i++) {
219365a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
219465a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2195629c3df2SDmitry Karpeev   }
21969566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
21979566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
21989566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21999566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2200ac530a7eSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &C));
2201ac530a7eSPierre Jolivet   else *newmat = C;
22023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2203be705e3aSPierre Jolivet }
2204629c3df2SDmitry Karpeev 
MatConvert_Nest_Dense(Mat A,MatType newtype,MatReuse reuse,Mat * newmat)220566976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2206d71ae5a4SJacob Faibussowitsch {
2207629c3df2SDmitry Karpeev   Mat      B;
2208be705e3aSPierre Jolivet   PetscInt m, n, M, N;
2209be705e3aSPierre Jolivet 
2210be705e3aSPierre Jolivet   PetscFunctionBegin;
22119566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
22129566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &m, &n));
2213be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2214be705e3aSPierre Jolivet     B = *newmat;
22159566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2216be705e3aSPierre Jolivet   } else {
22179566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2218629c3df2SDmitry Karpeev   }
22199566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2220ac530a7eSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
2221ac530a7eSPierre Jolivet   else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
22223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2223629c3df2SDmitry Karpeev }
2224629c3df2SDmitry Karpeev 
MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool * has)222566976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2226d71ae5a4SJacob Faibussowitsch {
22278b7d3b4bSBarry Smith   Mat_Nest    *bA = (Mat_Nest *)mat->data;
22283c6db4c4SPierre Jolivet   MatOperation opAdd;
22298b7d3b4bSBarry Smith   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
22308b7d3b4bSBarry Smith   PetscBool    flg;
22318b7d3b4bSBarry Smith 
22324d86920dSPierre Jolivet   PetscFunctionBegin;
223352c5f739Sprj-   *has = PETSC_FALSE;
22343c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
22353c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
22368b7d3b4bSBarry Smith     for (j = 0; j < nc; j++) {
22378b7d3b4bSBarry Smith       for (i = 0; i < nr; i++) {
22388b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
22399566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
22403ba16761SJacob Faibussowitsch         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
22418b7d3b4bSBarry Smith       }
22428b7d3b4bSBarry Smith     }
22438b7d3b4bSBarry Smith   }
22443c6db4c4SPierre Jolivet   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
22453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22468b7d3b4bSBarry Smith }
22478b7d3b4bSBarry Smith 
2248659c6bb0SJed Brown /*MC
22492ef1f0ffSBarry Smith   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2250659c6bb0SJed Brown 
2251659c6bb0SJed Brown   Level: intermediate
2252659c6bb0SJed Brown 
2253659c6bb0SJed Brown   Notes:
225411a5261eSBarry Smith   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2255659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
225611a5261eSBarry Smith   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2257659c6bb0SJed Brown 
22588b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22598b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22608b7d3b4bSBarry Smith   than the nest matrix.
22618b7d3b4bSBarry Smith 
22621cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2263db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2264db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2265659c6bb0SJed Brown M*/
MatCreate_Nest(Mat A)2266d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2267d71ae5a4SJacob Faibussowitsch {
2268c8883902SJed Brown   Mat_Nest *s;
2269c8883902SJed Brown 
2270c8883902SJed Brown   PetscFunctionBegin;
22714dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&s));
2272c8883902SJed Brown   A->data = (void *)s;
2273e7c19651SJed Brown 
2274e7c19651SJed Brown   s->nr            = -1;
2275e7c19651SJed Brown   s->nc            = -1;
22760298fd71SBarry Smith   s->m             = NULL;
2277e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2278c8883902SJed Brown 
22799566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
228026fbe8dcSKarl Rupp 
2281c8883902SJed Brown   A->ops->mult                      = MatMult_Nest;
22829194d70fSJed Brown   A->ops->multadd                   = MatMultAdd_Nest;
2283c8883902SJed Brown   A->ops->multtranspose             = MatMultTranspose_Nest;
22849194d70fSJed Brown   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2285f8170845SAlex Fikl   A->ops->transpose                 = MatTranspose_Nest;
22860998551bSBlanca Mellado Pinto   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
22870998551bSBlanca Mellado Pinto   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2288c8883902SJed Brown   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2289c8883902SJed Brown   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2290c8883902SJed Brown   A->ops->zeroentries               = MatZeroEntries_Nest;
2291c222c20dSDavid Ham   A->ops->copy                      = MatCopy_Nest;
22926e76ffeaSPierre Jolivet   A->ops->axpy                      = MatAXPY_Nest;
2293c8883902SJed Brown   A->ops->duplicate                 = MatDuplicate_Nest;
22947dae84e0SHong Zhang   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2295c8883902SJed Brown   A->ops->destroy                   = MatDestroy_Nest;
2296c8883902SJed Brown   A->ops->view                      = MatView_Nest;
2297f4259b30SLisandro Dalcin   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2298c8883902SJed Brown   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2299c8883902SJed Brown   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2300429bac76SJed Brown   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2301429bac76SJed Brown   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2302a061e289SJed Brown   A->ops->scale                     = MatScale_Nest;
2303a061e289SJed Brown   A->ops->shift                     = MatShift_Nest;
230413135bc6SAlex Fikl   A->ops->diagonalset               = MatDiagonalSet_Nest;
2305f8170845SAlex Fikl   A->ops->setrandom                 = MatSetRandom_Nest;
23068b7d3b4bSBarry Smith   A->ops->hasoperation              = MatHasOperation_Nest;
2307c8883902SJed Brown 
2308f4259b30SLisandro Dalcin   A->spptr     = NULL;
2309c8883902SJed Brown   A->assembled = PETSC_FALSE;
2310c8883902SJed Brown 
2311c8883902SJed Brown   /* expose Nest api's */
23129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
23139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
23149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
23159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
23169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
23179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
23189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
23199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
23209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
23219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
23229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
23239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
23249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
23259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
23269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
23279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2328c8883902SJed Brown 
23299566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
23303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2331c8883902SJed Brown }
2332