xref: /petsc/src/mat/impls/is/matis.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1b4319ba4SBarry Smith /*
2b4319ba4SBarry Smith     Creates a matrix class for using the Neumann-Neumann type preconditioners.
3b4319ba4SBarry Smith     This stores the matrices in globally unassembled form. Each processor
4b4319ba4SBarry Smith     assembles only its local Neumann problem and the parallel matrix vector
5b4319ba4SBarry Smith     product is handled "implicitly".
6b4319ba4SBarry Smith 
7b4319ba4SBarry Smith     Currently this allows for only one subdomain per processor.
8b4319ba4SBarry Smith */
9b4319ba4SBarry Smith 
10d0dbe9f7SStefano Zampini #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/
114f2d7cafSStefano Zampini #include <petsc/private/sfimpl.h>
12a72d46e8SStefano Zampini #include <petsc/private/vecimpl.h>
13e432b41dSStefano Zampini #include <petsc/private/hashseti.h>
1428f4e0baSStefano Zampini 
15f26d0771SStefano Zampini #define MATIS_MAX_ENTRIES_INSERTION 2048
16b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
17b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
188546b261SStefano Zampini static PetscErrorCode MatISSetUpScatters_Private(Mat);
19f26d0771SStefano Zampini 
209371c9d4SSatish Balay static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr) {
2175d48cdbSStefano Zampini   MatISPtAP ptap = (MatISPtAP)ptr;
2275d48cdbSStefano Zampini 
2375d48cdbSStefano Zampini   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP));
259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis0));
269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis1));
279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris0));
289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris1));
299566063dSJacob Faibussowitsch   PetscCall(PetscFree(ptap));
3075d48cdbSStefano Zampini   PetscFunctionReturn(0);
3175d48cdbSStefano Zampini }
3275d48cdbSStefano Zampini 
339371c9d4SSatish Balay static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C) {
3475d48cdbSStefano Zampini   MatISPtAP      ptap;
3575d48cdbSStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
3675d48cdbSStefano Zampini   Mat            lA, lC;
3775d48cdbSStefano Zampini   MatReuse       reuse;
3875d48cdbSStefano Zampini   IS             ris[2], cis[2];
3975d48cdbSStefano Zampini   PetscContainer c;
4075d48cdbSStefano Zampini   PetscInt       n;
4175d48cdbSStefano Zampini 
4275d48cdbSStefano Zampini   PetscFunctionBegin;
439566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c));
4428b400f6SJacob Faibussowitsch   PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information");
459566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(c, (void **)&ptap));
4675d48cdbSStefano Zampini   ris[0] = ptap->ris0;
4775d48cdbSStefano Zampini   ris[1] = ptap->ris1;
4875d48cdbSStefano Zampini   cis[0] = ptap->cis0;
4975d48cdbSStefano Zampini   cis[1] = ptap->cis1;
5075d48cdbSStefano Zampini   n      = ptap->ris1 ? 2 : 1;
5175d48cdbSStefano Zampini   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
529566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP));
5375d48cdbSStefano Zampini 
549566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
559566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(C, &lC));
5675d48cdbSStefano Zampini   if (ptap->ris1) { /* unsymmetric A mapping */
5775d48cdbSStefano Zampini     Mat lPt;
5875d48cdbSStefano Zampini 
599566063dSJacob Faibussowitsch     PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt));
609566063dSJacob Faibussowitsch     PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC));
61*48a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", (PetscObject)lPt));
629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lPt));
6375d48cdbSStefano Zampini   } else {
649566063dSJacob Faibussowitsch     PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC));
65*48a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0]));
6675d48cdbSStefano Zampini   }
6775d48cdbSStefano Zampini   if (reuse == MAT_INITIAL_MATRIX) {
689566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(C, lC));
699566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lC));
7075d48cdbSStefano Zampini   }
719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
729566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
7375d48cdbSStefano Zampini   PetscFunctionReturn(0);
7475d48cdbSStefano Zampini }
7575d48cdbSStefano Zampini 
769371c9d4SSatish Balay static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis) {
7775d48cdbSStefano Zampini   Mat             Po, Pd;
7875d48cdbSStefano Zampini   IS              zd, zo;
7975d48cdbSStefano Zampini   const PetscInt *garray;
8075d48cdbSStefano Zampini   PetscInt       *aux, i, bs;
8175d48cdbSStefano Zampini   PetscInt        dc, stc, oc, ctd, cto;
8275d48cdbSStefano Zampini   PetscBool       ismpiaij, ismpibaij, isseqaij, isseqbaij;
8375d48cdbSStefano Zampini   MPI_Comm        comm;
8475d48cdbSStefano Zampini 
8575d48cdbSStefano Zampini   PetscFunctionBegin;
8675d48cdbSStefano Zampini   PetscValidHeaderSpecific(PT, MAT_CLASSID, 1);
8775d48cdbSStefano Zampini   PetscValidPointer(cis, 2);
889566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)PT, &comm));
8975d48cdbSStefano Zampini   bs = 1;
909566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij));
919566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij));
929566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij));
939566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij));
9475d48cdbSStefano Zampini   if (isseqaij || isseqbaij) {
9575d48cdbSStefano Zampini     Pd     = PT;
9675d48cdbSStefano Zampini     Po     = NULL;
9775d48cdbSStefano Zampini     garray = NULL;
9875d48cdbSStefano Zampini   } else if (ismpiaij) {
999566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray));
10075d48cdbSStefano Zampini   } else if (ismpibaij) {
1019566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray));
1029566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(PT, &bs));
10398921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(PT))->type_name);
10475d48cdbSStefano Zampini 
10575d48cdbSStefano Zampini   /* identify any null columns in Pd or Po */
10622f7620eSStefano Zampini   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
10722f7620eSStefano Zampini      some of the columns are not really zero, but very close to */
10875d48cdbSStefano Zampini   zo = zd = NULL;
109*48a46eb9SPierre Jolivet   if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo));
1109566063dSJacob Faibussowitsch   PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd));
11175d48cdbSStefano Zampini 
1129566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(PT, NULL, &dc));
1139566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL));
1149566063dSJacob Faibussowitsch   if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc));
11575d48cdbSStefano Zampini   else oc = 0;
1169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
11775d48cdbSStefano Zampini   if (zd) {
11875d48cdbSStefano Zampini     const PetscInt *idxs;
11975d48cdbSStefano Zampini     PetscInt        nz;
12075d48cdbSStefano Zampini 
12175d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1229566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zd, bs));
1239566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zd, &nz));
1249566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zd, &idxs));
12575d48cdbSStefano Zampini     ctd = nz / bs;
12675d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs;
1279566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zd, &idxs));
12875d48cdbSStefano Zampini   } else {
12975d48cdbSStefano Zampini     ctd = dc / bs;
13075d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = i + stc / bs;
13175d48cdbSStefano Zampini   }
13275d48cdbSStefano Zampini   if (zo) {
13375d48cdbSStefano Zampini     const PetscInt *idxs;
13475d48cdbSStefano Zampini     PetscInt        nz;
13575d48cdbSStefano Zampini 
13675d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1379566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zo, bs));
1389566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zo, &nz));
1399566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zo, &idxs));
14075d48cdbSStefano Zampini     cto = nz / bs;
14175d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs];
1429566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zo, &idxs));
14375d48cdbSStefano Zampini   } else {
14475d48cdbSStefano Zampini     cto = oc / bs;
14575d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[i];
14675d48cdbSStefano Zampini   }
1479566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis));
1489566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zd));
1499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zo));
15075d48cdbSStefano Zampini   PetscFunctionReturn(0);
15175d48cdbSStefano Zampini }
15275d48cdbSStefano Zampini 
1539371c9d4SSatish Balay static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C) {
1548546b261SStefano Zampini   Mat                    PT, lA;
15575d48cdbSStefano Zampini   MatISPtAP              ptap;
15675d48cdbSStefano Zampini   ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g;
15775d48cdbSStefano Zampini   PetscContainer         c;
1588546b261SStefano Zampini   MatType                lmtype;
15975d48cdbSStefano Zampini   const PetscInt        *garray;
16075d48cdbSStefano Zampini   PetscInt               ibs, N, dc;
16175d48cdbSStefano Zampini   MPI_Comm               comm;
16275d48cdbSStefano Zampini 
16375d48cdbSStefano Zampini   PetscFunctionBegin;
1649566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1659566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATIS));
1669566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
1679566063dSJacob Faibussowitsch   PetscCall(MatGetType(lA, &lmtype));
1689566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(C, lmtype));
1699566063dSJacob Faibussowitsch   PetscCall(MatGetSize(P, NULL, &N));
1709566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(P, NULL, &dc));
1719566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, dc, dc, N, N));
17275d48cdbSStefano Zampini   /* Not sure about this
1739566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSizes(P,NULL,&ibs));
1749566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(*C,ibs));
17575d48cdbSStefano Zampini */
17675d48cdbSStefano Zampini 
1779566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ptap));
1789566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1799566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ptap));
1809566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyPtAP_Private));
1819566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c));
1829566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
18375d48cdbSStefano Zampini   ptap->fill = fill;
18475d48cdbSStefano Zampini 
1859566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g));
18675d48cdbSStefano Zampini 
1879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs));
1889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N));
1899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray));
1909566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0));
1919566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray));
19275d48cdbSStefano Zampini 
1939566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT));
1949566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0));
1959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g));
1969566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&PT));
19775d48cdbSStefano Zampini 
19875d48cdbSStefano Zampini   Crl2g = NULL;
19975d48cdbSStefano Zampini   if (rl2g != cl2g) { /* unsymmetric A mapping */
20075d48cdbSStefano Zampini     PetscBool same, lsame = PETSC_FALSE;
20175d48cdbSStefano Zampini     PetscInt  N1, ibs1;
20275d48cdbSStefano Zampini 
2039566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1));
2049566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1));
2059566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray));
2069566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1));
2079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray));
20875d48cdbSStefano Zampini     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
20975d48cdbSStefano Zampini       const PetscInt *i1, *i2;
21075d48cdbSStefano Zampini 
2119566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris0, &i1));
2129566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris1, &i2));
2139566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(i1, i2, N, &lsame));
21475d48cdbSStefano Zampini     }
2151c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lsame, &same, 1, MPIU_BOOL, MPI_LAND, comm));
21675d48cdbSStefano Zampini     if (same) {
2179566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ptap->ris1));
21875d48cdbSStefano Zampini     } else {
2199566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT));
2209566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1));
2219566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g));
2229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&PT));
22375d48cdbSStefano Zampini     }
22475d48cdbSStefano Zampini   }
22575d48cdbSStefano Zampini   /* Not sure about this
22675d48cdbSStefano Zampini   if (!Crl2g) {
2279566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(C,&ibs));
2289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs));
22975d48cdbSStefano Zampini   }
23075d48cdbSStefano Zampini */
2319566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g));
2329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g));
2339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g));
23475d48cdbSStefano Zampini 
2354222ddf1SHong Zhang   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
23675d48cdbSStefano Zampini   PetscFunctionReturn(0);
23775d48cdbSStefano Zampini }
23875d48cdbSStefano Zampini 
2394222ddf1SHong Zhang /* ----------------------------------------- */
2409371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C) {
2414222ddf1SHong Zhang   Mat_Product *product = C->product;
2424222ddf1SHong Zhang   Mat          A = product->A, P = product->B;
2434222ddf1SHong Zhang   PetscReal    fill = product->fill;
24475d48cdbSStefano Zampini 
24575d48cdbSStefano Zampini   PetscFunctionBegin;
2469566063dSJacob Faibussowitsch   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
2474222ddf1SHong Zhang   C->ops->productnumeric = MatProductNumeric_PtAP;
24875d48cdbSStefano Zampini   PetscFunctionReturn(0);
24975d48cdbSStefano Zampini }
25075d48cdbSStefano Zampini 
2519371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C) {
2524222ddf1SHong Zhang   PetscFunctionBegin;
2534222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
2544222ddf1SHong Zhang   PetscFunctionReturn(0);
2554222ddf1SHong Zhang }
2564222ddf1SHong Zhang 
2579371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C) {
2584222ddf1SHong Zhang   Mat_Product *product = C->product;
2594222ddf1SHong Zhang 
2604222ddf1SHong Zhang   PetscFunctionBegin;
261*48a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
2624222ddf1SHong Zhang   PetscFunctionReturn(0);
2634222ddf1SHong Zhang }
2644222ddf1SHong Zhang 
2654222ddf1SHong Zhang /* ----------------------------------------- */
2669371c9d4SSatish Balay static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr) {
2675b003df0Sstefano_zampini   MatISLocalFields lf = (MatISLocalFields)ptr;
2685b003df0Sstefano_zampini   PetscInt         i;
2695b003df0Sstefano_zampini 
270ab4d48faSStefano Zampini   PetscFunctionBegin;
271*48a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
272*48a46eb9SPierre Jolivet   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
2739566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lf->rf, lf->cf));
2749566063dSJacob Faibussowitsch   PetscCall(PetscFree(lf));
2755b003df0Sstefano_zampini   PetscFunctionReturn(0);
2765b003df0Sstefano_zampini }
277a72627d2SStefano Zampini 
2789371c9d4SSatish Balay static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) {
279c9225affSStefano Zampini   Mat B, lB;
280c9225affSStefano Zampini 
281c9225affSStefano Zampini   PetscFunctionBegin;
282c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
283c9225affSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
284c9225affSStefano Zampini     PetscInt               bs;
285c9225affSStefano Zampini     IS                     is;
286c9225affSStefano Zampini 
2879566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
2889566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
289c9225affSStefano Zampini     if (bs > 1) {
290c9225affSStefano Zampini       IS       is2;
291c9225affSStefano Zampini       PetscInt i, *aux;
292c9225affSStefano Zampini 
2939566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
2949566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
2959566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
2969566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
2979566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
298c9225affSStefano Zampini       is = is2;
299c9225affSStefano Zampini     }
3009566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3039566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
304c9225affSStefano Zampini     if (bs > 1) {
305c9225affSStefano Zampini       IS       is2;
306c9225affSStefano Zampini       PetscInt i, *aux;
307c9225affSStefano Zampini 
3089566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3109566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3119566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3129566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
313c9225affSStefano Zampini       is = is2;
314c9225affSStefano Zampini     }
3159566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3169566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3179566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3189566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
3199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3219566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
322c9225affSStefano Zampini     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
323c9225affSStefano Zampini   } else {
324c9225affSStefano Zampini     B = *newmat;
3259566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
326c9225affSStefano Zampini     lB = A;
327c9225affSStefano Zampini   }
3289566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lB));
3299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lB));
3309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
332*48a46eb9SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
333c9225affSStefano Zampini   PetscFunctionReturn(0);
334c9225affSStefano Zampini }
335c9225affSStefano Zampini 
3369371c9d4SSatish Balay static PetscErrorCode MatISScaleDisassembling_Private(Mat A) {
337c9225affSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(A->data);
338c9225affSStefano Zampini   PetscScalar    *aa;
339c9225affSStefano Zampini   const PetscInt *ii, *jj;
340c9225affSStefano Zampini   PetscInt        i, n, m;
341fabe8965SStefano Zampini   PetscInt       *ecount, **eneighs;
342c9225affSStefano Zampini   PetscBool       flg;
343c9225affSStefano Zampini 
344c9225affSStefano Zampini   PetscFunctionBegin;
3459566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
34608401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
3479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
34808401ef6SPierre Jolivet   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
3499566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
350c9225affSStefano Zampini   for (i = 0; i < n; i++) {
351fabe8965SStefano Zampini     if (ecount[i] > 1) {
352c9225affSStefano Zampini       PetscInt j;
353c9225affSStefano Zampini 
354c9225affSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
355c9225affSStefano Zampini         PetscInt  i2   = jj[j], p, p2;
356fabe8965SStefano Zampini         PetscReal scal = 0.0;
357c9225affSStefano Zampini 
358c9225affSStefano Zampini         for (p = 0; p < ecount[i]; p++) {
359c9225affSStefano Zampini           for (p2 = 0; p2 < ecount[i2]; p2++) {
3609371c9d4SSatish Balay             if (eneighs[i][p] == eneighs[i2][p2]) {
3619371c9d4SSatish Balay               scal += 1.0;
3629371c9d4SSatish Balay               break;
3639371c9d4SSatish Balay             }
364c9225affSStefano Zampini           }
365c9225affSStefano Zampini         }
366fabe8965SStefano Zampini         if (scal) aa[j] /= scal;
367c9225affSStefano Zampini       }
368c9225affSStefano Zampini     }
369c9225affSStefano Zampini   }
3709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
3719566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
3729566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
37308401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
374c9225affSStefano Zampini   PetscFunctionReturn(0);
375c9225affSStefano Zampini }
376c9225affSStefano Zampini 
3779371c9d4SSatish Balay typedef enum {
3789371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_NATURAL,
3799371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_MAT,
3809371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_ND
3819371c9d4SSatish Balay } MatISDisassemblel2gType;
382fabe8965SStefano Zampini 
3839371c9d4SSatish Balay static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g) {
384fabe8965SStefano Zampini   Mat                     Ad, Ao;
385fabe8965SStefano Zampini   IS                      is, ndmap, ndsub;
386c9225affSStefano Zampini   MPI_Comm                comm;
387fabe8965SStefano Zampini   const PetscInt         *garray, *ndmapi;
388fabe8965SStefano Zampini   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
389fabe8965SStefano Zampini   PetscBool               ismpiaij, ismpibaij;
390f4259b30SLisandro Dalcin   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
391fabe8965SStefano Zampini   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
392fabe8965SStefano Zampini   MatPartitioning         part;
393fabe8965SStefano Zampini   PetscSF                 sf;
39491d376acSStefano Zampini   PetscObject             dm;
395c9225affSStefano Zampini 
396c9225affSStefano Zampini   PetscFunctionBegin;
397d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
3989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-mat_is_disassemble_l2g_type", "Type of local-to-global mapping to be used for disassembling", "MatISDisassemblel2gType", MatISDisassemblel2gTypes, (PetscEnum)mode, (PetscEnum *)&mode, NULL));
399d0609cedSBarry Smith   PetscOptionsEnd();
400fabe8965SStefano Zampini   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
4019566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
402c9225affSStefano Zampini     PetscFunctionReturn(0);
403c9225affSStefano Zampini   }
4049566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4059566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
4069566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
4079566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
408fabe8965SStefano Zampini   switch (mode) {
409fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_ND:
4109566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(comm, &part));
4119566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(part, A));
4129566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
4139566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(part));
4149566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApplyND(part, &ndmap));
4159566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&part));
4169566063dSJacob Faibussowitsch     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
4179566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
4189566063dSJacob Faibussowitsch     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
4199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
420fabe8965SStefano Zampini 
421fabe8965SStefano Zampini     /* it may happen that a separator node is not properly shared */
4229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
4239566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &sf));
4249566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
4259566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
4269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
4279566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
4289566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4299566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4309566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
4319566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ndmap, &ndmapi));
432fabe8965SStefano Zampini     for (i = 0, cnt = 0; i < A->rmap->n; i++)
4339371c9d4SSatish Balay       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
434fabe8965SStefano Zampini 
4351c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
436fabe8965SStefano Zampini     if (i) { /* we detected isolated separator nodes */
437fabe8965SStefano Zampini       Mat                    A2, A3;
438fabe8965SStefano Zampini       IS                    *workis, is2;
439fabe8965SStefano Zampini       PetscScalar           *vals;
440fabe8965SStefano Zampini       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
441fabe8965SStefano Zampini       ISLocalToGlobalMapping ll2g;
442fabe8965SStefano Zampini       PetscBool              flg;
443fabe8965SStefano Zampini       const PetscInt        *ii, *jj;
444fabe8965SStefano Zampini 
445fabe8965SStefano Zampini       /* communicate global id of separators */
446d0609cedSBarry Smith       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
4479371c9d4SSatish Balay       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
448fabe8965SStefano Zampini 
4499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl, &lndmapi));
4509566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
451fabe8965SStefano Zampini 
452fabe8965SStefano Zampini       /* compute adjacency of isolated separators node */
4539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(gcnt, &workis));
454fabe8965SStefano Zampini       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
455*48a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
456fabe8965SStefano Zampini       }
457*48a46eb9SPierre Jolivet       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
458fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4599566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
4609566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
461fabe8965SStefano Zampini       }
462fabe8965SStefano Zampini 
463fabe8965SStefano Zampini       /* no communications since all the ISes correspond to locally owned rows */
4649566063dSJacob Faibussowitsch       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
465fabe8965SStefano Zampini 
466fabe8965SStefano Zampini       /* end communicate global id of separators */
4679566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
468fabe8965SStefano Zampini 
469fabe8965SStefano Zampini       /* communicate new layers : create a matrix and transpose it */
4709566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(dnz, A->rmap->n));
4719566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(onz, A->rmap->n));
472fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) {
473fabe8965SStefano Zampini         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
474fabe8965SStefano Zampini           const PetscInt *idxs;
475fabe8965SStefano Zampini           PetscInt        s;
476fabe8965SStefano Zampini 
4779566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(workis[j], &s));
4789566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
4799566063dSJacob Faibussowitsch           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
480fabe8965SStefano Zampini           j++;
481fabe8965SStefano Zampini         }
482fabe8965SStefano Zampini       }
48308401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
484fabe8965SStefano Zampini 
485fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4869566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
4879566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
488fabe8965SStefano Zampini       }
489fabe8965SStefano Zampini 
490fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
4919566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(j, &vals));
492fabe8965SStefano Zampini       for (i = 0; i < j; i++) vals[i] = 1.0;
493fabe8965SStefano Zampini 
4949566063dSJacob Faibussowitsch       PetscCall(MatCreate(comm, &A2));
4959566063dSJacob Faibussowitsch       PetscCall(MatSetType(A2, MATMPIAIJ));
4969566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
4979566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
4989566063dSJacob Faibussowitsch       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
499fabe8965SStefano Zampini       for (i = 0, j = 0; i < A2->rmap->n; i++) {
500fabe8965SStefano Zampini         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
501fabe8965SStefano Zampini         const PetscInt *idxs;
502fabe8965SStefano Zampini 
503fabe8965SStefano Zampini         if (s) {
5049566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5059566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
5069566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(workis[j], &idxs));
507fabe8965SStefano Zampini           j++;
508fabe8965SStefano Zampini         }
509fabe8965SStefano Zampini       }
51008401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
5119566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
5129566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
5139566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
5149566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
515fabe8965SStefano Zampini 
516fabe8965SStefano Zampini       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
517fabe8965SStefano Zampini       for (i = 0, j = 0; i < nl; i++)
518fabe8965SStefano Zampini         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
5199566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
5209566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
5219566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5229566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A2));
523fabe8965SStefano Zampini 
524fabe8965SStefano Zampini       /* extend local to global map to include connected isolated separators */
5259566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
52628b400f6SJacob Faibussowitsch       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
5279566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
5289566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
52928b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5309566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
5319566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
53228b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5339566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
5349566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
536fabe8965SStefano Zampini 
537fabe8965SStefano Zampini       /* add new nodes to the local-to-global map */
5389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
5399566063dSJacob Faibussowitsch       PetscCall(ISExpand(ndsub, is2, &is));
5409566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is2));
5419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5429566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
543fabe8965SStefano Zampini 
5449566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A3));
5459566063dSJacob Faibussowitsch       PetscCall(PetscFree(lndmapi));
546d0609cedSBarry Smith       MatPreallocateEnd(dnz, onz);
547*48a46eb9SPierre Jolivet       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
5489566063dSJacob Faibussowitsch       PetscCall(PetscFree(workis));
549fabe8965SStefano Zampini     }
5509566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
5519566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
5529566063dSJacob Faibussowitsch     PetscCall(PetscFree(ndmapc));
5539566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndmap));
5549566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndsub));
5559566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
5569566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-matis_nd_l2g_view"));
557fabe8965SStefano Zampini     break;
558fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
55991d376acSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)&dm));
56091d376acSStefano Zampini     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
56191d376acSStefano Zampini       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
56291d376acSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*l2g));
56391d376acSStefano Zampini       if (*l2g) PetscFunctionReturn(0);
56491d376acSStefano Zampini     }
565fabe8965SStefano Zampini     if (ismpiaij) {
5669566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
567fabe8965SStefano Zampini     } else if (ismpibaij) {
5689566063dSJacob Faibussowitsch       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
56998921bdaSJacob Faibussowitsch     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
570c9225affSStefano Zampini     if (A->rmap->n) {
571fabe8965SStefano Zampini       PetscInt dc, oc, stc, *aux;
572c9225affSStefano Zampini 
573ebf8cefbSJunchao Zhang       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
5749566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
575d0dbe9f7SStefano Zampini       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
5769566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
5779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
578c9225affSStefano Zampini       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
579ebf8cefbSJunchao Zhang       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
5809566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
581c9225affSStefano Zampini     } else {
5829566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
583c9225affSStefano Zampini     }
5849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
586fabe8965SStefano Zampini     break;
5879371c9d4SSatish Balay   default: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
588c9225affSStefano Zampini   }
589c9225affSStefano Zampini   PetscFunctionReturn(0);
590c9225affSStefano Zampini }
591c9225affSStefano Zampini 
5929371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) {
593c9225affSStefano Zampini   Mat                    lA, Ad, Ao, B = NULL;
5946989cf23SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
5956989cf23SStefano Zampini   IS                     is;
5966989cf23SStefano Zampini   MPI_Comm               comm;
5976989cf23SStefano Zampini   void                  *ptrs[2];
5986989cf23SStefano Zampini   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
599c9225affSStefano Zampini   const PetscInt        *garray;
6006989cf23SStefano Zampini   PetscScalar           *dd, *od, *aa, *data;
601c9225affSStefano Zampini   const PetscInt        *di, *dj, *oi, *oj;
602c9225affSStefano Zampini   const PetscInt        *odi, *odj, *ooi, *ooj;
6036989cf23SStefano Zampini   PetscInt              *aux, *ii, *jj;
604c9225affSStefano Zampini   PetscInt               bs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
605c9225affSStefano Zampini   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE;
606c9225affSStefano Zampini   PetscMPIInt            size;
6076989cf23SStefano Zampini 
608ab4d48faSStefano Zampini   PetscFunctionBegin;
6099566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
6109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
611c9225affSStefano Zampini   if (size == 1) {
6129566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
613c9225affSStefano Zampini     PetscFunctionReturn(0);
614c9225affSStefano Zampini   }
615c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
6169566063dSJacob Faibussowitsch     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
6179566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
6189566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
6199566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
6209566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
6219566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6229566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSize(B, bs));
6239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
624c9225affSStefano Zampini     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
625c9225affSStefano Zampini     reuse = MAT_REUSE_MATRIX;
626c9225affSStefano Zampini   }
627c9225affSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
628c9225affSStefano Zampini     Mat            *newlA, lA;
629c9225affSStefano Zampini     IS              rows, cols;
630c9225affSStefano Zampini     const PetscInt *ridx, *cidx;
631c9225affSStefano Zampini     PetscInt        rbs, cbs, nr, nc;
632c9225affSStefano Zampini 
633c9225affSStefano Zampini     if (!B) B = *newmat;
6349566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
6359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
6369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
6379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
6389566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
6399566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
6409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
6419566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
642c9225affSStefano Zampini     if (rl2g != cl2g) {
6439566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
644c9225affSStefano Zampini     } else {
6459566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)rows));
646c9225affSStefano Zampini       cols = rows;
647c9225affSStefano Zampini     }
6489566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(B, &lA));
6499566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
6509566063dSJacob Faibussowitsch     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
6519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
6529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
6539566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rows));
6549566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cols));
655c9225affSStefano Zampini     if (!lA->preallocated) { /* first time */
6569566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
6579566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(B, lA));
6589566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)lA));
659c9225affSStefano Zampini     }
6609566063dSJacob Faibussowitsch     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
6619566063dSJacob Faibussowitsch     PetscCall(MatDestroySubMatrices(1, &newlA));
6629566063dSJacob Faibussowitsch     PetscCall(MatISScaleDisassembling_Private(B));
6639566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
6649566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
6659566063dSJacob Faibussowitsch     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
666c9225affSStefano Zampini     else *newmat = B;
667c9225affSStefano Zampini     PetscFunctionReturn(0);
668c9225affSStefano Zampini   }
669c9225affSStefano Zampini   /* rectangular case, just compress out the column space */
6709566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
6719566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
672c9225affSStefano Zampini   if (ismpiaij) {
673c9225affSStefano Zampini     bs = 1;
6749566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
675c9225affSStefano Zampini   } else if (ismpibaij) {
6769566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6779566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
6789566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
6799566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
68098921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
6819566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ad, &dd));
6829566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ao, &od));
68328b400f6SJacob Faibussowitsch   PetscCheck(garray, comm, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
6846989cf23SStefano Zampini 
6856989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
6869566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
6879566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
6889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &dr, &dc));
6899566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
6909566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
69128b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
6929566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
69328b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
694c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
695c9225affSStefano Zampini   /* store original pointers to be restored later */
6969371c9d4SSatish Balay   odi = di;
6979371c9d4SSatish Balay   odj = dj;
6989371c9d4SSatish Balay   ooi = oi;
6999371c9d4SSatish Balay   ooj = oj;
7006989cf23SStefano Zampini 
7016989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
7029566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(comm, dr / bs, str / bs, 1, &is));
703c9225affSStefano Zampini   if (bs > 1) {
704c9225affSStefano Zampini     IS is2;
705c9225affSStefano Zampini 
7069566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7079566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
7089566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, i, aux, PETSC_COPY_VALUES, &is2));
7099566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
711c9225affSStefano Zampini     is = is2;
712c9225affSStefano Zampini   }
7139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
715e363d98aSStefano Zampini   if (dr) {
7169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
717c9225affSStefano Zampini     for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
718c9225affSStefano Zampini     for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = garray[i];
7199566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
720e363d98aSStefano Zampini     lc = dc + oc;
721e363d98aSStefano Zampini   } else {
7229566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, 0, NULL, PETSC_OWN_POINTER, &is));
723e363d98aSStefano Zampini     lc = 0;
724e363d98aSStefano Zampini   }
7259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7276989cf23SStefano Zampini 
7286989cf23SStefano Zampini   /* create MATIS object */
7299566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7309566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7319566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
7329566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, bs));
7339566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7366989cf23SStefano Zampini 
7376989cf23SStefano Zampini   /* merge local matrices */
7389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7406989cf23SStefano Zampini   ii  = aux;
7416989cf23SStefano Zampini   jj  = aux + dr + 1;
7426989cf23SStefano Zampini   aa  = data;
7436989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7449371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7459371c9d4SSatish Balay     for (; jd < *di; jd++) {
7469371c9d4SSatish Balay       *jj++ = *dj++;
7479371c9d4SSatish Balay       *aa++ = *dd++;
7489371c9d4SSatish Balay     }
7499371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7509371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7519371c9d4SSatish Balay       *aa++ = *od++;
7529371c9d4SSatish Balay     }
7536989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7546989cf23SStefano Zampini   }
7556989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
756c9225affSStefano Zampini 
7579566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
75828b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7599566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
76028b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7619566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7629566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
763c9225affSStefano Zampini 
7646989cf23SStefano Zampini   ii = aux;
7656989cf23SStefano Zampini   jj = aux + dr + 1;
7666989cf23SStefano Zampini   aa = data;
7679566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
7686989cf23SStefano Zampini 
7696989cf23SStefano Zampini   /* create containers to destroy the data */
7706989cf23SStefano Zampini   ptrs[0] = aux;
7716989cf23SStefano Zampini   ptrs[1] = data;
7726989cf23SStefano Zampini   for (i = 0; i < 2; i++) {
7736989cf23SStefano Zampini     PetscContainer c;
7746989cf23SStefano Zampini 
7759566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
7769566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, ptrs[i]));
7779566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
7789566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)lA, names[i], (PetscObject)c));
7799566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
7806989cf23SStefano Zampini   }
781c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7829566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7839566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
784c9225affSStefano Zampini   }
7856989cf23SStefano Zampini 
7866989cf23SStefano Zampini   /* finalize matrix */
7879566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
7889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
7899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
7909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
791c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
7929566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
793c9225affSStefano Zampini   } else *newmat = B;
7946989cf23SStefano Zampini   PetscFunctionReturn(0);
7956989cf23SStefano Zampini }
7966989cf23SStefano Zampini 
7979371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) {
7985e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
7995e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8005e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8015e3038f0Sstefano_zampini   MPI_Comm               comm;
8025b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8035b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8049e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8055e3038f0Sstefano_zampini 
806ab4d48faSStefano Zampini   PetscFunctionBegin;
8079566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8085e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8095e3038f0Sstefano_zampini   rnest  = NULL;
8105e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8115e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8125e3038f0Sstefano_zampini 
8139566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
81428b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)(*newmat))->type_name);
8159566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8169566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8175e3038f0Sstefano_zampini     if (isnest) {
8189566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8195e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8205e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8215e3038f0Sstefano_zampini     }
8225e3038f0Sstefano_zampini   }
8239566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8249566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8259566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8269566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8275e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8285e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8295e3038f0Sstefano_zampini       PetscBool ismatis;
8309e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8315e3038f0Sstefano_zampini 
8325e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8335e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8345e3038f0Sstefano_zampini 
8355e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
8369566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEMAT, &istrans[ij]));
8379e7b2b25Sstefano_zampini       if (istrans[ij]) {
8389e7b2b25Sstefano_zampini         Mat T, lT;
8399566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8409566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
84128b400f6SJacob Faibussowitsch         PetscCheck(ismatis, comm, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") (transposed) is not of type MATIS", i, j);
8429566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8439566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8449e7b2b25Sstefano_zampini       } else {
8459566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
84628b400f6SJacob Faibussowitsch         PetscCheck(ismatis, comm, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") is not of type MATIS", i, j);
8479566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8489e7b2b25Sstefano_zampini       }
8495e3038f0Sstefano_zampini 
8505e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8519566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8529566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8535e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
854aed4548fSBarry Smith       PetscCheck(!lr[i] || l1 == lr[i], PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, lr[i], l1);
855aed4548fSBarry Smith       PetscCheck(!lc[j] || l2 == lc[j], PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, lc[j], l2);
8565e3038f0Sstefano_zampini       lr[i] = l1;
8575e3038f0Sstefano_zampini       lc[j] = l2;
8585e3038f0Sstefano_zampini 
8595e3038f0Sstefano_zampini       /* check compatibilty for local matrix reusage */
8605e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8615e3038f0Sstefano_zampini     }
8625e3038f0Sstefano_zampini   }
8635e3038f0Sstefano_zampini 
86476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8655e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8665e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8675e3038f0Sstefano_zampini       rl2g = NULL;
8685e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8695e3038f0Sstefano_zampini         PetscInt n1, n2;
8705e3038f0Sstefano_zampini 
8715e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8729e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8739e7b2b25Sstefano_zampini           Mat T;
8749e7b2b25Sstefano_zampini 
8759566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8769566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8779e7b2b25Sstefano_zampini         } else {
8789566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8799e7b2b25Sstefano_zampini         }
8809566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8815e3038f0Sstefano_zampini         if (!n1) continue;
8825e3038f0Sstefano_zampini         if (!rl2g) {
8835e3038f0Sstefano_zampini           rl2g = cl2g;
8845e3038f0Sstefano_zampini         } else {
8855e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
8865e3038f0Sstefano_zampini           PetscBool       same;
8875e3038f0Sstefano_zampini 
8889566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
88908401ef6SPierre Jolivet           PetscCheck(n1 == n2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, n1, n2);
8909566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
8919566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
8929566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
8939566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
8949566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
89528b400f6SJacob Faibussowitsch           PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap", i, j);
8965e3038f0Sstefano_zampini         }
8975e3038f0Sstefano_zampini       }
8985e3038f0Sstefano_zampini     }
8995e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9005e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9015e3038f0Sstefano_zampini       rl2g = NULL;
9025e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9035e3038f0Sstefano_zampini         PetscInt n1, n2;
9045e3038f0Sstefano_zampini 
9055e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9069e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9079e7b2b25Sstefano_zampini           Mat T;
9089e7b2b25Sstefano_zampini 
9099566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9109566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9119e7b2b25Sstefano_zampini         } else {
9129566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9139e7b2b25Sstefano_zampini         }
9149566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9155e3038f0Sstefano_zampini         if (!n1) continue;
9165e3038f0Sstefano_zampini         if (!rl2g) {
9175e3038f0Sstefano_zampini           rl2g = cl2g;
9185e3038f0Sstefano_zampini         } else {
9195e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9205e3038f0Sstefano_zampini           PetscBool       same;
9215e3038f0Sstefano_zampini 
9229566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
92308401ef6SPierre Jolivet           PetscCheck(n1 == n2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT, j, i, n1, n2);
9249566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9259566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9269566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9279566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9289566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
92928b400f6SJacob Faibussowitsch           PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap", j, i);
9305e3038f0Sstefano_zampini         }
9315e3038f0Sstefano_zampini       }
9325e3038f0Sstefano_zampini     }
93376bd3646SJed Brown   }
9345e3038f0Sstefano_zampini 
9355e3038f0Sstefano_zampini   B = NULL;
9365e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9375b003df0Sstefano_zampini     PetscInt stl;
9385b003df0Sstefano_zampini 
9395e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9405e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9425b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9435e3038f0Sstefano_zampini       Mat             usedmat;
9445e3038f0Sstefano_zampini       Mat_IS         *matis;
9455e3038f0Sstefano_zampini       const PetscInt *idxs;
9465e3038f0Sstefano_zampini 
9475e3038f0Sstefano_zampini       /* local IS for local NEST */
9489566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9495e3038f0Sstefano_zampini 
9505e3038f0Sstefano_zampini       /* l2gmap */
9515e3038f0Sstefano_zampini       j       = 0;
9525e3038f0Sstefano_zampini       usedmat = nest[i][j];
9539e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
95428b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9559e7b2b25Sstefano_zampini 
9569e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9579e7b2b25Sstefano_zampini         Mat T;
9589566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9599e7b2b25Sstefano_zampini         usedmat = T;
9609e7b2b25Sstefano_zampini       }
9615e3038f0Sstefano_zampini       matis = (Mat_IS *)(usedmat->data);
9629566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9639e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9649566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9659566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9669e7b2b25Sstefano_zampini       } else {
9679566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9689566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9699e7b2b25Sstefano_zampini       }
9709566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9715e3038f0Sstefano_zampini       stl += lr[i];
9725e3038f0Sstefano_zampini     }
9739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9745e3038f0Sstefano_zampini 
9755e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9765e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9785b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9795e3038f0Sstefano_zampini       Mat             usedmat;
9805e3038f0Sstefano_zampini       Mat_IS         *matis;
9815e3038f0Sstefano_zampini       const PetscInt *idxs;
9825e3038f0Sstefano_zampini 
9835e3038f0Sstefano_zampini       /* local IS for local NEST */
9849566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
9855e3038f0Sstefano_zampini 
9865e3038f0Sstefano_zampini       /* l2gmap */
9875e3038f0Sstefano_zampini       j       = 0;
9885e3038f0Sstefano_zampini       usedmat = nest[j][i];
9899e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
99028b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
9919e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
9929e7b2b25Sstefano_zampini         Mat T;
9939566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9949e7b2b25Sstefano_zampini         usedmat = T;
9959e7b2b25Sstefano_zampini       }
9965e3038f0Sstefano_zampini       matis = (Mat_IS *)(usedmat->data);
9979566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
9989e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
9999566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10009566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10019e7b2b25Sstefano_zampini       } else {
10029566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10039566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10049e7b2b25Sstefano_zampini       }
10059566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10065e3038f0Sstefano_zampini       stl += lc[i];
10075e3038f0Sstefano_zampini     }
10089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10095e3038f0Sstefano_zampini 
10105e3038f0Sstefano_zampini     /* Create MATIS */
10119566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10129566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10139566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10149566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10159566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10169566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10178546b261SStefano Zampini     { /* hack : avoid setup of scatters */
10188546b261SStefano Zampini       Mat_IS *matis     = (Mat_IS *)(B->data);
10198546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10208546b261SStefano Zampini     }
10219566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10249566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10259566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10269e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
1027*48a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10289e7b2b25Sstefano_zampini     }
10299566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10309566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10318546b261SStefano Zampini     { /* hack : setup of scatters done here */
10328546b261SStefano Zampini       Mat_IS *matis = (Mat_IS *)(B->data);
10338546b261SStefano Zampini 
10348546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10359566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10368546b261SStefano Zampini     }
10379566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10389566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10395e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10409566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10415e3038f0Sstefano_zampini     } else {
10425e3038f0Sstefano_zampini       *newmat = B;
10435e3038f0Sstefano_zampini     }
10445e3038f0Sstefano_zampini   } else {
10455e3038f0Sstefano_zampini     if (lreuse) {
10469566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10475e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10485e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10495e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10509566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
1051*48a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10525e3038f0Sstefano_zampini           }
10535e3038f0Sstefano_zampini         }
10545e3038f0Sstefano_zampini       }
10555e3038f0Sstefano_zampini     } else {
10565b003df0Sstefano_zampini       PetscInt stl;
10575b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10589566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10595b003df0Sstefano_zampini         stl += lr[i];
10605e3038f0Sstefano_zampini       }
10615b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10629566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10635b003df0Sstefano_zampini         stl += lc[i];
10645e3038f0Sstefano_zampini       }
10659566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1066ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
1067*48a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1068ab4d48faSStefano Zampini       }
10699566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10709566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10715e3038f0Sstefano_zampini     }
10729566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10739566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10745e3038f0Sstefano_zampini   }
10755e3038f0Sstefano_zampini 
10765b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10775b003df0Sstefano_zampini   convert = PETSC_FALSE;
10789566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-matis_convert_local_nest", &convert, NULL));
10795b003df0Sstefano_zampini   if (convert) {
10805b003df0Sstefano_zampini     Mat              M;
10815b003df0Sstefano_zampini     MatISLocalFields lf;
10825b003df0Sstefano_zampini     PetscContainer   c;
10835b003df0Sstefano_zampini 
10849566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
10859566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
10869566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
10879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
10885b003df0Sstefano_zampini 
10895b003df0Sstefano_zampini     /* attach local fields to the matrix */
10909566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
10919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
10925b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
10935b003df0Sstefano_zampini       PetscInt n, st;
10945b003df0Sstefano_zampini 
10959566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
10969566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
10979566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
10985b003df0Sstefano_zampini     }
10995b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11005b003df0Sstefano_zampini       PetscInt n, st;
11015b003df0Sstefano_zampini 
11029566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11039566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11049566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11055b003df0Sstefano_zampini     }
11065b003df0Sstefano_zampini     lf->nr = nr;
11075b003df0Sstefano_zampini     lf->nc = nc;
11089566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)), &c));
11099566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, lf));
11109566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyFields_Private));
11119566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)(*newmat), "_convert_nest_lfields", (PetscObject)c));
11129566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
11135b003df0Sstefano_zampini   }
11145b003df0Sstefano_zampini 
11155e3038f0Sstefano_zampini   /* Free workspace */
1116*48a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
1117*48a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11189566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11205e3038f0Sstefano_zampini   PetscFunctionReturn(0);
11215e3038f0Sstefano_zampini }
11225e3038f0Sstefano_zampini 
11239371c9d4SSatish Balay static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r) {
1124ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1125ad219c80Sstefano_zampini   Vec                ll, rr;
1126ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1127ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1128ad219c80Sstefano_zampini 
1129ad219c80Sstefano_zampini   PetscFunctionBegin;
1130ad219c80Sstefano_zampini   if (l) {
1131ad219c80Sstefano_zampini     ll = matis->y;
11329566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11339566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11349566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1135ad219c80Sstefano_zampini   } else {
1136ad219c80Sstefano_zampini     ll = NULL;
1137ad219c80Sstefano_zampini   }
1138ad219c80Sstefano_zampini   if (r) {
1139ad219c80Sstefano_zampini     rr = matis->x;
11409566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11419566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11429566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1143ad219c80Sstefano_zampini   } else {
1144ad219c80Sstefano_zampini     rr = NULL;
1145ad219c80Sstefano_zampini   }
1146ad219c80Sstefano_zampini   if (ll) {
11479566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11489566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11499566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1150ad219c80Sstefano_zampini   }
1151ad219c80Sstefano_zampini   if (rr) {
11529566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11539566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11549566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1155ad219c80Sstefano_zampini   }
11569566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
1157ad219c80Sstefano_zampini   PetscFunctionReturn(0);
1158ad219c80Sstefano_zampini }
1159ad219c80Sstefano_zampini 
11609371c9d4SSatish Balay static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo) {
11617fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11627fa8f2d3SStefano Zampini   MatInfo        info;
11633966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11647fa8f2d3SStefano Zampini   PetscInt       bs;
11657fa8f2d3SStefano Zampini 
11667fa8f2d3SStefano Zampini   PetscFunctionBegin;
11679566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1168a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11699566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11707fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11717fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11727fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11737fa8f2d3SStefano Zampini     isend[3] = info.memory;
11747fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1175a2ccb5f9Sstefano_zampini   } else {
1176a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1177a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1178a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1179a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1180a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1181a2ccb5f9Sstefano_zampini   }
1182314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
11837fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
11847fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
11857fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
11867fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
11877fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
11887fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1189314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
11907fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
11911c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
11927fa8f2d3SStefano Zampini 
11937fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
11947fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
11957fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
11967fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
11977fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1198314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
11997fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
12001c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12017fa8f2d3SStefano Zampini 
12027fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12037fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12047fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12057fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12067fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12077fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12087fa8f2d3SStefano Zampini   }
12097fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12107fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12117fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12127fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12135e3038f0Sstefano_zampini   PetscFunctionReturn(0);
12145e3038f0Sstefano_zampini }
12155e3038f0Sstefano_zampini 
12169371c9d4SSatish Balay static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B) {
1217d7f69cd0SStefano Zampini   Mat C, lC, lA;
1218d7f69cd0SStefano Zampini 
1219d7f69cd0SStefano Zampini   PetscFunctionBegin;
12207fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1221cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1222cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12239566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12249566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
12259566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
12269566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12279566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12289566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1229e432b41dSStefano Zampini   } else C = *B;
1230d7f69cd0SStefano Zampini 
1231d7f69cd0SStefano Zampini   /* perform local transposition */
12329566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12339566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12349566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12359566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1237d7f69cd0SStefano Zampini 
1238cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1239d7f69cd0SStefano Zampini     *B = C;
1240d7f69cd0SStefano Zampini   } else {
12419566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1242d7f69cd0SStefano Zampini   }
12439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1245d7f69cd0SStefano Zampini   PetscFunctionReturn(0);
1246d7f69cd0SStefano Zampini }
1247d7f69cd0SStefano Zampini 
12489371c9d4SSatish Balay static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode) {
12493fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12503fd1c9e7SStefano Zampini 
12513fd1c9e7SStefano Zampini   PetscFunctionBegin;
12524b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12539566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12549566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12553fd1c9e7SStefano Zampini   }
12569566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12579566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12583fd1c9e7SStefano Zampini   PetscFunctionReturn(0);
12593fd1c9e7SStefano Zampini }
12603fd1c9e7SStefano Zampini 
12619371c9d4SSatish Balay static PetscErrorCode MatShift_IS(Mat A, PetscScalar a) {
12624b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12633fd1c9e7SStefano Zampini 
12643fd1c9e7SStefano Zampini   PetscFunctionBegin;
12659566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12669566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12673fd1c9e7SStefano Zampini   PetscFunctionReturn(0);
12683fd1c9e7SStefano Zampini }
12693fd1c9e7SStefano Zampini 
12709371c9d4SSatish Balay static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
1271f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1272f26d0771SStefano Zampini 
1273f26d0771SStefano Zampini   PetscFunctionBegin;
1274aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
12759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
12769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
12779566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1278f26d0771SStefano Zampini   PetscFunctionReturn(0);
1279f26d0771SStefano Zampini }
1280f26d0771SStefano Zampini 
12819371c9d4SSatish Balay static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
1282f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1283f26d0771SStefano Zampini 
1284f26d0771SStefano Zampini   PetscFunctionBegin;
1285aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column block indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
12869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
12879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
12889566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1289f26d0771SStefano Zampini   PetscFunctionReturn(0);
1290f26d0771SStefano Zampini }
1291f26d0771SStefano Zampini 
12929371c9d4SSatish Balay static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat) {
1293a8116848SStefano Zampini   Mat             locmat, newlocmat;
1294a8116848SStefano Zampini   Mat_IS         *newmatis;
1295a8116848SStefano Zampini   const PetscInt *idxs;
1296a8116848SStefano Zampini   PetscInt        i, m, n;
1297a8116848SStefano Zampini 
1298a8116848SStefano Zampini   PetscFunctionBegin;
1299a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1300a8116848SStefano Zampini     PetscBool ismatis;
1301a8116848SStefano Zampini 
13029566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
130328b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1304a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
130528b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
130628b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1307a8116848SStefano Zampini   }
1308a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
130976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
131076bd3646SJed Brown     Vec                rtest, ltest;
131176bd3646SJed Brown     const PetscScalar *array;
131276bd3646SJed Brown 
13139566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13149566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13159566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
1316*48a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13179566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13189566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13199566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13209566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13219566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1322aed4548fSBarry Smith     for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Irow may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i]));
13239566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13249566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13259566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13269566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
1327*48a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13289566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13299566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13309566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13319566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13329566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1333aed4548fSBarry Smith     for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Icol may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i]));
13349566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13359566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13379566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
133876bd3646SJed Brown   }
1339a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1340a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1341a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1342a8116848SStefano Zampini     IS                     is;
1343a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1344306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
134594342113SStefano Zampini     PetscBool              cong;
1346a8116848SStefano Zampini     MPI_Comm               comm;
1347a8116848SStefano Zampini 
13489566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13499566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13509566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13519566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1352306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1353306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13549566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13559566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13569566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13579566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13589566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13599566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1360a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13629566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13639566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13649566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1365a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13669566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
13679566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
13689566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13699566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13709371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
13719371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
13729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
13739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
13743d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1375a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1376a8116848SStefano Zampini         lidxs[newloc]      = i;
1377a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1378a8116848SStefano Zampini       }
13799566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
13809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
13819566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
13829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1383a8116848SStefano Zampini     /* local is to extract local submatrix */
1384a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
13859566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
13869566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
138794342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
13889566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
13899566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1390a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1391a8116848SStefano Zampini     } else {
1392a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1393a8116848SStefano Zampini 
1394a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
13959566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
13969566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
13979566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
13989566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1399a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14009566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14019566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14029566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14039566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14049371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14059371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14079566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14083d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1409a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1410a8116848SStefano Zampini           lidxs[newloc]      = i;
1411a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1412a8116848SStefano Zampini         }
14139566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14149566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14159566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14169566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1417a8116848SStefano Zampini       /* local is to extract local submatrix */
14189566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14199566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14209566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1421a8116848SStefano Zampini     }
14229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1423a8116848SStefano Zampini   } else {
14249566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1425a8116848SStefano Zampini   }
14269566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1427a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14289566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1429a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14309566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14319566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1432a8116848SStefano Zampini   }
14339566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1435a8116848SStefano Zampini   PetscFunctionReturn(0);
1436a8116848SStefano Zampini }
1437a8116848SStefano Zampini 
14389371c9d4SSatish Balay static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str) {
14392b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14402b404112SStefano Zampini   PetscBool ismatis;
14412b404112SStefano Zampini 
14422b404112SStefano Zampini   PetscFunctionBegin;
14439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
144428b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14452b404112SStefano Zampini   b = (Mat_IS *)B->data;
14469566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14479566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14482b404112SStefano Zampini   PetscFunctionReturn(0);
14492b404112SStefano Zampini }
14502b404112SStefano Zampini 
14519371c9d4SSatish Balay static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d) {
1452527b2640SStefano Zampini   Vec                v;
1453527b2640SStefano Zampini   const PetscScalar *array;
1454527b2640SStefano Zampini   PetscInt           i, n;
14556bd84002SStefano Zampini 
14566bd84002SStefano Zampini   PetscFunctionBegin;
1457527b2640SStefano Zampini   *missing = PETSC_FALSE;
14589566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14599566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14609566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14619566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14629371c9d4SSatish Balay   for (i = 0; i < n; i++)
14639371c9d4SSatish Balay     if (array[i] == 0.) break;
14649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
14659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1466527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1467527b2640SStefano Zampini   if (d) {
1468527b2640SStefano Zampini     *d = -1;
1469527b2640SStefano Zampini     if (*missing) {
1470527b2640SStefano Zampini       PetscInt rstart;
14719566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1472527b2640SStefano Zampini       *d = i + rstart;
1473527b2640SStefano Zampini     }
1474527b2640SStefano Zampini   }
14756bd84002SStefano Zampini   PetscFunctionReturn(0);
14766bd84002SStefano Zampini }
14776bd84002SStefano Zampini 
14789371c9d4SSatish Balay static PetscErrorCode MatISSetUpSF_IS(Mat B) {
147928f4e0baSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(B->data);
148028f4e0baSStefano Zampini   const PetscInt *gidxs;
14814f2d7cafSStefano Zampini   PetscInt        nleaves;
148228f4e0baSStefano Zampini 
148328f4e0baSStefano Zampini   PetscFunctionBegin;
14844f2d7cafSStefano Zampini   if (matis->sf) PetscFunctionReturn(0);
14859566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
14869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
14879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
14889566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
14899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
14909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1491e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
14929566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
14939566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
14949566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
14959566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
14969566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
14979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1498a8116848SStefano Zampini   } else {
1499a8116848SStefano Zampini     matis->csf          = matis->sf;
1500a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1501a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1502a8116848SStefano Zampini   }
150328f4e0baSStefano Zampini   PetscFunctionReturn(0);
150428f4e0baSStefano Zampini }
15052e1947a5SStefano Zampini 
1506eb82efa4SStefano Zampini /*@
150775d48cdbSStefano Zampini    MatISStoreL2L - Store local-to-local operators during the Galerkin process of MatPtAP.
150875d48cdbSStefano Zampini 
1509d083f849SBarry Smith    Collective
151075d48cdbSStefano Zampini 
151175d48cdbSStefano Zampini    Input Parameters:
151275d48cdbSStefano Zampini +  A - the matrix
151375d48cdbSStefano Zampini -  store - the boolean flag
151475d48cdbSStefano Zampini 
151575d48cdbSStefano Zampini    Level: advanced
151675d48cdbSStefano Zampini 
151775d48cdbSStefano Zampini    Notes:
151875d48cdbSStefano Zampini 
1519db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
152075d48cdbSStefano Zampini @*/
15219371c9d4SSatish Balay PetscErrorCode MatISStoreL2L(Mat A, PetscBool store) {
152275d48cdbSStefano Zampini   PetscFunctionBegin;
152375d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
152475d48cdbSStefano Zampini   PetscValidType(A, 1);
152575d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1526cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
152775d48cdbSStefano Zampini   PetscFunctionReturn(0);
152875d48cdbSStefano Zampini }
152975d48cdbSStefano Zampini 
15309371c9d4SSatish Balay static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store) {
153175d48cdbSStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
153275d48cdbSStefano Zampini 
153375d48cdbSStefano Zampini   PetscFunctionBegin;
153475d48cdbSStefano Zampini   matis->storel2l = store;
1535*48a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
153675d48cdbSStefano Zampini   PetscFunctionReturn(0);
153775d48cdbSStefano Zampini }
153875d48cdbSStefano Zampini 
153975d48cdbSStefano Zampini /*@
1540f03112d0SStefano Zampini    MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1541f03112d0SStefano Zampini 
1542d083f849SBarry Smith    Collective
1543f03112d0SStefano Zampini 
1544f03112d0SStefano Zampini    Input Parameters:
1545f03112d0SStefano Zampini +  A - the matrix
1546f03112d0SStefano Zampini -  fix - the boolean flag
1547f03112d0SStefano Zampini 
1548f03112d0SStefano Zampini    Level: advanced
1549f03112d0SStefano Zampini 
1550f03112d0SStefano Zampini    Notes: When fix is true, new local matrices and l2g maps are generated during the final assembly process.
1551f03112d0SStefano Zampini 
1552db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1553f03112d0SStefano Zampini @*/
15549371c9d4SSatish Balay PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix) {
1555f03112d0SStefano Zampini   PetscFunctionBegin;
1556f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1557f03112d0SStefano Zampini   PetscValidType(A, 1);
1558f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1559cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
1560f03112d0SStefano Zampini   PetscFunctionReturn(0);
1561f03112d0SStefano Zampini }
1562f03112d0SStefano Zampini 
15639371c9d4SSatish Balay static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix) {
1564f03112d0SStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
1565f03112d0SStefano Zampini 
1566f03112d0SStefano Zampini   PetscFunctionBegin;
1567f03112d0SStefano Zampini   matis->locempty = fix;
1568f03112d0SStefano Zampini   PetscFunctionReturn(0);
1569f03112d0SStefano Zampini }
1570f03112d0SStefano Zampini 
1571f03112d0SStefano Zampini /*@
1572a88811baSStefano Zampini    MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.
1573a88811baSStefano Zampini 
1574d083f849SBarry Smith    Collective
1575a88811baSStefano Zampini 
1576a88811baSStefano Zampini    Input Parameters:
1577a88811baSStefano Zampini +  B - the matrix
1578a88811baSStefano Zampini .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1579a88811baSStefano Zampini            (same value is used for all local rows)
1580a88811baSStefano Zampini .  d_nnz - array containing the number of nonzeros in the various rows of the
1581a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
1582a88811baSStefano Zampini            or NULL, if d_nz is used to specify the nonzero structure.
1583a88811baSStefano Zampini            The size of this array is equal to the number of local rows, i.e 'm'.
1584a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1585a88811baSStefano Zampini            the diagonal entry even if it is zero.
1586a88811baSStefano Zampini .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1587a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1588a88811baSStefano Zampini -  o_nnz - array containing the number of nonzeros in the various rows of the
1589a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
1590a88811baSStefano Zampini            each row) or NULL, if o_nz is used to specify the nonzero
1591a88811baSStefano Zampini            structure. The size of this array is equal to the number
1592a88811baSStefano Zampini            of local rows, i.e 'm'.
1593a88811baSStefano Zampini 
1594a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1595a88811baSStefano Zampini 
1596a88811baSStefano Zampini    Level: intermediate
1597a88811baSStefano Zampini 
159895452b02SPatrick Sanan    Notes:
159995452b02SPatrick Sanan     This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
1600a88811baSStefano Zampini           from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
1601a88811baSStefano Zampini           matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1602a88811baSStefano Zampini 
1603db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1604a88811baSStefano Zampini @*/
16059371c9d4SSatish Balay PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) {
16062e1947a5SStefano Zampini   PetscFunctionBegin;
16072e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
16082e1947a5SStefano Zampini   PetscValidType(B, 1);
1609cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
16102e1947a5SStefano Zampini   PetscFunctionReturn(0);
16112e1947a5SStefano Zampini }
16122e1947a5SStefano Zampini 
1613844bd0d7SStefano Zampini /* this is used by DMDA */
16149371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) {
16152e1947a5SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(B->data);
161628f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
16172e1947a5SStefano Zampini 
16182e1947a5SStefano Zampini   PetscFunctionBegin;
16199566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
16209371c9d4SSatish Balay   if (!d_nnz)
16219371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
16229371c9d4SSatish Balay   else
16239371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
16244f2d7cafSStefano Zampini 
16259371c9d4SSatish Balay   if (!o_nnz)
16269371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
16279371c9d4SSatish Balay   else
16289371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
16294f2d7cafSStefano Zampini 
16309566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16319566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
16329566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
16339566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16344f2d7cafSStefano Zampini 
16354f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
16369566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
16370f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
16389566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
16390f2f62c7SStefano Zampini #endif
16404f2d7cafSStefano Zampini 
1641fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1642fc989267SStefano Zampini     PetscInt b;
1643fc989267SStefano Zampini 
1644fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
16459371c9d4SSatish Balay     for (b = 1; b < bs; b++) { matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs); }
1646fc989267SStefano Zampini   }
16479566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16484f2d7cafSStefano Zampini 
164900a59248SStefano Zampini   nlocalcols /= bs;
165000a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
16519566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16520f2f62c7SStefano Zampini 
16530f2f62c7SStefano Zampini   /* for other matrix types */
16549566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
16552e1947a5SStefano Zampini   PetscFunctionReturn(0);
16562e1947a5SStefano Zampini }
1657b4319ba4SBarry Smith 
16589371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce) {
16593927de2eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(A->data);
16603927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1661ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
16623927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
16633927de2eSStefano Zampini   PetscInt        lrows, lcols;
16643927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1665f03112d0SStefano Zampini   PetscMPIInt     size;
16663927de2eSStefano Zampini   PetscBool       isdense, issbaij;
16673927de2eSStefano Zampini 
16683927de2eSStefano Zampini   PetscFunctionBegin;
16699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
16709566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
16719566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
16729566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
16739566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
16749566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
16759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1676e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
16779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
16780dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1679ecf5a873SStefano Zampini 
16809566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
16813927de2eSStefano Zampini   /*
1682ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
16833927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
16843927de2eSStefano Zampini   */
16859566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1686d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
16873927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
16889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
16899566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1690f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
16915f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
16923927de2eSStefano Zampini   }
16939566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
16943927de2eSStefano Zampini 
16953927de2eSStefano Zampini   /*
16963927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
16973927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
16983927de2eSStefano Zampini   */
16999566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
17003927de2eSStefano Zampini   /* preallocation as a MATAIJ */
17013927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
17023927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
170312dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
170412dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1705ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
17063927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17073927de2eSStefano Zampini           my_dnz[i] += 1;
17083927de2eSStefano Zampini         } else { /* offdiag block */
17093927de2eSStefano Zampini           my_onz[i] += 1;
17103927de2eSStefano Zampini         }
17113927de2eSStefano Zampini       }
17123927de2eSStefano Zampini     }
1713bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1714bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1715bb1015c3SStefano Zampini     PetscBool       done;
17169566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17175f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1718bb1015c3SStefano Zampini     jptr = jj;
1719bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1720bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1721bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1722bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1723bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1724bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1725bb1015c3SStefano Zampini           my_dnz[i] += 1;
1726bb1015c3SStefano Zampini         } else { /* offdiag block */
1727bb1015c3SStefano Zampini           my_onz[i] += 1;
1728bb1015c3SStefano Zampini         }
1729bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1730bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1731bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1732bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1733bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1734bb1015c3SStefano Zampini           } else {
1735bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1736bb1015c3SStefano Zampini           }
1737bb1015c3SStefano Zampini         }
1738bb1015c3SStefano Zampini       }
1739bb1015c3SStefano Zampini     }
17409566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17415f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1742bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
17433927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
17443927de2eSStefano Zampini       const PetscInt *cols;
1745ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
17469566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
17473927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
17483927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1749ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
17503927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17513927de2eSStefano Zampini           my_dnz[i] += 1;
17523927de2eSStefano Zampini         } else { /* offdiag block */
17533927de2eSStefano Zampini           my_onz[i] += 1;
17543927de2eSStefano Zampini         }
17553927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1756d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
17573927de2eSStefano Zampini           owner = row_ownership[index_col];
17583927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1759d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
17603927de2eSStefano Zampini           } else {
1761d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
17623927de2eSStefano Zampini           }
17633927de2eSStefano Zampini         }
17643927de2eSStefano Zampini       }
17659566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
17663927de2eSStefano Zampini     }
17673927de2eSStefano Zampini   }
1768*48a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
17699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
17709566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1771ecf5a873SStefano Zampini 
1772ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
17733927de2eSStefano Zampini   if (maxreduce) {
17749566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
17759566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
17769566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
17779566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
17783927de2eSStefano Zampini   } else {
17799566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
17809566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
17819566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
17829566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
17833927de2eSStefano Zampini   }
17849566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
17853927de2eSStefano Zampini 
17863927de2eSStefano Zampini   /* Resize preallocation if overestimated */
17873927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
17883927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
17893927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
17903927de2eSStefano Zampini   }
17911670daf9Sstefano_zampini 
17921670daf9Sstefano_zampini   /* Set preallocation */
17939566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
17949566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
17959566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
179653b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
179753b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
179853b44cf5SStefano Zampini 
179953b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
180053b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
180153b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
180253b44cf5SStefano Zampini     }
180353b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
180453b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
18053927de2eSStefano Zampini   }
18069566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
18079566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
18089566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1809d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
18109566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
18119566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
18123927de2eSStefano Zampini   PetscFunctionReturn(0);
18133927de2eSStefano Zampini }
18143927de2eSStefano Zampini 
18159371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M) {
1816b7ce53b6SStefano Zampini   Mat_IS            *matis = (Mat_IS *)(mat->data);
1817487b449aSStefano Zampini   Mat                local_mat, MT;
181853b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1819b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1820b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1821f03112d0SStefano Zampini   PetscMPIInt        size;
18221683a169SBarry Smith   const PetscScalar *array;
1823b7ce53b6SStefano Zampini 
1824b7ce53b6SStefano Zampini   PetscFunctionBegin;
18259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1826f03112d0SStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
18271670daf9Sstefano_zampini     Mat      B;
182853b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1829487b449aSStefano Zampini     PetscInt rbs, cbs;
18301670daf9Sstefano_zampini 
18319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
183353b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
183453b44cf5SStefano Zampini       IS              rows, cols;
183553b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
183653b44cf5SStefano Zampini       PetscInt        i, nw, *work;
183753b44cf5SStefano Zampini 
18389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18399566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
184053b44cf5SStefano Zampini       nw = nw / rbs;
18419566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nw, &work));
184253b44cf5SStefano Zampini       for (i = 0; i < nw; i++) work[ridxs[i]] += 1;
18439371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18449371c9d4SSatish Balay         if (!work[i] || work[i] > 1) break;
184553b44cf5SStefano Zampini       if (i == nw) {
18469566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18479566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18489566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18499566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
185053b44cf5SStefano Zampini       }
18519566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18529566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
1853e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18549566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18559566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
185653b44cf5SStefano Zampini         nw = nw / cbs;
18579566063dSJacob Faibussowitsch         PetscCall(PetscCalloc1(nw, &work));
185853b44cf5SStefano Zampini         for (i = 0; i < nw; i++) work[cidxs[i]] += 1;
18599371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18609371c9d4SSatish Balay           if (!work[i] || work[i] > 1) break;
186153b44cf5SStefano Zampini         if (i == nw) {
18629566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18639566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18649566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18659566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
186653b44cf5SStefano Zampini         }
18679566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
18689566063dSJacob Faibussowitsch         PetscCall(PetscFree(work));
186953b44cf5SStefano Zampini       } else if (irows) {
18709566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
187153b44cf5SStefano Zampini         icols = irows;
187253b44cf5SStefano Zampini       }
187353b44cf5SStefano Zampini     } else {
18749566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
18759566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
18769566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
18779566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
187853b44cf5SStefano Zampini     }
187953b44cf5SStefano Zampini     if (!irows || !icols) {
18809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
18819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
188253b44cf5SStefano Zampini       goto general_assembly;
188353b44cf5SStefano Zampini     }
18849566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1885487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
18869566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
18879566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
18889566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1889487b449aSStefano Zampini     } else {
1890487b449aSStefano Zampini       Mat C;
1891487b449aSStefano Zampini 
18929566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
18939566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1894487b449aSStefano Zampini     }
18959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
18969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
18979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
18987c03b4e8SStefano Zampini     PetscFunctionReturn(0);
18997c03b4e8SStefano Zampini   }
190053b44cf5SStefano Zampini general_assembly:
19019566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19029566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19049566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19059566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19069566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19079566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19089566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19099566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1910aed4548fSBarry Smith   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(matis->A))->type_name);
191176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
191276bd3646SJed Brown     PetscBool lb[4], bb[4];
191376bd3646SJed Brown 
1914b9ed4604SStefano Zampini     lb[0] = isseqdense;
1915b9ed4604SStefano Zampini     lb[1] = isseqaij;
1916b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1917b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
19181c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1919aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
192076bd3646SJed Brown   }
1921b7ce53b6SStefano Zampini 
1922487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
19239566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19249566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19259566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19269566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
19279566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
1928b7ce53b6SStefano Zampini   } else {
192953b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1930487b449aSStefano Zampini 
1931b7ce53b6SStefano Zampini     /* some checks */
1932487b449aSStefano Zampini     MT = *M;
19339566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19349566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19359566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
193608401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
193708401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
193808401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
193908401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
194008401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
194108401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
19429566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
1943b7ce53b6SStefano Zampini   }
1944d9a9e74cSStefano Zampini 
19458546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
19469566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
19478546b261SStefano Zampini     isseqaij = PETSC_TRUE;
1948d9a9e74cSStefano Zampini   } else {
19499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
1950d9a9e74cSStefano Zampini     local_mat = matis->A;
1951d9a9e74cSStefano Zampini   }
1952686e3a49SStefano Zampini 
1953b7ce53b6SStefano Zampini   /* Set values */
19549566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1955b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
195665066ba5SStefano Zampini     PetscInt i, *dummy;
1957ecf5a873SStefano Zampini 
19589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
195965066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
19609566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
19619566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
19629566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
19639566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
19649566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
1965686e3a49SStefano Zampini   } else if (isseqaij) {
19666afe12f5SStefano Zampini     const PetscInt *blocks;
19676afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
1968686e3a49SStefano Zampini     PetscBool       done;
19691683a169SBarry Smith     PetscScalar    *sarray;
1970686e3a49SStefano Zampini 
19719566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
197228b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
19739566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
19749566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
19756afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
19766afe12f5SStefano Zampini       PetscInt sum;
19776afe12f5SStefano Zampini 
19786afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
19796afe12f5SStefano Zampini       if (sum == nvtxs) {
19806afe12f5SStefano Zampini         PetscInt r;
19816afe12f5SStefano Zampini 
19826afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
19836bdcaf15SBarry Smith           PetscAssert(blocks[i] == xadj[r + 1] - xadj[r], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid block sizes prescribed for block %" PetscInt_FMT ": expected %" PetscInt_FMT ", got %" PetscInt_FMT, i, blocks[i], xadj[r + 1] - xadj[r]);
19849566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
19856afe12f5SStefano Zampini           r += blocks[i];
19866afe12f5SStefano Zampini         }
19876afe12f5SStefano Zampini       } else {
1988*48a46eb9SPierre Jolivet         for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], adjncy + xadj[i], sarray + xadj[i], ADD_VALUES));
19896afe12f5SStefano Zampini       }
19906afe12f5SStefano Zampini     } else {
1991*48a46eb9SPierre Jolivet       for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], adjncy + xadj[i], sarray + xadj[i], ADD_VALUES));
19926afe12f5SStefano Zampini     }
19939566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
199428b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
19959566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
1996686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
1997ecf5a873SStefano Zampini     PetscInt i;
1998c0962df8SStefano Zampini 
1999686e3a49SStefano Zampini     for (i = 0; i < local_rows; i++) {
2000686e3a49SStefano Zampini       PetscInt        j;
2001ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2002686e3a49SStefano Zampini 
20039566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
20049566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
20059566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2006686e3a49SStefano Zampini     }
2007b7ce53b6SStefano Zampini   }
20089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20109566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
20111baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2012487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20139566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2014487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2015487b449aSStefano Zampini     *M = MT;
2016b7ce53b6SStefano Zampini   }
2017b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2018b7ce53b6SStefano Zampini }
2019b7ce53b6SStefano Zampini 
2020b7ce53b6SStefano Zampini /*@
2021b7ce53b6SStefano Zampini     MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format
2022b7ce53b6SStefano Zampini 
2023d8d19677SJose E. Roman   Input Parameters:
2024a2b725a8SWilliam Gropp +  mat - the matrix (should be of type MATIS)
2025a2b725a8SWilliam Gropp -  reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
2026b7ce53b6SStefano Zampini 
2027b7ce53b6SStefano Zampini   Output Parameter:
2028b7ce53b6SStefano Zampini .  newmat - the matrix in AIJ format
2029b7ce53b6SStefano Zampini 
2030b7ce53b6SStefano Zampini   Level: developer
2031b7ce53b6SStefano Zampini 
203295452b02SPatrick Sanan   Notes:
2033487b449aSStefano Zampini     This function has been deprecated and it will be removed in future releases. Update your code to use the MatConvert() interface.
2034b7ce53b6SStefano Zampini 
2035db781477SPatrick Sanan .seealso: `MATIS`, `MatConvert()`
2036b7ce53b6SStefano Zampini @*/
20379371c9d4SSatish Balay PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat) {
2038b7ce53b6SStefano Zampini   PetscFunctionBegin;
2039b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2040b7ce53b6SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, reuse, 2);
2041b7ce53b6SStefano Zampini   PetscValidPointer(newmat, 3);
2042487b449aSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
2043b7ce53b6SStefano Zampini     PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 3);
2044b7ce53b6SStefano Zampini     PetscCheckSameComm(mat, 1, *newmat, 3);
204508401ef6SPierre Jolivet     PetscCheck(mat != *newmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse the same matrix");
2046b7ce53b6SStefano Zampini   }
2047cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetMPIXAIJ_C", (Mat, MatType, MatReuse, Mat *), (mat, MATAIJ, reuse, newmat));
2048b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2049b7ce53b6SStefano Zampini }
2050b7ce53b6SStefano Zampini 
20519371c9d4SSatish Balay static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat) {
2052ad6194a2SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(mat->data);
2053c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2054ad6194a2SStefano Zampini   Mat      B, localmat;
2055ad6194a2SStefano Zampini 
2056ad6194a2SStefano Zampini   PetscFunctionBegin;
20579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20599566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20609566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20619566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20629566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20639566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20649566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20659566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20669566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20679566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
20689566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
20699566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
20709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
20719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
20729566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2073ad6194a2SStefano Zampini   *newmat = B;
2074ad6194a2SStefano Zampini   PetscFunctionReturn(0);
2075ad6194a2SStefano Zampini }
2076ad6194a2SStefano Zampini 
20779371c9d4SSatish Balay static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg) {
207869796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
207969796d55SStefano Zampini   PetscBool local_sym;
208069796d55SStefano Zampini 
208169796d55SStefano Zampini   PetscFunctionBegin;
20829566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
20831c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
208469796d55SStefano Zampini   PetscFunctionReturn(0);
208569796d55SStefano Zampini }
208669796d55SStefano Zampini 
20879371c9d4SSatish Balay static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg) {
208869796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
208969796d55SStefano Zampini   PetscBool local_sym;
209069796d55SStefano Zampini 
209169796d55SStefano Zampini   PetscFunctionBegin;
2092e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2093e432b41dSStefano Zampini     *flg = PETSC_FALSE;
2094e432b41dSStefano Zampini     PetscFunctionReturn(0);
2095e432b41dSStefano Zampini   }
20969566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
20971c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
209869796d55SStefano Zampini   PetscFunctionReturn(0);
209969796d55SStefano Zampini }
210069796d55SStefano Zampini 
21019371c9d4SSatish Balay static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg) {
210245471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
210345471136SStefano Zampini   PetscBool local_sym;
210445471136SStefano Zampini 
210545471136SStefano Zampini   PetscFunctionBegin;
2106e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
210745471136SStefano Zampini     *flg = PETSC_FALSE;
210845471136SStefano Zampini     PetscFunctionReturn(0);
210945471136SStefano Zampini   }
21109566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
21111c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
211245471136SStefano Zampini   PetscFunctionReturn(0);
211345471136SStefano Zampini }
211445471136SStefano Zampini 
21159371c9d4SSatish Balay static PetscErrorCode MatDestroy_IS(Mat A) {
2116b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2117b4319ba4SBarry Smith 
2118b4319ba4SBarry Smith   PetscFunctionBegin;
21199566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21209566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21219566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21229566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21239566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21259566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2129a8116848SStefano Zampini   if (b->sf != b->csf) {
21309566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21319566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2132f03112d0SStefano Zampini   } else b->csf = NULL;
21339566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2137d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2138d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21399566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21409566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21442e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", NULL));
21469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
2160b4319ba4SBarry Smith   PetscFunctionReturn(0);
2161b4319ba4SBarry Smith }
2162b4319ba4SBarry Smith 
21639371c9d4SSatish Balay static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y) {
2164b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2165b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2166b4319ba4SBarry Smith 
2167b4319ba4SBarry Smith   PetscFunctionBegin;
2168b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
21699566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
21709566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2171b4319ba4SBarry Smith 
2172b4319ba4SBarry Smith   /* multiply the local matrix */
21739566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2174b4319ba4SBarry Smith 
2175b4319ba4SBarry Smith   /* scatter product back into global memory */
21769566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
21779566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21789566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2179b4319ba4SBarry Smith   PetscFunctionReturn(0);
2180b4319ba4SBarry Smith }
2181b4319ba4SBarry Smith 
21829371c9d4SSatish Balay static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) {
2183650997f4SStefano Zampini   Vec temp_vec;
21842e74eeadSLisandro Dalcin 
21852e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2186650997f4SStefano Zampini   if (v3 != v2) {
21879566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
21889566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2189650997f4SStefano Zampini   } else {
21909566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
21919566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
21929566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
21939566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
21949566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2195650997f4SStefano Zampini   }
21962e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
21972e74eeadSLisandro Dalcin }
21982e74eeadSLisandro Dalcin 
21999371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x) {
22002e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
22012e74eeadSLisandro Dalcin 
2202e176bc59SStefano Zampini   PetscFunctionBegin;
22032e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
22049566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22059566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22062e74eeadSLisandro Dalcin 
22072e74eeadSLisandro Dalcin   /* multiply the local matrix */
22089566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
22092e74eeadSLisandro Dalcin 
22102e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22119566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22129566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22139566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22142e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22152e74eeadSLisandro Dalcin }
22162e74eeadSLisandro Dalcin 
22179371c9d4SSatish Balay static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) {
2218650997f4SStefano Zampini   Vec temp_vec;
22192e74eeadSLisandro Dalcin 
22202e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2221650997f4SStefano Zampini   if (v3 != v2) {
22229566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22239566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2224650997f4SStefano Zampini   } else {
22259566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22269566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22279566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22289566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22299566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2230650997f4SStefano Zampini   }
22312e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22322e74eeadSLisandro Dalcin }
22332e74eeadSLisandro Dalcin 
22349371c9d4SSatish Balay static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer) {
2235b4319ba4SBarry Smith   Mat_IS     *a = (Mat_IS *)A->data;
2236b4319ba4SBarry Smith   PetscViewer sviewer;
2237ee2491ecSStefano Zampini   PetscBool   isascii, view = PETSC_TRUE;
2238b4319ba4SBarry Smith 
2239b4319ba4SBarry Smith   PetscFunctionBegin;
22409566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2241ee2491ecSStefano Zampini   if (isascii) {
2242ee2491ecSStefano Zampini     PetscViewerFormat format;
2243ee2491ecSStefano Zampini 
22449566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2245ee2491ecSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2246ee2491ecSStefano Zampini   }
2247ee2491ecSStefano Zampini   if (!view) PetscFunctionReturn(0);
22489566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22499566063dSJacob Faibussowitsch   PetscCall(MatView(a->A, sviewer));
22509566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22519566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
2252b4319ba4SBarry Smith   PetscFunctionReturn(0);
2253b4319ba4SBarry Smith }
2254b4319ba4SBarry Smith 
22559371c9d4SSatish Balay static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values) {
2256b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2257b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2258b89f26deSStefano Zampini   const PetscScalar *lv;
2259b89f26deSStefano Zampini   PetscInt           bs;
2260b89f26deSStefano Zampini 
2261b89f26deSStefano Zampini   PetscFunctionBegin;
22629566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
22639566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
22649566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
2265*48a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
22669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(bs, MPIU_SCALAR, &nodeType));
22679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
22689566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
22699566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
22709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2271b89f26deSStefano Zampini   if (values) *values = is->bdiag;
2272b89f26deSStefano Zampini   PetscFunctionReturn(0);
2273b89f26deSStefano Zampini }
2274b89f26deSStefano Zampini 
22759371c9d4SSatish Balay static PetscErrorCode MatISSetUpScatters_Private(Mat A) {
2276e176bc59SStefano Zampini   Vec             cglobal, rglobal;
22778546b261SStefano Zampini   IS              from;
22788546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2279b89f26deSStefano Zampini   PetscScalar     sum;
22808546b261SStefano Zampini   const PetscInt *garray;
22818546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2282e432b41dSStefano Zampini   VecType         rtype;
2283b4319ba4SBarry Smith 
2284b4319ba4SBarry Smith   PetscFunctionBegin;
22859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
22869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
22879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
22889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
22899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
22909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
22919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
22929566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
22939566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
22949566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
22959566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
22969566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
22979566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
22989566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
22999566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
23009566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
23019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
23029566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
23039566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
23049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
23059566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2306e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
23079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
23089566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
23099566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
23109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
23119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
23128546b261SStefano Zampini   } else {
23139566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
23148546b261SStefano Zampini     is->cctx = is->rctx;
23158546b261SStefano Zampini   }
23169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2317b89f26deSStefano Zampini 
23188546b261SStefano Zampini   /* interface counter vector (local) */
23199566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
23209566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
23219566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
23229566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23239566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23249566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23259566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23269566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
23279566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2328b89f26deSStefano Zampini 
2329b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
23309566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2331b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2332e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
23339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2334b0cc1f67SStefano Zampini 
2335b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
23369566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
23378546b261SStefano Zampini   PetscFunctionReturn(0);
23388546b261SStefano Zampini }
23398546b261SStefano Zampini 
23409371c9d4SSatish Balay static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap) {
2341e432b41dSStefano Zampini   IS                         is;
2342e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2343e432b41dSStefano Zampini   const PetscInt            *idxs;
2344e432b41dSStefano Zampini   PetscHSetI                 ht;
2345e432b41dSStefano Zampini   PetscInt                  *nidxs;
2346e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2347e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2348e432b41dSStefano Zampini 
2349e432b41dSStefano Zampini   PetscFunctionBegin;
23509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
23519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
23529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
23539566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
23549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2355e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
2356e432b41dSStefano Zampini     PetscBool missing;
23579371c9d4SSatish Balay     if (idxs[i] < 0) {
23589371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
23599371c9d4SSatish Balay       continue;
23609371c9d4SSatish Balay     }
23619566063dSJacob Faibussowitsch     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2362e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2363e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2364e432b41dSStefano Zampini   }
23659566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
23661c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2367e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2368e432b41dSStefano Zampini     *nmap = NULL;
2369e432b41dSStefano Zampini     *lmap = NULL;
23709566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
23719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2372e432b41dSStefano Zampini     PetscFunctionReturn(0);
2373e432b41dSStefano Zampini   }
2374e432b41dSStefano Zampini 
2375e432b41dSStefano Zampini   /* New l2g map without negative or repeated indices */
23769566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
23779566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
23789566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
23799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
23809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2381e432b41dSStefano Zampini 
2382e432b41dSStefano Zampini   /* New local l2g map for repeated indices */
23839566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
23849566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
23859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
23869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2387e432b41dSStefano Zampini 
23889566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
23899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2390e432b41dSStefano Zampini   PetscFunctionReturn(0);
2391e432b41dSStefano Zampini }
2392e432b41dSStefano Zampini 
23939371c9d4SSatish Balay static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping) {
23948546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2395e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2396e432b41dSStefano Zampini   PetscBool              cong, freem[]                       = {PETSC_FALSE, PETSC_FALSE};
2397e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
23988546b261SStefano Zampini 
23998546b261SStefano Zampini   PetscFunctionBegin;
2400fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2401fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2402e432b41dSStefano Zampini 
24039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
24049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24059566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
24069566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
24079566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2408e432b41dSStefano Zampini 
2409fc989267SStefano Zampini   /* If NULL, local space matches global space */
2410fc989267SStefano Zampini   if (!rmapping) {
2411fc989267SStefano Zampini     IS is;
2412fc989267SStefano Zampini 
24139566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
24149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
24159566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
24169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2417e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2418e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2419e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
24209566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2421e432b41dSStefano Zampini     if (rmapping == cmapping) {
24229566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2423e432b41dSStefano Zampini       is->cmapping = is->rmapping;
24249566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2425e432b41dSStefano Zampini       localcmapping = localrmapping;
2426fc989267SStefano Zampini     }
2427fc989267SStefano Zampini   }
2428fc989267SStefano Zampini   if (!cmapping) {
2429fc989267SStefano Zampini     IS is;
2430fc989267SStefano Zampini 
24319566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
24329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
24339566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
24349566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2435e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2436e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
24379566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2438e432b41dSStefano Zampini   }
2439e432b41dSStefano Zampini   if (!is->rmapping) {
24409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2441e432b41dSStefano Zampini     is->rmapping = rmapping;
2442e432b41dSStefano Zampini   }
2443e432b41dSStefano Zampini   if (!is->cmapping) {
24449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2445e432b41dSStefano Zampini     is->cmapping = cmapping;
2446fc989267SStefano Zampini   }
2447fc989267SStefano Zampini 
2448fc989267SStefano Zampini   /* Clean up */
24499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2450872cf891SStefano Zampini   if (is->csf != is->sf) {
24519566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
24529566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2453f03112d0SStefano Zampini   } else is->csf = NULL;
24549566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
24559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
24569566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
24573bbff08aSStefano Zampini 
2458fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2459fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
24609566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
24619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
24629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
24639566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2464e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2465e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
24666625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
24676625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
24686625354bSStefano Zampini 
24699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
24709566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
24719566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
24729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
24739566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
24746625354bSStefano Zampini     }
24751c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2476e432b41dSStefano Zampini     if (same) {
24779566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24789566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2479e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2480e432b41dSStefano Zampini     }
24816625354bSStefano Zampini   }
24829566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
24839566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2484e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
24859566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
24869566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
24879566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
24889566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
24896625354bSStefano Zampini 
24906625354bSStefano Zampini   /* Create the local matrix A */
24919566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
24929566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
24939566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
24949566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
24959566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
24969566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
24979566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
24989566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
24999566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
25009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
25019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2502b4319ba4SBarry Smith 
2503fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
25049566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2505fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
2506fc989267SStefano Zampini   PetscFunctionReturn(0);
2507fc989267SStefano Zampini }
2508fc989267SStefano Zampini 
25099371c9d4SSatish Balay static PetscErrorCode MatSetUp_IS(Mat A) {
2510fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2511fc989267SStefano Zampini 
2512fc989267SStefano Zampini   PetscFunctionBegin;
25139566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
2514*48a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
2515b4319ba4SBarry Smith   PetscFunctionReturn(0);
2516b4319ba4SBarry Smith }
2517b4319ba4SBarry Smith 
25189371c9d4SSatish Balay static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
25192e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2520f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
25212e74eeadSLisandro Dalcin 
25222e74eeadSLisandro Dalcin   PetscFunctionBegin;
25239566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2524e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25259566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25269566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2527e432b41dSStefano Zampini   } else {
25289566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2529e432b41dSStefano Zampini   }
25302e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
25312e74eeadSLisandro Dalcin }
25322e74eeadSLisandro Dalcin 
25339371c9d4SSatish Balay static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
253497563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2535f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
253697563a80SStefano Zampini 
253797563a80SStefano Zampini   PetscFunctionBegin;
25389566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2539e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25409566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25419566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2542e432b41dSStefano Zampini   } else {
25439566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, rows_l, values, addv));
2544e432b41dSStefano Zampini   }
254597563a80SStefano Zampini   PetscFunctionReturn(0);
254697563a80SStefano Zampini }
254797563a80SStefano Zampini 
25489371c9d4SSatish Balay static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
2549b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2550b4319ba4SBarry Smith 
2551b4319ba4SBarry Smith   PetscFunctionBegin;
2552e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
25539566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2554872cf891SStefano Zampini   } else {
25559566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2556872cf891SStefano Zampini   }
2557b4319ba4SBarry Smith   PetscFunctionReturn(0);
2558b4319ba4SBarry Smith }
2559b4319ba4SBarry Smith 
25609371c9d4SSatish Balay static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
2561f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2562f0006bf2SLisandro Dalcin 
2563f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2564e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
25659566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2566b4f971dfSStefano Zampini   } else {
25679566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2568b4f971dfSStefano Zampini   }
2569f0006bf2SLisandro Dalcin   PetscFunctionReturn(0);
2570f0006bf2SLisandro Dalcin }
2571f0006bf2SLisandro Dalcin 
25729371c9d4SSatish Balay static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns) {
2573f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2574f0ae7da4SStefano Zampini 
2575f0ae7da4SStefano Zampini   PetscFunctionBegin;
2576f0ae7da4SStefano Zampini   if (!n) {
2577f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2578f0ae7da4SStefano Zampini   } else {
2579f0ae7da4SStefano Zampini     PetscInt i;
2580f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2581f0ae7da4SStefano Zampini 
2582f0ae7da4SStefano Zampini     if (columns) {
25839566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2584f0ae7da4SStefano Zampini     } else {
25859566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2586f0ae7da4SStefano Zampini     }
2587f0ae7da4SStefano Zampini     if (diag != 0.) {
2588f0ae7da4SStefano Zampini       const PetscScalar *array;
25899566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
2590*48a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
25919566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2592f0ae7da4SStefano Zampini     }
25939566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
25949566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2595f0ae7da4SStefano Zampini   }
2596f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2597f0ae7da4SStefano Zampini }
2598f0ae7da4SStefano Zampini 
25999371c9d4SSatish Balay static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns) {
26006e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
26016e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
26026e520ac8SStefano Zampini   PetscInt *lrows;
26032e74eeadSLisandro Dalcin 
26042e74eeadSLisandro Dalcin   PetscFunctionBegin;
2605cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2606f0ae7da4SStefano Zampini     PetscBool cong;
260726b0207aSStefano Zampini 
26089566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
260926b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
261008401ef6SPierre Jolivet     PetscCheck(cong || !columns, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Columns can be zeroed if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2611aed4548fSBarry Smith     PetscCheck(cong || diag == 0., PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Nonzero diagonal value supported if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2612aed4548fSBarry Smith     PetscCheck(cong || !x || !b, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "A->rmap and A->cmap need to be congruent, and the l2g maps be the same");
2613f0ae7da4SStefano Zampini   }
26146e520ac8SStefano Zampini   /* get locally owned rows */
26159566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
26166e520ac8SStefano Zampini   /* fix right hand side if needed */
26176e520ac8SStefano Zampini   if (x && b) {
26186e520ac8SStefano Zampini     const PetscScalar *xx;
26196e520ac8SStefano Zampini     PetscScalar       *bb;
26206e520ac8SStefano Zampini 
26219566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
26229566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
26236e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
26249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
26259566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
26262e74eeadSLisandro Dalcin   }
26276e520ac8SStefano Zampini   /* get rows associated to the local matrices */
26289566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
26299566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
26309566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
26316e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
26329566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
26339566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26349566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
26369371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
26379371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
26389566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
26399566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2640d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2641d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
26422e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
26432e74eeadSLisandro Dalcin }
26442e74eeadSLisandro Dalcin 
26459371c9d4SSatish Balay static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) {
2646b4319ba4SBarry Smith   PetscFunctionBegin;
26479566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
2648f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2649f0ae7da4SStefano Zampini }
26502205254eSKarl Rupp 
26519371c9d4SSatish Balay static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) {
2652f0ae7da4SStefano Zampini   PetscFunctionBegin;
26539566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
2654b4319ba4SBarry Smith   PetscFunctionReturn(0);
2655b4319ba4SBarry Smith }
2656b4319ba4SBarry Smith 
26579371c9d4SSatish Balay static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type) {
2658b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2659b4319ba4SBarry Smith 
2660b4319ba4SBarry Smith   PetscFunctionBegin;
26619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
2662b4319ba4SBarry Smith   PetscFunctionReturn(0);
2663b4319ba4SBarry Smith }
2664b4319ba4SBarry Smith 
26659371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type) {
2666b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2667d0dbe9f7SStefano Zampini   PetscBool lnnz;
2668b4319ba4SBarry Smith 
2669b4319ba4SBarry Smith   PetscFunctionBegin;
26709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2671872cf891SStefano Zampini   /* fix for local empty rows/cols */
2672872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2673872cf891SStefano Zampini     Mat                    newlA;
2674f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2675f03112d0SStefano Zampini     IS                     nzr, nzc;
2676f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2677f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2678872cf891SStefano Zampini 
26799566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
26809566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
2681*48a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
26829566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
2683*48a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
26849566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
26859566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2686e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2687f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
26889566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2689f03112d0SStefano Zampini 
2690872cf891SStefano Zampini       /* extract valid submatrix */
26919566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2692f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2693f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
26949566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
26959566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2696f03112d0SStefano Zampini       newlA = is->A;
2697f03112d0SStefano Zampini     }
2698e432b41dSStefano Zampini 
2699f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2700f03112d0SStefano Zampini     if (newl2g) {
2701e432b41dSStefano Zampini       IS              zr, zc;
2702e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2703e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2704f03112d0SStefano Zampini 
27059566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
27069566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
27079566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
27089566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
27099566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
27109566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
27119566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
27129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
27139566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2714e432b41dSStefano Zampini 
27159566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2716e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
27179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
27189566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2719e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
27209566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2721e432b41dSStefano Zampini 
27229566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
27239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
27249566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
27259566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
27269566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
27279566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
27289566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
27299566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
27309566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
27319566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
27329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27339566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2734f03112d0SStefano Zampini     }
27359566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
27369566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
27379566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
27389566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2739872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2740f03112d0SStefano Zampini   }
2741d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2742d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
2743d0dbe9f7SStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2744d0dbe9f7SStefano Zampini   if (lnnz) A->nonzerostate++;
2745b4319ba4SBarry Smith   PetscFunctionReturn(0);
2746b4319ba4SBarry Smith }
2747b4319ba4SBarry Smith 
27489371c9d4SSatish Balay static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local) {
2749b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2750b4319ba4SBarry Smith 
2751b4319ba4SBarry Smith   PetscFunctionBegin;
2752b4319ba4SBarry Smith   *local = is->A;
2753b4319ba4SBarry Smith   PetscFunctionReturn(0);
2754b4319ba4SBarry Smith }
2755b4319ba4SBarry Smith 
27569371c9d4SSatish Balay static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local) {
27573b3b1effSJed Brown   PetscFunctionBegin;
27583b3b1effSJed Brown   *local = NULL;
27593b3b1effSJed Brown   PetscFunctionReturn(0);
27603b3b1effSJed Brown }
27613b3b1effSJed Brown 
2762b4319ba4SBarry Smith /*@
2763b4319ba4SBarry Smith     MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
2764b4319ba4SBarry Smith 
2765b4319ba4SBarry Smith   Input Parameter:
2766b4319ba4SBarry Smith .  mat - the matrix
2767b4319ba4SBarry Smith 
2768b4319ba4SBarry Smith   Output Parameter:
2769eb82efa4SStefano Zampini .  local - the local matrix
2770b4319ba4SBarry Smith 
2771b4319ba4SBarry Smith   Level: advanced
2772b4319ba4SBarry Smith 
2773b4319ba4SBarry Smith   Notes:
2774b4319ba4SBarry Smith     This can be called if you have precomputed the nonzero structure of the
2775b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
2776b4319ba4SBarry Smith   of the MatSetValues() operation.
2777b4319ba4SBarry Smith 
27783b3b1effSJed Brown   Call MatISRestoreLocalMat() when finished with the local matrix.
277996a6f129SJed Brown 
2780db781477SPatrick Sanan .seealso: `MATIS`
2781b4319ba4SBarry Smith @*/
27829371c9d4SSatish Balay PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local) {
2783b4319ba4SBarry Smith   PetscFunctionBegin;
27840700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2785b4319ba4SBarry Smith   PetscValidPointer(local, 2);
2786cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
2787b4319ba4SBarry Smith   PetscFunctionReturn(0);
2788b4319ba4SBarry Smith }
2789b4319ba4SBarry Smith 
27903b3b1effSJed Brown /*@
27913b3b1effSJed Brown     MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()
27923b3b1effSJed Brown 
27933b3b1effSJed Brown   Input Parameter:
27943b3b1effSJed Brown .  mat - the matrix
27953b3b1effSJed Brown 
27963b3b1effSJed Brown   Output Parameter:
27973b3b1effSJed Brown .  local - the local matrix
27983b3b1effSJed Brown 
27993b3b1effSJed Brown   Level: advanced
28003b3b1effSJed Brown 
2801db781477SPatrick Sanan .seealso: `MATIS`
28023b3b1effSJed Brown @*/
28039371c9d4SSatish Balay PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local) {
28043b3b1effSJed Brown   PetscFunctionBegin;
28053b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
28063b3b1effSJed Brown   PetscValidPointer(local, 2);
2807cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
28083b3b1effSJed Brown   PetscFunctionReturn(0);
28093b3b1effSJed Brown }
28103b3b1effSJed Brown 
28119371c9d4SSatish Balay static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype) {
28128546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
28138546b261SStefano Zampini 
28148546b261SStefano Zampini   PetscFunctionBegin;
28151baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
28169566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
28179566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
28188546b261SStefano Zampini   PetscFunctionReturn(0);
28198546b261SStefano Zampini }
28208546b261SStefano Zampini 
28218546b261SStefano Zampini /*@
28228546b261SStefano Zampini     MatISSetLocalMatType - Specifies the type of local matrix
28238546b261SStefano Zampini 
2824d8d19677SJose E. Roman   Input Parameters:
2825a2b725a8SWilliam Gropp +  mat - the matrix
2826a2b725a8SWilliam Gropp -  mtype - the local matrix type
28278546b261SStefano Zampini 
28288546b261SStefano Zampini   Output Parameter:
28298546b261SStefano Zampini 
28308546b261SStefano Zampini   Level: advanced
28318546b261SStefano Zampini 
2832db781477SPatrick Sanan .seealso: `MATIS`, `MatSetType()`, `MatType`
28338546b261SStefano Zampini @*/
28349371c9d4SSatish Balay PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype) {
28358546b261SStefano Zampini   PetscFunctionBegin;
28368546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2837cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
28388546b261SStefano Zampini   PetscFunctionReturn(0);
28398546b261SStefano Zampini }
28408546b261SStefano Zampini 
28419371c9d4SSatish Balay static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local) {
28423b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
28433b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
28448546b261SStefano Zampini   MatType   mtype, otype;
28458546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
28463b03a366Sstefano_zampini 
28473b03a366Sstefano_zampini   PetscFunctionBegin;
2848e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
28499566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
28509566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
2851aed4548fSBarry Smith     PetscCheck(orows == nrows && ocols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (you passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)", orows, ocols, nrows, ncols);
28529566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
28539566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
28549566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
28554e4c7dbeSStefano Zampini   }
28569566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
28579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
28583b03a366Sstefano_zampini   is->A = local;
28599566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
28609566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
2861*48a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
28623b03a366Sstefano_zampini   PetscFunctionReturn(0);
28633b03a366Sstefano_zampini }
28643b03a366Sstefano_zampini 
28653b03a366Sstefano_zampini /*@
2866eb82efa4SStefano Zampini     MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.
28673b03a366Sstefano_zampini 
28688546b261SStefano Zampini   Collective on Mat
28698546b261SStefano Zampini 
2870d8d19677SJose E. Roman   Input Parameters:
2871a2b725a8SWilliam Gropp +  mat - the matrix
2872a2b725a8SWilliam Gropp -  local - the local matrix
28733b03a366Sstefano_zampini 
28743b03a366Sstefano_zampini   Output Parameter:
28753b03a366Sstefano_zampini 
28763b03a366Sstefano_zampini   Level: advanced
28773b03a366Sstefano_zampini 
28783b03a366Sstefano_zampini   Notes:
28793b03a366Sstefano_zampini     This can be called if you have precomputed the local matrix and
28803b03a366Sstefano_zampini   want to provide it to the matrix object MATIS.
28813b03a366Sstefano_zampini 
2882db781477SPatrick Sanan .seealso: `MATIS`
28833b03a366Sstefano_zampini @*/
28849371c9d4SSatish Balay PetscErrorCode MatISSetLocalMat(Mat mat, Mat local) {
28853b03a366Sstefano_zampini   PetscFunctionBegin;
28863b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2887b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
2888cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
28893b03a366Sstefano_zampini   PetscFunctionReturn(0);
28903b03a366Sstefano_zampini }
28913b03a366Sstefano_zampini 
28929371c9d4SSatish Balay static PetscErrorCode MatZeroEntries_IS(Mat A) {
28936726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
28946726f965SBarry Smith 
28956726f965SBarry Smith   PetscFunctionBegin;
28969566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
28976726f965SBarry Smith   PetscFunctionReturn(0);
28986726f965SBarry Smith }
28996726f965SBarry Smith 
29009371c9d4SSatish Balay static PetscErrorCode MatScale_IS(Mat A, PetscScalar a) {
29012e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29022e74eeadSLisandro Dalcin 
29032e74eeadSLisandro Dalcin   PetscFunctionBegin;
29049566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
29052e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29062e74eeadSLisandro Dalcin }
29072e74eeadSLisandro Dalcin 
29089371c9d4SSatish Balay static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v) {
29092e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29102e74eeadSLisandro Dalcin 
29112e74eeadSLisandro Dalcin   PetscFunctionBegin;
29122e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
29139566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
29142e74eeadSLisandro Dalcin 
29152e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
29169566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
29179566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29189566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29192e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29202e74eeadSLisandro Dalcin }
29212e74eeadSLisandro Dalcin 
29229371c9d4SSatish Balay static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg) {
29236726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29246726f965SBarry Smith 
29256726f965SBarry Smith   PetscFunctionBegin;
29269566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
29276726f965SBarry Smith   PetscFunctionReturn(0);
29286726f965SBarry Smith }
29296726f965SBarry Smith 
29309371c9d4SSatish Balay static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str) {
2931f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
2932f26d0771SStefano Zampini   Mat_IS *x;
2933f26d0771SStefano Zampini 
2934f26d0771SStefano Zampini   PetscFunctionBegin;
293576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
293676bd3646SJed Brown     PetscBool ismatis;
29379566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
293828b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
293976bd3646SJed Brown   }
2940f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
29419566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
2942f26d0771SStefano Zampini   PetscFunctionReturn(0);
2943f26d0771SStefano Zampini }
2944f26d0771SStefano Zampini 
29459371c9d4SSatish Balay static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat) {
2946f26d0771SStefano Zampini   Mat                    lA;
2947e432b41dSStefano Zampini   Mat_IS                *matis = (Mat_IS *)(A->data);
2948f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
2949f26d0771SStefano Zampini   IS                     is;
2950f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
2951f26d0771SStefano Zampini   PetscInt               nrg;
2952f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
2953f26d0771SStefano Zampini 
2954f26d0771SStefano Zampini   PetscFunctionBegin;
29559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
29569566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
29579566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
29589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
295976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
296008401ef6SPierre Jolivet     for (i = 0; i < nrl; i++) PetscCheck(rl[i] < nrg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, rl[i], nrg);
296176bd3646SJed Brown   }
29629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
2963f26d0771SStefano Zampini   /* map from [0,nrl) to row */
2964f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
2965f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
29669566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
29679566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
29689566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
29699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
29709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2971f26d0771SStefano Zampini   /* compute new l2g map for columns */
2972e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
2973f26d0771SStefano Zampini     const PetscInt *cg, *cl;
2974f26d0771SStefano Zampini     PetscInt        ncg;
2975f26d0771SStefano Zampini     PetscInt        ncl;
2976f26d0771SStefano Zampini 
29779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
29789566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
29799566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
29809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
298176bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
298208401ef6SPierre Jolivet       for (i = 0; i < ncl; i++) PetscCheck(cl[i] < ncg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local column index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, cl[i], ncg);
298376bd3646SJed Brown     }
29849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
2985f26d0771SStefano Zampini     /* map from [0,ncl) to col */
2986f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
2987f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
29889566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
29899566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
29909566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
29919566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
29929566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2993f26d0771SStefano Zampini   } else {
29949566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
2995f26d0771SStefano Zampini     cl2g = rl2g;
2996f26d0771SStefano Zampini   }
2997f26d0771SStefano Zampini   /* create the MATIS submatrix */
29989566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
29999566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
30009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
30019566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3002b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3003f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
30049566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
30059566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
30069566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
30079566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
30089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
30099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
30109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3012e432b41dSStefano Zampini 
3013f26d0771SStefano Zampini   /* remove unsupported ops */
30149566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3015f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3016f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3017f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3018f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3019f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3020f26d0771SStefano Zampini   PetscFunctionReturn(0);
3021f26d0771SStefano Zampini }
3022f26d0771SStefano Zampini 
30239371c9d4SSatish Balay static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject) {
3024872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
30258546b261SStefano Zampini   char      type[256];
30268546b261SStefano Zampini   PetscBool flg;
3027872cf891SStefano Zampini 
3028872cf891SStefano Zampini   PetscFunctionBegin;
3029d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3030d0dbe9f7SStefano Zampini   PetscCall(PetscOptionsBool("-matis_keepassembled", "Store an assembled version if needed", "MatISKeepAssembled", a->keepassembled, &a->keepassembled, NULL));
30319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
30329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
30339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-matis_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
30341baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
30351baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3036d0609cedSBarry Smith   PetscOptionsHeadEnd();
3037872cf891SStefano Zampini   PetscFunctionReturn(0);
3038872cf891SStefano Zampini }
3039872cf891SStefano Zampini 
3040284134d9SBarry Smith /*@
30413c212e90SHong Zhang     MatCreateIS - Creates a "process" unassembled matrix, assembled on each
3042284134d9SBarry Smith        process but not across processes.
3043284134d9SBarry Smith 
3044284134d9SBarry Smith    Input Parameters:
3045284134d9SBarry Smith +     comm    - MPI communicator that will share the matrix
3046e176bc59SStefano Zampini .     bs      - block size of the matrix
3047df3898eeSBarry Smith .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3048e176bc59SStefano Zampini .     rmap    - local to global map for rows
3049e176bc59SStefano Zampini -     cmap    - local to global map for cols
3050284134d9SBarry Smith 
3051284134d9SBarry Smith    Output Parameter:
3052284134d9SBarry Smith .    A - the resulting matrix
3053284134d9SBarry Smith 
30548e6c10adSSatish Balay    Level: advanced
30558e6c10adSSatish Balay 
305695452b02SPatrick Sanan    Notes:
305795452b02SPatrick Sanan     See MATIS for more details.
3058fc989267SStefano Zampini     m and n are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
30596fdf41d1SStefano Zampini     used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
3060fc989267SStefano Zampini     If rmap (cmap) is NULL, then the local row (column) spaces matches the global space.
3061284134d9SBarry Smith 
3062db781477SPatrick Sanan .seealso: `MATIS`, `MatSetLocalToGlobalMapping()`
3063284134d9SBarry Smith @*/
30649371c9d4SSatish Balay PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A) {
3065284134d9SBarry Smith   PetscFunctionBegin;
30669566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
30679566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
3068*48a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
30699566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
30709566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
3071284134d9SBarry Smith   PetscFunctionReturn(0);
3072284134d9SBarry Smith }
3073284134d9SBarry Smith 
30749371c9d4SSatish Balay static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has) {
30758b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3076e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
30778b9382cfSStefano Zampini 
30788b9382cfSStefano Zampini   PetscFunctionBegin;
30798b9382cfSStefano Zampini   *has = PETSC_FALSE;
3080e26763e4SStefano Zampini   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(0);
3081d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
30829371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
30839371c9d4SSatish Balay     if (op == tobefiltered[i]) PetscFunctionReturn(0);
30849566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
30858b9382cfSStefano Zampini   PetscFunctionReturn(0);
30868b9382cfSStefano Zampini }
30878b9382cfSStefano Zampini 
30889371c9d4SSatish Balay static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode) {
3089e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3090e432b41dSStefano Zampini 
3091e432b41dSStefano Zampini   PetscFunctionBegin;
30929566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
30939566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
30949566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3095e432b41dSStefano Zampini   PetscFunctionReturn(0);
3096e432b41dSStefano Zampini }
3097e432b41dSStefano Zampini 
30989371c9d4SSatish Balay static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) {
3099e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3100e432b41dSStefano Zampini 
3101e432b41dSStefano Zampini   PetscFunctionBegin;
3102e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3103e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
31049566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3105e432b41dSStefano Zampini   } else {
31069566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3107e432b41dSStefano Zampini   }
31089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3109e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3110e432b41dSStefano Zampini   PetscFunctionReturn(0);
3111e432b41dSStefano Zampini }
3112e432b41dSStefano Zampini 
31139371c9d4SSatish Balay static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) {
3114e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3115e432b41dSStefano Zampini 
3116e432b41dSStefano Zampini   PetscFunctionBegin;
3117e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3118e432b41dSStefano Zampini   PetscCheck(ncoo <= PETSC_MAX_INT, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support", ncoo);
3119e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo, coo_i, NULL, coo_i));
3120e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo, coo_j, NULL, coo_j));
3121e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
31229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3123e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3124e432b41dSStefano Zampini   PetscFunctionReturn(0);
3125e432b41dSStefano Zampini }
3126e432b41dSStefano Zampini 
31279371c9d4SSatish Balay static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA) {
3128d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3129d0dbe9f7SStefano Zampini   PetscObjectState Astate, aAstate       = PETSC_MIN_INT;
3130d0dbe9f7SStefano Zampini   PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT;
3131d0dbe9f7SStefano Zampini 
3132d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3133d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3134d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3135d0dbe9f7SStefano Zampini   if (a->assembledA) {
3136d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3137d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3138d0dbe9f7SStefano Zampini   }
3139d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3140d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3141d0dbe9f7SStefano Zampini     MatType     aAtype;
3142d0dbe9f7SStefano Zampini     PetscMPIInt size;
3143d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3144d0dbe9f7SStefano Zampini 
3145d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3146d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3147d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3148d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3149d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3150d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3151d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3152d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3153d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3154d0dbe9f7SStefano Zampini 
3155d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3156d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3157d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3158d0dbe9f7SStefano Zampini   }
3159d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3160d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3161d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
3162d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3163d0dbe9f7SStefano Zampini }
3164d0dbe9f7SStefano Zampini 
31659371c9d4SSatish Balay static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA) {
3166d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3167d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3168d0dbe9f7SStefano Zampini   *tA = NULL;
3169d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3170d0dbe9f7SStefano Zampini }
3171d0dbe9f7SStefano Zampini 
31729371c9d4SSatish Balay static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA) {
3173d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3174d0dbe9f7SStefano Zampini   PetscObjectState Astate, dAstate = PETSC_MIN_INT;
3175d0dbe9f7SStefano Zampini 
3176d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3177d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3178d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3179d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3180d0dbe9f7SStefano Zampini     Mat     tA;
3181d0dbe9f7SStefano Zampini     MatType ltype;
3182d0dbe9f7SStefano Zampini 
3183d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3184d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3185d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3186d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3187d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3188d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3189d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3190d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3191d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3192d0dbe9f7SStefano Zampini   }
3193d0dbe9f7SStefano Zampini   *dA = a->dA;
3194d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3195d0dbe9f7SStefano Zampini }
3196d0dbe9f7SStefano Zampini 
31979371c9d4SSatish Balay static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[]) {
3198d0dbe9f7SStefano Zampini   Mat tA;
3199d0dbe9f7SStefano Zampini 
3200d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3201d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3202d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3203d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3204d0dbe9f7SStefano Zampini #if 0
3205d0dbe9f7SStefano Zampini   {
3206d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3207d0dbe9f7SStefano Zampini     MatType   ltype;
3208d0dbe9f7SStefano Zampini     VecType   vtype;
3209d0dbe9f7SStefano Zampini     char      *flg;
3210d0dbe9f7SStefano Zampini 
3211d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3212d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3213d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3214d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3215d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3216d0dbe9f7SStefano Zampini     if (flg) {
3217d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3218d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3219d0dbe9f7SStefano Zampini 
3220d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3221d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3222d0dbe9f7SStefano Zampini       }
3223d0dbe9f7SStefano Zampini     }
3224d0dbe9f7SStefano Zampini   }
3225d0dbe9f7SStefano Zampini #endif
3226d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3227d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3228d0dbe9f7SStefano Zampini }
3229d0dbe9f7SStefano Zampini 
32309371c9d4SSatish Balay static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov) {
3231d0dbe9f7SStefano Zampini   Mat tA;
3232d0dbe9f7SStefano Zampini 
3233d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3234d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3235d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3236d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3237d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3238d0dbe9f7SStefano Zampini }
3239d0dbe9f7SStefano Zampini 
3240e432b41dSStefano Zampini /*@
3241e432b41dSStefano Zampini    MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the MATIS object
3242e432b41dSStefano Zampini 
3243e432b41dSStefano Zampini    Not Collective
3244e432b41dSStefano Zampini 
3245e432b41dSStefano Zampini    Input Parameter:
3246e432b41dSStefano Zampini .  A - the matrix
3247e432b41dSStefano Zampini 
3248e432b41dSStefano Zampini    Output Parameters:
3249e432b41dSStefano Zampini +  rmapping - row mapping
3250e432b41dSStefano Zampini -  cmapping - column mapping
3251e432b41dSStefano Zampini 
3252e432b41dSStefano Zampini    Notes: The returned map can be different from the one used to construct the MATIS object, since it will not contain negative or repeated indices.
3253e432b41dSStefano Zampini 
3254e432b41dSStefano Zampini    Level: advanced
3255e432b41dSStefano Zampini 
3256db781477SPatrick Sanan .seealso: `MatSetLocalToGlobalMapping()`
3257e432b41dSStefano Zampini @*/
32589371c9d4SSatish Balay PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping) {
3259e432b41dSStefano Zampini   PetscFunctionBegin;
3260e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3261e432b41dSStefano Zampini   PetscValidType(A, 1);
3262e432b41dSStefano Zampini   if (rmapping) PetscValidPointer(rmapping, 2);
3263e432b41dSStefano Zampini   if (cmapping) PetscValidPointer(cmapping, 3);
3264cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
3265e432b41dSStefano Zampini   PetscFunctionReturn(0);
3266e432b41dSStefano Zampini }
3267e432b41dSStefano Zampini 
32689371c9d4SSatish Balay static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c) {
3269e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3270e432b41dSStefano Zampini 
3271e432b41dSStefano Zampini   PetscFunctionBegin;
3272e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3273e432b41dSStefano Zampini   if (c) *c = a->cmapping;
3274e432b41dSStefano Zampini   PetscFunctionReturn(0);
3275e432b41dSStefano Zampini }
3276e432b41dSStefano Zampini 
3277b4319ba4SBarry Smith /*MC
3278f26d0771SStefano Zampini    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
3279b89f26deSStefano Zampini    This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3280b4319ba4SBarry Smith    product is handled "implicitly".
3281b4319ba4SBarry Smith 
3282b4319ba4SBarry Smith    Options Database Keys:
328375d48cdbSStefano Zampini + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
328475d48cdbSStefano Zampini . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
328575d48cdbSStefano Zampini - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3286b4319ba4SBarry Smith 
328795452b02SPatrick Sanan    Notes:
328895452b02SPatrick Sanan     Options prefix for the inner matrix are given by -is_mat_xxx
3289b4319ba4SBarry Smith 
3290b4319ba4SBarry Smith           You must call MatSetLocalToGlobalMapping() before using this matrix type.
3291b4319ba4SBarry Smith 
3292b4319ba4SBarry Smith           You can do matrix preallocation on the local matrix after you obtain it with
3293eb82efa4SStefano Zampini           MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()
3294b4319ba4SBarry Smith 
3295b4319ba4SBarry Smith   Level: advanced
3296b4319ba4SBarry Smith 
3297db781477SPatrick Sanan .seealso: `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3298b4319ba4SBarry Smith 
3299b4319ba4SBarry Smith M*/
33009371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A) {
3301e432b41dSStefano Zampini   Mat_IS *a;
3302b4319ba4SBarry Smith 
3303b4319ba4SBarry Smith   PetscFunctionBegin;
33049566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A, &a));
33059566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3306e432b41dSStefano Zampini   A->data = (void *)a;
3307b4319ba4SBarry Smith 
3308e176bc59SStefano Zampini   /* matrix ops */
33099566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3310b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
33112e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
33122e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
33132e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3314b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3315b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
33162e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
331798921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3318b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3319f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
33202e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3321f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3322b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3323b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3324b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
33256726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
33262e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
33272e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
33286726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
332969796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
333069796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
333145471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3332ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
33336bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
33342b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3335659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
33367dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3337f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
33383fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
33393fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3340d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
33417fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3342ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3343872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3344fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
33458b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3346d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3347d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3348d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3349b4319ba4SBarry Smith 
3350b7ce53b6SStefano Zampini   /* special MATIS functions */
33519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
33529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
33539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
33549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
33559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", MatConvert_IS_XAIJ));
33569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
33579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
33589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
33599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
33609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
33619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
33629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
33639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
33649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
33659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
33669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
33679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
33689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
33699566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
3370b4319ba4SBarry Smith   PetscFunctionReturn(0);
3371b4319ba4SBarry Smith }
3372