xref: /petsc/src/mat/impls/is/matis.c (revision 013e2dc7137d1d9dc4e6b44a828a8fb0f1bd6f29)
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));
6148a46eb9SPierre 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));
6548a46eb9SPierre 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;
10948a46eb9SPierre 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;
26148a46eb9SPierre 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;
27148a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
27248a46eb9SPierre 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));
33248a46eb9SPierre 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++) {
45548a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
456fabe8965SStefano Zampini       }
45748a46eb9SPierre 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);
54748a46eb9SPierre 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 */
836*013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &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++) {
102748a46eb9SPierre 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]));
105148a46eb9SPierre 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++) {
106748a46eb9SPierre 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 */
111648a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
111748a46eb9SPierre 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));
131648a46eb9SPierre 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));
132748a46eb9SPierre 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 /*@
150711a5261eSBarry Smith    MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing 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 
1517db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
151875d48cdbSStefano Zampini @*/
15199371c9d4SSatish Balay PetscErrorCode MatISStoreL2L(Mat A, PetscBool store) {
152075d48cdbSStefano Zampini   PetscFunctionBegin;
152175d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
152275d48cdbSStefano Zampini   PetscValidType(A, 1);
152375d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1524cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
152575d48cdbSStefano Zampini   PetscFunctionReturn(0);
152675d48cdbSStefano Zampini }
152775d48cdbSStefano Zampini 
15289371c9d4SSatish Balay static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store) {
152975d48cdbSStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
153075d48cdbSStefano Zampini 
153175d48cdbSStefano Zampini   PetscFunctionBegin;
153275d48cdbSStefano Zampini   matis->storel2l = store;
153348a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
153475d48cdbSStefano Zampini   PetscFunctionReturn(0);
153575d48cdbSStefano Zampini }
153675d48cdbSStefano Zampini 
153775d48cdbSStefano Zampini /*@
1538f03112d0SStefano Zampini    MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1539f03112d0SStefano Zampini 
1540d083f849SBarry Smith    Collective
1541f03112d0SStefano Zampini 
1542f03112d0SStefano Zampini    Input Parameters:
1543f03112d0SStefano Zampini +  A - the matrix
1544f03112d0SStefano Zampini -  fix - the boolean flag
1545f03112d0SStefano Zampini 
1546f03112d0SStefano Zampini    Level: advanced
1547f03112d0SStefano Zampini 
154811a5261eSBarry Smith    Note:
154911a5261eSBarry Smith    When fix is true, new local matrices and l2g maps are generated during the final assembly process.
1550f03112d0SStefano Zampini 
155111a5261eSBarry Smith .seealso: `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1552f03112d0SStefano Zampini @*/
15539371c9d4SSatish Balay PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix) {
1554f03112d0SStefano Zampini   PetscFunctionBegin;
1555f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1556f03112d0SStefano Zampini   PetscValidType(A, 1);
1557f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1558cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
1559f03112d0SStefano Zampini   PetscFunctionReturn(0);
1560f03112d0SStefano Zampini }
1561f03112d0SStefano Zampini 
15629371c9d4SSatish Balay static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix) {
1563f03112d0SStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
1564f03112d0SStefano Zampini 
1565f03112d0SStefano Zampini   PetscFunctionBegin;
1566f03112d0SStefano Zampini   matis->locempty = fix;
1567f03112d0SStefano Zampini   PetscFunctionReturn(0);
1568f03112d0SStefano Zampini }
1569f03112d0SStefano Zampini 
1570f03112d0SStefano Zampini /*@
157111a5261eSBarry Smith    MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1572a88811baSStefano Zampini 
1573d083f849SBarry Smith    Collective
1574a88811baSStefano Zampini 
1575a88811baSStefano Zampini    Input Parameters:
1576a88811baSStefano Zampini +  B - the matrix
1577a88811baSStefano Zampini .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1578a88811baSStefano Zampini            (same value is used for all local rows)
1579a88811baSStefano Zampini .  d_nnz - array containing the number of nonzeros in the various rows of the
1580a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
1581a88811baSStefano Zampini            or NULL, if d_nz is used to specify the nonzero structure.
1582a88811baSStefano Zampini            The size of this array is equal to the number of local rows, i.e 'm'.
1583a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1584a88811baSStefano Zampini            the diagonal entry even if it is zero.
1585a88811baSStefano Zampini .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1586a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1587a88811baSStefano Zampini -  o_nnz - array containing the number of nonzeros in the various rows of the
1588a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
1589a88811baSStefano Zampini            each row) or NULL, if o_nz is used to specify the nonzero
1590a88811baSStefano Zampini            structure. The size of this array is equal to the number
1591a88811baSStefano Zampini            of local rows, i.e 'm'.
1592a88811baSStefano Zampini 
1593a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1594a88811baSStefano Zampini 
1595a88811baSStefano Zampini    Level: intermediate
1596a88811baSStefano Zampini 
159711a5261eSBarry Smith    Note:
159811a5261eSBarry Smith    This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
159911a5261eSBarry Smith    from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1600a88811baSStefano Zampini    matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1601a88811baSStefano Zampini 
1602db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1603a88811baSStefano Zampini @*/
16049371c9d4SSatish Balay PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) {
16052e1947a5SStefano Zampini   PetscFunctionBegin;
16062e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
16072e1947a5SStefano Zampini   PetscValidType(B, 1);
1608cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
16092e1947a5SStefano Zampini   PetscFunctionReturn(0);
16102e1947a5SStefano Zampini }
16112e1947a5SStefano Zampini 
1612844bd0d7SStefano Zampini /* this is used by DMDA */
16139371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) {
16142e1947a5SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(B->data);
161528f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
16162e1947a5SStefano Zampini 
16172e1947a5SStefano Zampini   PetscFunctionBegin;
16189566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
16199371c9d4SSatish Balay   if (!d_nnz)
16209371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
16219371c9d4SSatish Balay   else
16229371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
16234f2d7cafSStefano Zampini 
16249371c9d4SSatish Balay   if (!o_nnz)
16259371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
16269371c9d4SSatish Balay   else
16279371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
16284f2d7cafSStefano Zampini 
16299566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16309566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
16319566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
16329566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16334f2d7cafSStefano Zampini 
16344f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
16359566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
16360f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
16379566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
16380f2f62c7SStefano Zampini #endif
16394f2d7cafSStefano Zampini 
1640fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1641fc989267SStefano Zampini     PetscInt b;
1642fc989267SStefano Zampini 
1643fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1644ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1645fc989267SStefano Zampini   }
16469566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16474f2d7cafSStefano Zampini 
164800a59248SStefano Zampini   nlocalcols /= bs;
164900a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
16509566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16510f2f62c7SStefano Zampini 
16520f2f62c7SStefano Zampini   /* for other matrix types */
16539566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
16542e1947a5SStefano Zampini   PetscFunctionReturn(0);
16552e1947a5SStefano Zampini }
1656b4319ba4SBarry Smith 
16579371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce) {
16583927de2eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(A->data);
16593927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1660ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
16613927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
16623927de2eSStefano Zampini   PetscInt        lrows, lcols;
16633927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1664f03112d0SStefano Zampini   PetscMPIInt     size;
16653927de2eSStefano Zampini   PetscBool       isdense, issbaij;
16663927de2eSStefano Zampini 
16673927de2eSStefano Zampini   PetscFunctionBegin;
16689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
16699566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
16709566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
16719566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
16729566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
16739566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
16749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1675e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
16769566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
16770dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1678ecf5a873SStefano Zampini 
16799566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
16803927de2eSStefano Zampini   /*
1681ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
16823927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
16833927de2eSStefano Zampini   */
16849566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1685d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
16863927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
16879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
16889566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1689f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
16905f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
16913927de2eSStefano Zampini   }
16929566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
16933927de2eSStefano Zampini 
16943927de2eSStefano Zampini   /*
16953927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
16963927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
16973927de2eSStefano Zampini   */
16989566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
16993927de2eSStefano Zampini   /* preallocation as a MATAIJ */
17003927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
17013927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
170212dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
170312dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1704ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
17053927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17063927de2eSStefano Zampini           my_dnz[i] += 1;
17073927de2eSStefano Zampini         } else { /* offdiag block */
17083927de2eSStefano Zampini           my_onz[i] += 1;
17093927de2eSStefano Zampini         }
17103927de2eSStefano Zampini       }
17113927de2eSStefano Zampini     }
1712bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1713bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1714bb1015c3SStefano Zampini     PetscBool       done;
17159566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17165f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1717bb1015c3SStefano Zampini     jptr = jj;
1718bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1719bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1720bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1721bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1722bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1723bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1724bb1015c3SStefano Zampini           my_dnz[i] += 1;
1725bb1015c3SStefano Zampini         } else { /* offdiag block */
1726bb1015c3SStefano Zampini           my_onz[i] += 1;
1727bb1015c3SStefano Zampini         }
1728bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1729bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1730bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1731bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1732bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1733bb1015c3SStefano Zampini           } else {
1734bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1735bb1015c3SStefano Zampini           }
1736bb1015c3SStefano Zampini         }
1737bb1015c3SStefano Zampini       }
1738bb1015c3SStefano Zampini     }
17399566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17405f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1741bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
17423927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
17433927de2eSStefano Zampini       const PetscInt *cols;
1744ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
17459566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
17463927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
17473927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1748ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
17493927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17503927de2eSStefano Zampini           my_dnz[i] += 1;
17513927de2eSStefano Zampini         } else { /* offdiag block */
17523927de2eSStefano Zampini           my_onz[i] += 1;
17533927de2eSStefano Zampini         }
17543927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1755d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
17563927de2eSStefano Zampini           owner = row_ownership[index_col];
17573927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1758d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
17593927de2eSStefano Zampini           } else {
1760d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
17613927de2eSStefano Zampini           }
17623927de2eSStefano Zampini         }
17633927de2eSStefano Zampini       }
17649566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
17653927de2eSStefano Zampini     }
17663927de2eSStefano Zampini   }
176748a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
17689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
17699566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1770ecf5a873SStefano Zampini 
1771ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
17723927de2eSStefano Zampini   if (maxreduce) {
17739566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
17749566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
17759566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
17769566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
17773927de2eSStefano Zampini   } else {
17789566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
17799566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
17809566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
17819566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
17823927de2eSStefano Zampini   }
17839566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
17843927de2eSStefano Zampini 
17853927de2eSStefano Zampini   /* Resize preallocation if overestimated */
17863927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
17873927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
17883927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
17893927de2eSStefano Zampini   }
17901670daf9Sstefano_zampini 
17911670daf9Sstefano_zampini   /* Set preallocation */
17929566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
17939566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
17949566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
179553b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
179653b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
179753b44cf5SStefano Zampini 
179853b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
179953b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
180053b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
180153b44cf5SStefano Zampini     }
180253b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
180353b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
18043927de2eSStefano Zampini   }
18059566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
18069566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
18079566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1808d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
18099566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
18109566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
18113927de2eSStefano Zampini   PetscFunctionReturn(0);
18123927de2eSStefano Zampini }
18133927de2eSStefano Zampini 
18149371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M) {
1815b7ce53b6SStefano Zampini   Mat_IS            *matis = (Mat_IS *)(mat->data);
1816487b449aSStefano Zampini   Mat                local_mat, MT;
181753b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1818b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1819b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1820f03112d0SStefano Zampini   PetscMPIInt        size;
18211683a169SBarry Smith   const PetscScalar *array;
1822b7ce53b6SStefano Zampini 
1823b7ce53b6SStefano Zampini   PetscFunctionBegin;
18249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1825f03112d0SStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
18261670daf9Sstefano_zampini     Mat      B;
182753b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1828487b449aSStefano Zampini     PetscInt rbs, cbs;
18291670daf9Sstefano_zampini 
18309566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
183253b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
183353b44cf5SStefano Zampini       IS              rows, cols;
183453b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
183553b44cf5SStefano Zampini       PetscInt        i, nw, *work;
183653b44cf5SStefano Zampini 
18379566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
183953b44cf5SStefano Zampini       nw = nw / rbs;
18409566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nw, &work));
184153b44cf5SStefano Zampini       for (i = 0; i < nw; i++) work[ridxs[i]] += 1;
18429371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18439371c9d4SSatish Balay         if (!work[i] || work[i] > 1) break;
184453b44cf5SStefano Zampini       if (i == nw) {
18459566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18469566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18479566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18489566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
184953b44cf5SStefano Zampini       }
18509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18519566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
1852e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18539566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18549566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
185553b44cf5SStefano Zampini         nw = nw / cbs;
18569566063dSJacob Faibussowitsch         PetscCall(PetscCalloc1(nw, &work));
185753b44cf5SStefano Zampini         for (i = 0; i < nw; i++) work[cidxs[i]] += 1;
18589371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18599371c9d4SSatish Balay           if (!work[i] || work[i] > 1) break;
186053b44cf5SStefano Zampini         if (i == nw) {
18619566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18629566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18639566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18649566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
186553b44cf5SStefano Zampini         }
18669566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
18679566063dSJacob Faibussowitsch         PetscCall(PetscFree(work));
186853b44cf5SStefano Zampini       } else if (irows) {
18699566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
187053b44cf5SStefano Zampini         icols = irows;
187153b44cf5SStefano Zampini       }
187253b44cf5SStefano Zampini     } else {
18739566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
18749566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
18759566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
18769566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
187753b44cf5SStefano Zampini     }
187853b44cf5SStefano Zampini     if (!irows || !icols) {
18799566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
18809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
188153b44cf5SStefano Zampini       goto general_assembly;
188253b44cf5SStefano Zampini     }
18839566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1884487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
18859566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
18869566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
18879566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1888487b449aSStefano Zampini     } else {
1889487b449aSStefano Zampini       Mat C;
1890487b449aSStefano Zampini 
18919566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
18929566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1893487b449aSStefano Zampini     }
18949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
18959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
18969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
18977c03b4e8SStefano Zampini     PetscFunctionReturn(0);
18987c03b4e8SStefano Zampini   }
189953b44cf5SStefano Zampini general_assembly:
19009566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19029566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19039566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19049566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19059566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19069566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19079566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19089566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1909aed4548fSBarry Smith   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(matis->A))->type_name);
191076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
191176bd3646SJed Brown     PetscBool lb[4], bb[4];
191276bd3646SJed Brown 
1913b9ed4604SStefano Zampini     lb[0] = isseqdense;
1914b9ed4604SStefano Zampini     lb[1] = isseqaij;
1915b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1916b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
19171c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1918aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
191976bd3646SJed Brown   }
1920b7ce53b6SStefano Zampini 
1921487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
19229566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19239566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19249566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19259566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
19269566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
1927b7ce53b6SStefano Zampini   } else {
192853b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1929487b449aSStefano Zampini 
1930b7ce53b6SStefano Zampini     /* some checks */
1931487b449aSStefano Zampini     MT = *M;
19329566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19339566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19349566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
193508401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
193608401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
193708401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
193808401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
193908401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
194008401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
19419566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
1942b7ce53b6SStefano Zampini   }
1943d9a9e74cSStefano Zampini 
19448546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
19459566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
19468546b261SStefano Zampini     isseqaij = PETSC_TRUE;
1947d9a9e74cSStefano Zampini   } else {
19489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
1949d9a9e74cSStefano Zampini     local_mat = matis->A;
1950d9a9e74cSStefano Zampini   }
1951686e3a49SStefano Zampini 
1952b7ce53b6SStefano Zampini   /* Set values */
19539566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1954b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
195565066ba5SStefano Zampini     PetscInt i, *dummy;
1956ecf5a873SStefano Zampini 
19579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
195865066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
19599566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
19609566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
19619566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
19629566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
19639566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
1964686e3a49SStefano Zampini   } else if (isseqaij) {
19656afe12f5SStefano Zampini     const PetscInt *blocks;
19666afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
1967686e3a49SStefano Zampini     PetscBool       done;
19681683a169SBarry Smith     PetscScalar    *sarray;
1969686e3a49SStefano Zampini 
19709566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
197128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
19729566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
19739566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
19746afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
19756afe12f5SStefano Zampini       PetscInt sum;
19766afe12f5SStefano Zampini 
19776afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
19786afe12f5SStefano Zampini       if (sum == nvtxs) {
19796afe12f5SStefano Zampini         PetscInt r;
19806afe12f5SStefano Zampini 
19816afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
19826bdcaf15SBarry 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]);
19839566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
19846afe12f5SStefano Zampini           r += blocks[i];
19856afe12f5SStefano Zampini         }
19866afe12f5SStefano Zampini       } else {
198748a46eb9SPierre 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));
19886afe12f5SStefano Zampini       }
19896afe12f5SStefano Zampini     } else {
199048a46eb9SPierre 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));
19916afe12f5SStefano Zampini     }
19929566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
199328b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
19949566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
1995686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
1996ecf5a873SStefano Zampini     PetscInt i;
1997c0962df8SStefano Zampini 
1998686e3a49SStefano Zampini     for (i = 0; i < local_rows; i++) {
1999686e3a49SStefano Zampini       PetscInt        j;
2000ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2001686e3a49SStefano Zampini 
20029566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
20039566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
20049566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2005686e3a49SStefano Zampini     }
2006b7ce53b6SStefano Zampini   }
20079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
20101baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2011487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20129566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2013487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2014487b449aSStefano Zampini     *M = MT;
2015b7ce53b6SStefano Zampini   }
2016b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2017b7ce53b6SStefano Zampini }
2018b7ce53b6SStefano Zampini 
2019b7ce53b6SStefano Zampini /*@
202011a5261eSBarry Smith     MatISGetMPIXAIJ - Converts `MATIS` matrix into a parallel `MATAIJ` format
2021b7ce53b6SStefano Zampini 
2022d8d19677SJose E. Roman   Input Parameters:
202311a5261eSBarry Smith +  mat - the matrix (should be of type `MATIS`)
202411a5261eSBarry Smith -  reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
2025b7ce53b6SStefano Zampini 
2026b7ce53b6SStefano Zampini   Output Parameter:
202711a5261eSBarry Smith .  newmat - the matrix in `MATAIJ` format
2028b7ce53b6SStefano Zampini 
2029b7ce53b6SStefano Zampini   Level: developer
2030b7ce53b6SStefano Zampini 
203111a5261eSBarry Smith   Note:
203211a5261eSBarry Smith     This function has been deprecated and it will be removed in future releases. Update your code to use the `MatConvert()` interface.
2033b7ce53b6SStefano Zampini 
2034db781477SPatrick Sanan .seealso: `MATIS`, `MatConvert()`
2035b7ce53b6SStefano Zampini @*/
20369371c9d4SSatish Balay PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat) {
2037b7ce53b6SStefano Zampini   PetscFunctionBegin;
2038b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2039b7ce53b6SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, reuse, 2);
2040b7ce53b6SStefano Zampini   PetscValidPointer(newmat, 3);
2041487b449aSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
2042b7ce53b6SStefano Zampini     PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 3);
2043b7ce53b6SStefano Zampini     PetscCheckSameComm(mat, 1, *newmat, 3);
204408401ef6SPierre Jolivet     PetscCheck(mat != *newmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse the same matrix");
2045b7ce53b6SStefano Zampini   }
2046cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetMPIXAIJ_C", (Mat, MatType, MatReuse, Mat *), (mat, MATAIJ, reuse, newmat));
2047b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2048b7ce53b6SStefano Zampini }
2049b7ce53b6SStefano Zampini 
20509371c9d4SSatish Balay static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat) {
2051ad6194a2SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(mat->data);
2052c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2053ad6194a2SStefano Zampini   Mat      B, localmat;
2054ad6194a2SStefano Zampini 
2055ad6194a2SStefano Zampini   PetscFunctionBegin;
20569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20589566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20599566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20609566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20619566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20629566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20639566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20649566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20659566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20669566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
20679566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
20689566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
20699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
20709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
20719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2072ad6194a2SStefano Zampini   *newmat = B;
2073ad6194a2SStefano Zampini   PetscFunctionReturn(0);
2074ad6194a2SStefano Zampini }
2075ad6194a2SStefano Zampini 
20769371c9d4SSatish Balay static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg) {
207769796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
207869796d55SStefano Zampini   PetscBool local_sym;
207969796d55SStefano Zampini 
208069796d55SStefano Zampini   PetscFunctionBegin;
20819566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
20821c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
208369796d55SStefano Zampini   PetscFunctionReturn(0);
208469796d55SStefano Zampini }
208569796d55SStefano Zampini 
20869371c9d4SSatish Balay static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg) {
208769796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
208869796d55SStefano Zampini   PetscBool local_sym;
208969796d55SStefano Zampini 
209069796d55SStefano Zampini   PetscFunctionBegin;
2091e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2092e432b41dSStefano Zampini     *flg = PETSC_FALSE;
2093e432b41dSStefano Zampini     PetscFunctionReturn(0);
2094e432b41dSStefano Zampini   }
20959566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
20961c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
209769796d55SStefano Zampini   PetscFunctionReturn(0);
209869796d55SStefano Zampini }
209969796d55SStefano Zampini 
21009371c9d4SSatish Balay static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg) {
210145471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
210245471136SStefano Zampini   PetscBool local_sym;
210345471136SStefano Zampini 
210445471136SStefano Zampini   PetscFunctionBegin;
2105e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
210645471136SStefano Zampini     *flg = PETSC_FALSE;
210745471136SStefano Zampini     PetscFunctionReturn(0);
210845471136SStefano Zampini   }
21099566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
21101c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
211145471136SStefano Zampini   PetscFunctionReturn(0);
211245471136SStefano Zampini }
211345471136SStefano Zampini 
21149371c9d4SSatish Balay static PetscErrorCode MatDestroy_IS(Mat A) {
2115b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2116b4319ba4SBarry Smith 
2117b4319ba4SBarry Smith   PetscFunctionBegin;
21189566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21199566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21219566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21229566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21239566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21259566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2128a8116848SStefano Zampini   if (b->sf != b->csf) {
21299566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21309566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2131f03112d0SStefano Zampini   } else b->csf = NULL;
21329566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2136d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2137d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21389566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21399566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21432e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", NULL));
21459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
2159b4319ba4SBarry Smith   PetscFunctionReturn(0);
2160b4319ba4SBarry Smith }
2161b4319ba4SBarry Smith 
21629371c9d4SSatish Balay static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y) {
2163b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2164b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2165b4319ba4SBarry Smith 
2166b4319ba4SBarry Smith   PetscFunctionBegin;
2167b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
21689566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
21699566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2170b4319ba4SBarry Smith 
2171b4319ba4SBarry Smith   /* multiply the local matrix */
21729566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2173b4319ba4SBarry Smith 
2174b4319ba4SBarry Smith   /* scatter product back into global memory */
21759566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
21769566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21779566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2178b4319ba4SBarry Smith   PetscFunctionReturn(0);
2179b4319ba4SBarry Smith }
2180b4319ba4SBarry Smith 
21819371c9d4SSatish Balay static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) {
2182650997f4SStefano Zampini   Vec temp_vec;
21832e74eeadSLisandro Dalcin 
21842e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2185650997f4SStefano Zampini   if (v3 != v2) {
21869566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
21879566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2188650997f4SStefano Zampini   } else {
21899566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
21909566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
21919566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
21929566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
21939566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2194650997f4SStefano Zampini   }
21952e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
21962e74eeadSLisandro Dalcin }
21972e74eeadSLisandro Dalcin 
21989371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x) {
21992e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
22002e74eeadSLisandro Dalcin 
2201e176bc59SStefano Zampini   PetscFunctionBegin;
22022e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
22039566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22049566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22052e74eeadSLisandro Dalcin 
22062e74eeadSLisandro Dalcin   /* multiply the local matrix */
22079566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
22082e74eeadSLisandro Dalcin 
22092e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22109566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22119566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22129566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22132e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22142e74eeadSLisandro Dalcin }
22152e74eeadSLisandro Dalcin 
22169371c9d4SSatish Balay static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) {
2217650997f4SStefano Zampini   Vec temp_vec;
22182e74eeadSLisandro Dalcin 
22192e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2220650997f4SStefano Zampini   if (v3 != v2) {
22219566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22229566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2223650997f4SStefano Zampini   } else {
22249566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22259566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22269566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22279566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22289566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2229650997f4SStefano Zampini   }
22302e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22312e74eeadSLisandro Dalcin }
22322e74eeadSLisandro Dalcin 
22339371c9d4SSatish Balay static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer) {
2234b4319ba4SBarry Smith   Mat_IS     *a = (Mat_IS *)A->data;
2235b4319ba4SBarry Smith   PetscViewer sviewer;
2236ee2491ecSStefano Zampini   PetscBool   isascii, view = PETSC_TRUE;
2237b4319ba4SBarry Smith 
2238b4319ba4SBarry Smith   PetscFunctionBegin;
22399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2240ee2491ecSStefano Zampini   if (isascii) {
2241ee2491ecSStefano Zampini     PetscViewerFormat format;
2242ee2491ecSStefano Zampini 
22439566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2244ee2491ecSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2245ee2491ecSStefano Zampini   }
2246ee2491ecSStefano Zampini   if (!view) PetscFunctionReturn(0);
22479566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22489566063dSJacob Faibussowitsch   PetscCall(MatView(a->A, sviewer));
22499566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22509566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
2251b4319ba4SBarry Smith   PetscFunctionReturn(0);
2252b4319ba4SBarry Smith }
2253b4319ba4SBarry Smith 
22549371c9d4SSatish Balay static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values) {
2255b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2256b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2257b89f26deSStefano Zampini   const PetscScalar *lv;
2258b89f26deSStefano Zampini   PetscInt           bs;
2259b89f26deSStefano Zampini 
2260b89f26deSStefano Zampini   PetscFunctionBegin;
22619566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
22629566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
22639566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
226448a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
22659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(bs, MPIU_SCALAR, &nodeType));
22669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
22679566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
22689566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
22699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2270b89f26deSStefano Zampini   if (values) *values = is->bdiag;
2271b89f26deSStefano Zampini   PetscFunctionReturn(0);
2272b89f26deSStefano Zampini }
2273b89f26deSStefano Zampini 
22749371c9d4SSatish Balay static PetscErrorCode MatISSetUpScatters_Private(Mat A) {
2275e176bc59SStefano Zampini   Vec             cglobal, rglobal;
22768546b261SStefano Zampini   IS              from;
22778546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2278b89f26deSStefano Zampini   PetscScalar     sum;
22798546b261SStefano Zampini   const PetscInt *garray;
22808546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2281e432b41dSStefano Zampini   VecType         rtype;
2282b4319ba4SBarry Smith 
2283b4319ba4SBarry Smith   PetscFunctionBegin;
22849566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
22859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
22869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
22879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
22889566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
22899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
22909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
22919566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
22929566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
22939566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
22949566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
22959566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
22969566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
22979566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
22989566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
22999566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
23009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
23019566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
23029566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
23039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
23049566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2305e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
23069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
23079566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
23089566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
23099566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
23109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
23118546b261SStefano Zampini   } else {
23129566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
23138546b261SStefano Zampini     is->cctx = is->rctx;
23148546b261SStefano Zampini   }
23159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2316b89f26deSStefano Zampini 
23178546b261SStefano Zampini   /* interface counter vector (local) */
23189566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
23199566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
23209566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
23219566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23229566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23239566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23249566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23259566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
23269566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2327b89f26deSStefano Zampini 
2328b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
23299566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2330b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2331e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
23329566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2333b0cc1f67SStefano Zampini 
2334b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
23359566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
23368546b261SStefano Zampini   PetscFunctionReturn(0);
23378546b261SStefano Zampini }
23388546b261SStefano Zampini 
23399371c9d4SSatish Balay static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap) {
2340e432b41dSStefano Zampini   IS                         is;
2341e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2342e432b41dSStefano Zampini   const PetscInt            *idxs;
2343e432b41dSStefano Zampini   PetscHSetI                 ht;
2344e432b41dSStefano Zampini   PetscInt                  *nidxs;
2345e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2346e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2347e432b41dSStefano Zampini 
2348e432b41dSStefano Zampini   PetscFunctionBegin;
23499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
23509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
23519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
23529566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
23539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2354e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
2355e432b41dSStefano Zampini     PetscBool missing;
23569371c9d4SSatish Balay     if (idxs[i] < 0) {
23579371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
23589371c9d4SSatish Balay       continue;
23599371c9d4SSatish Balay     }
23609566063dSJacob Faibussowitsch     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2361e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2362e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2363e432b41dSStefano Zampini   }
23649566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
23651c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2366e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2367e432b41dSStefano Zampini     *nmap = NULL;
2368e432b41dSStefano Zampini     *lmap = NULL;
23699566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
23709566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2371e432b41dSStefano Zampini     PetscFunctionReturn(0);
2372e432b41dSStefano Zampini   }
2373e432b41dSStefano Zampini 
2374e432b41dSStefano Zampini   /* New l2g map without negative or repeated indices */
23759566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
23769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
23779566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
23789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
23799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2380e432b41dSStefano Zampini 
2381e432b41dSStefano Zampini   /* New local l2g map for repeated indices */
23829566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
23839566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
23849566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
23859566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2386e432b41dSStefano Zampini 
23879566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
23889566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2389e432b41dSStefano Zampini   PetscFunctionReturn(0);
2390e432b41dSStefano Zampini }
2391e432b41dSStefano Zampini 
23929371c9d4SSatish Balay static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping) {
23938546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2394e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2395e432b41dSStefano Zampini   PetscBool              cong, freem[]                       = {PETSC_FALSE, PETSC_FALSE};
2396e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
23978546b261SStefano Zampini 
23988546b261SStefano Zampini   PetscFunctionBegin;
2399fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2400fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2401e432b41dSStefano Zampini 
24029566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
24039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24049566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
24059566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
24069566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2407e432b41dSStefano Zampini 
2408fc989267SStefano Zampini   /* If NULL, local space matches global space */
2409fc989267SStefano Zampini   if (!rmapping) {
2410fc989267SStefano Zampini     IS is;
2411fc989267SStefano Zampini 
24129566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
24139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
24149566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
24159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2416e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2417e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2418e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
24199566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2420e432b41dSStefano Zampini     if (rmapping == cmapping) {
24219566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2422e432b41dSStefano Zampini       is->cmapping = is->rmapping;
24239566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2424e432b41dSStefano Zampini       localcmapping = localrmapping;
2425fc989267SStefano Zampini     }
2426fc989267SStefano Zampini   }
2427fc989267SStefano Zampini   if (!cmapping) {
2428fc989267SStefano Zampini     IS is;
2429fc989267SStefano Zampini 
24309566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
24319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
24329566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
24339566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2434e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2435e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
24369566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2437e432b41dSStefano Zampini   }
2438e432b41dSStefano Zampini   if (!is->rmapping) {
24399566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2440e432b41dSStefano Zampini     is->rmapping = rmapping;
2441e432b41dSStefano Zampini   }
2442e432b41dSStefano Zampini   if (!is->cmapping) {
24439566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2444e432b41dSStefano Zampini     is->cmapping = cmapping;
2445fc989267SStefano Zampini   }
2446fc989267SStefano Zampini 
2447fc989267SStefano Zampini   /* Clean up */
24489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2449872cf891SStefano Zampini   if (is->csf != is->sf) {
24509566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
24519566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2452f03112d0SStefano Zampini   } else is->csf = NULL;
24539566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
24549566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
24559566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
24563bbff08aSStefano Zampini 
2457fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2458fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
24599566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
24609566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
24619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
24629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2463e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2464e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
24656625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
24666625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
24676625354bSStefano Zampini 
24689566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
24699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
24709566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
24719566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
24729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
24736625354bSStefano Zampini     }
24741c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2475e432b41dSStefano Zampini     if (same) {
24769566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24779566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2478e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2479e432b41dSStefano Zampini     }
24806625354bSStefano Zampini   }
24819566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
24829566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2483e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
24849566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
24859566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
24869566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
24879566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
24886625354bSStefano Zampini 
24896625354bSStefano Zampini   /* Create the local matrix A */
24909566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
24919566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
24929566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
24939566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
24949566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
24959566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
24969566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
24979566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
24989566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
24999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
25009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2501b4319ba4SBarry Smith 
2502fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
25039566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2504fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
2505fc989267SStefano Zampini   PetscFunctionReturn(0);
2506fc989267SStefano Zampini }
2507fc989267SStefano Zampini 
25089371c9d4SSatish Balay static PetscErrorCode MatSetUp_IS(Mat A) {
2509fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2510fc989267SStefano Zampini 
2511fc989267SStefano Zampini   PetscFunctionBegin;
25129566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
251348a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
2514b4319ba4SBarry Smith   PetscFunctionReturn(0);
2515b4319ba4SBarry Smith }
2516b4319ba4SBarry Smith 
25179371c9d4SSatish Balay static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
25182e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2519f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
25202e74eeadSLisandro Dalcin 
25212e74eeadSLisandro Dalcin   PetscFunctionBegin;
25229566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2523e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25249566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25259566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2526e432b41dSStefano Zampini   } else {
25279566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2528e432b41dSStefano Zampini   }
25292e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
25302e74eeadSLisandro Dalcin }
25312e74eeadSLisandro Dalcin 
25329371c9d4SSatish Balay static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
253397563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2534f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
253597563a80SStefano Zampini 
253697563a80SStefano Zampini   PetscFunctionBegin;
25379566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2538e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25399566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25409566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2541e432b41dSStefano Zampini   } else {
25429566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, rows_l, values, addv));
2543e432b41dSStefano Zampini   }
254497563a80SStefano Zampini   PetscFunctionReturn(0);
254597563a80SStefano Zampini }
254697563a80SStefano Zampini 
25479371c9d4SSatish Balay static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
2548b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2549b4319ba4SBarry Smith 
2550b4319ba4SBarry Smith   PetscFunctionBegin;
2551e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
25529566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2553872cf891SStefano Zampini   } else {
25549566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2555872cf891SStefano Zampini   }
2556b4319ba4SBarry Smith   PetscFunctionReturn(0);
2557b4319ba4SBarry Smith }
2558b4319ba4SBarry Smith 
25599371c9d4SSatish Balay static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) {
2560f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2561f0006bf2SLisandro Dalcin 
2562f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2563e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
25649566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2565b4f971dfSStefano Zampini   } else {
25669566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2567b4f971dfSStefano Zampini   }
2568f0006bf2SLisandro Dalcin   PetscFunctionReturn(0);
2569f0006bf2SLisandro Dalcin }
2570f0006bf2SLisandro Dalcin 
25719371c9d4SSatish Balay static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns) {
2572f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2573f0ae7da4SStefano Zampini 
2574f0ae7da4SStefano Zampini   PetscFunctionBegin;
2575f0ae7da4SStefano Zampini   if (!n) {
2576f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2577f0ae7da4SStefano Zampini   } else {
2578f0ae7da4SStefano Zampini     PetscInt i;
2579f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2580f0ae7da4SStefano Zampini 
2581f0ae7da4SStefano Zampini     if (columns) {
25829566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2583f0ae7da4SStefano Zampini     } else {
25849566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2585f0ae7da4SStefano Zampini     }
2586f0ae7da4SStefano Zampini     if (diag != 0.) {
2587f0ae7da4SStefano Zampini       const PetscScalar *array;
25889566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
258948a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
25909566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2591f0ae7da4SStefano Zampini     }
25929566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
25939566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2594f0ae7da4SStefano Zampini   }
2595f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2596f0ae7da4SStefano Zampini }
2597f0ae7da4SStefano Zampini 
25989371c9d4SSatish Balay static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns) {
25996e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
26006e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
26016e520ac8SStefano Zampini   PetscInt *lrows;
26022e74eeadSLisandro Dalcin 
26032e74eeadSLisandro Dalcin   PetscFunctionBegin;
2604cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2605f0ae7da4SStefano Zampini     PetscBool cong;
260626b0207aSStefano Zampini 
26079566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
260826b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
260908401ef6SPierre 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");
2610aed4548fSBarry 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");
2611aed4548fSBarry 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");
2612f0ae7da4SStefano Zampini   }
26136e520ac8SStefano Zampini   /* get locally owned rows */
26149566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
26156e520ac8SStefano Zampini   /* fix right hand side if needed */
26166e520ac8SStefano Zampini   if (x && b) {
26176e520ac8SStefano Zampini     const PetscScalar *xx;
26186e520ac8SStefano Zampini     PetscScalar       *bb;
26196e520ac8SStefano Zampini 
26209566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
26219566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
26226e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
26239566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
26249566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
26252e74eeadSLisandro Dalcin   }
26266e520ac8SStefano Zampini   /* get rows associated to the local matrices */
26279566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
26289566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
26299566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
26306e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
26319566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
26329566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26339566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
26359371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
26369371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
26379566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
26389566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2639d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2640d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
26412e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
26422e74eeadSLisandro Dalcin }
26432e74eeadSLisandro Dalcin 
26449371c9d4SSatish Balay static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) {
2645b4319ba4SBarry Smith   PetscFunctionBegin;
26469566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
2647f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2648f0ae7da4SStefano Zampini }
26492205254eSKarl Rupp 
26509371c9d4SSatish Balay static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) {
2651f0ae7da4SStefano Zampini   PetscFunctionBegin;
26529566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
2653b4319ba4SBarry Smith   PetscFunctionReturn(0);
2654b4319ba4SBarry Smith }
2655b4319ba4SBarry Smith 
26569371c9d4SSatish Balay static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type) {
2657b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2658b4319ba4SBarry Smith 
2659b4319ba4SBarry Smith   PetscFunctionBegin;
26609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
2661b4319ba4SBarry Smith   PetscFunctionReturn(0);
2662b4319ba4SBarry Smith }
2663b4319ba4SBarry Smith 
26649371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type) {
2665b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2666d0dbe9f7SStefano Zampini   PetscBool lnnz;
2667b4319ba4SBarry Smith 
2668b4319ba4SBarry Smith   PetscFunctionBegin;
26699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2670872cf891SStefano Zampini   /* fix for local empty rows/cols */
2671872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2672872cf891SStefano Zampini     Mat                    newlA;
2673f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2674f03112d0SStefano Zampini     IS                     nzr, nzc;
2675f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2676f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2677872cf891SStefano Zampini 
26789566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
26799566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
268048a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
26819566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
268248a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
26839566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
26849566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2685e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2686f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
26879566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2688f03112d0SStefano Zampini 
2689872cf891SStefano Zampini       /* extract valid submatrix */
26909566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2691f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2692f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
26939566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
26949566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2695f03112d0SStefano Zampini       newlA = is->A;
2696f03112d0SStefano Zampini     }
2697e432b41dSStefano Zampini 
2698f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2699f03112d0SStefano Zampini     if (newl2g) {
2700e432b41dSStefano Zampini       IS              zr, zc;
2701e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2702e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2703f03112d0SStefano Zampini 
27049566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
27059566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
27069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
27079566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
27089566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
27099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
27109566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
27119566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
27129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2713e432b41dSStefano Zampini 
27149566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2715e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
27169566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
27179566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2718e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
27199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2720e432b41dSStefano Zampini 
27219566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
27229566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
27239566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
27249566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
27259566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
27269566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
27279566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
27289566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
27299566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
27309566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
27319566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2733f03112d0SStefano Zampini     }
27349566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
27359566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
27369566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
27379566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2738872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2739f03112d0SStefano Zampini   }
2740d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2741d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
2742d0dbe9f7SStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2743d0dbe9f7SStefano Zampini   if (lnnz) A->nonzerostate++;
2744b4319ba4SBarry Smith   PetscFunctionReturn(0);
2745b4319ba4SBarry Smith }
2746b4319ba4SBarry Smith 
27479371c9d4SSatish Balay static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local) {
2748b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2749b4319ba4SBarry Smith 
2750b4319ba4SBarry Smith   PetscFunctionBegin;
2751b4319ba4SBarry Smith   *local = is->A;
2752b4319ba4SBarry Smith   PetscFunctionReturn(0);
2753b4319ba4SBarry Smith }
2754b4319ba4SBarry Smith 
27559371c9d4SSatish Balay static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local) {
27563b3b1effSJed Brown   PetscFunctionBegin;
27573b3b1effSJed Brown   *local = NULL;
27583b3b1effSJed Brown   PetscFunctionReturn(0);
27593b3b1effSJed Brown }
27603b3b1effSJed Brown 
2761b4319ba4SBarry Smith /*@
276211a5261eSBarry Smith     MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2763b4319ba4SBarry Smith 
2764b4319ba4SBarry Smith   Input Parameter:
2765b4319ba4SBarry Smith .  mat - the matrix
2766b4319ba4SBarry Smith 
2767b4319ba4SBarry Smith   Output Parameter:
2768eb82efa4SStefano Zampini .  local - the local matrix
2769b4319ba4SBarry Smith 
2770b4319ba4SBarry Smith   Level: advanced
2771b4319ba4SBarry Smith 
2772b4319ba4SBarry Smith   Notes:
2773b4319ba4SBarry Smith     This can be called if you have precomputed the nonzero structure of the
2774b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
277511a5261eSBarry Smith   of the `MatSetValues()` operation.
2776b4319ba4SBarry Smith 
277711a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
277896a6f129SJed Brown 
277911a5261eSBarry Smith .seealso: `MATIS`, `MatISRestoreLocalMat()`
2780b4319ba4SBarry Smith @*/
27819371c9d4SSatish Balay PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local) {
2782b4319ba4SBarry Smith   PetscFunctionBegin;
27830700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2784b4319ba4SBarry Smith   PetscValidPointer(local, 2);
2785cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
2786b4319ba4SBarry Smith   PetscFunctionReturn(0);
2787b4319ba4SBarry Smith }
2788b4319ba4SBarry Smith 
27893b3b1effSJed Brown /*@
279011a5261eSBarry Smith     MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
27913b3b1effSJed Brown 
27923b3b1effSJed Brown   Input Parameter:
27933b3b1effSJed Brown .  mat - the matrix
27943b3b1effSJed Brown 
27953b3b1effSJed Brown   Output Parameter:
27963b3b1effSJed Brown .  local - the local matrix
27973b3b1effSJed Brown 
27983b3b1effSJed Brown   Level: advanced
27993b3b1effSJed Brown 
280011a5261eSBarry Smith .seealso: `MATIS`, `MatISGetLocalMat()`
28013b3b1effSJed Brown @*/
28029371c9d4SSatish Balay PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local) {
28033b3b1effSJed Brown   PetscFunctionBegin;
28043b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
28053b3b1effSJed Brown   PetscValidPointer(local, 2);
2806cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
28073b3b1effSJed Brown   PetscFunctionReturn(0);
28083b3b1effSJed Brown }
28093b3b1effSJed Brown 
28109371c9d4SSatish Balay static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype) {
28118546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
28128546b261SStefano Zampini 
28138546b261SStefano Zampini   PetscFunctionBegin;
28141baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
28159566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
28169566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
28178546b261SStefano Zampini   PetscFunctionReturn(0);
28188546b261SStefano Zampini }
28198546b261SStefano Zampini 
28208546b261SStefano Zampini /*@
282111a5261eSBarry Smith     MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
28228546b261SStefano Zampini 
2823d8d19677SJose E. Roman   Input Parameters:
2824a2b725a8SWilliam Gropp +  mat - the matrix
2825a2b725a8SWilliam Gropp -  mtype - the local matrix type
28268546b261SStefano Zampini 
28278546b261SStefano Zampini   Level: advanced
28288546b261SStefano Zampini 
2829db781477SPatrick Sanan .seealso: `MATIS`, `MatSetType()`, `MatType`
28308546b261SStefano Zampini @*/
28319371c9d4SSatish Balay PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype) {
28328546b261SStefano Zampini   PetscFunctionBegin;
28338546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2834cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
28358546b261SStefano Zampini   PetscFunctionReturn(0);
28368546b261SStefano Zampini }
28378546b261SStefano Zampini 
28389371c9d4SSatish Balay static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local) {
28393b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
28403b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
28418546b261SStefano Zampini   MatType   mtype, otype;
28428546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
28433b03a366Sstefano_zampini 
28443b03a366Sstefano_zampini   PetscFunctionBegin;
2845e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
28469566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
28479566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
2848aed4548fSBarry 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);
28499566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
28509566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
28519566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
28524e4c7dbeSStefano Zampini   }
28539566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
28549566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
28553b03a366Sstefano_zampini   is->A = local;
28569566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
28579566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
285848a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
28593b03a366Sstefano_zampini   PetscFunctionReturn(0);
28603b03a366Sstefano_zampini }
28613b03a366Sstefano_zampini 
28623b03a366Sstefano_zampini /*@
286311a5261eSBarry Smith     MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
28643b03a366Sstefano_zampini 
28658546b261SStefano Zampini   Collective on Mat
28668546b261SStefano Zampini 
2867d8d19677SJose E. Roman   Input Parameters:
2868a2b725a8SWilliam Gropp +  mat - the matrix
2869a2b725a8SWilliam Gropp -  local - the local matrix
28703b03a366Sstefano_zampini 
28713b03a366Sstefano_zampini   Level: advanced
28723b03a366Sstefano_zampini 
28733b03a366Sstefano_zampini   Notes:
287411a5261eSBarry Smith   Any previous matrix within the `MATIS` has its reference count decreased by one.
28753b03a366Sstefano_zampini 
287611a5261eSBarry Smith   This can be called if you have precomputed the local matrix and
287711a5261eSBarry Smith   want to provide it to the matrix object `MATIS`.
287811a5261eSBarry Smith 
287911a5261eSBarry Smith .seealso: `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
28803b03a366Sstefano_zampini @*/
28819371c9d4SSatish Balay PetscErrorCode MatISSetLocalMat(Mat mat, Mat local) {
28823b03a366Sstefano_zampini   PetscFunctionBegin;
28833b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2884b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
2885cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
28863b03a366Sstefano_zampini   PetscFunctionReturn(0);
28873b03a366Sstefano_zampini }
28883b03a366Sstefano_zampini 
28899371c9d4SSatish Balay static PetscErrorCode MatZeroEntries_IS(Mat A) {
28906726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
28916726f965SBarry Smith 
28926726f965SBarry Smith   PetscFunctionBegin;
28939566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
28946726f965SBarry Smith   PetscFunctionReturn(0);
28956726f965SBarry Smith }
28966726f965SBarry Smith 
28979371c9d4SSatish Balay static PetscErrorCode MatScale_IS(Mat A, PetscScalar a) {
28982e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
28992e74eeadSLisandro Dalcin 
29002e74eeadSLisandro Dalcin   PetscFunctionBegin;
29019566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
29022e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29032e74eeadSLisandro Dalcin }
29042e74eeadSLisandro Dalcin 
29059371c9d4SSatish Balay static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v) {
29062e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29072e74eeadSLisandro Dalcin 
29082e74eeadSLisandro Dalcin   PetscFunctionBegin;
29092e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
29109566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
29112e74eeadSLisandro Dalcin 
29122e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
29139566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
29149566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29159566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29162e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29172e74eeadSLisandro Dalcin }
29182e74eeadSLisandro Dalcin 
29199371c9d4SSatish Balay static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg) {
29206726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29216726f965SBarry Smith 
29226726f965SBarry Smith   PetscFunctionBegin;
29239566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
29246726f965SBarry Smith   PetscFunctionReturn(0);
29256726f965SBarry Smith }
29266726f965SBarry Smith 
29279371c9d4SSatish Balay static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str) {
2928f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
2929f26d0771SStefano Zampini   Mat_IS *x;
2930f26d0771SStefano Zampini 
2931f26d0771SStefano Zampini   PetscFunctionBegin;
293276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
293376bd3646SJed Brown     PetscBool ismatis;
29349566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
293528b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
293676bd3646SJed Brown   }
2937f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
29389566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
2939f26d0771SStefano Zampini   PetscFunctionReturn(0);
2940f26d0771SStefano Zampini }
2941f26d0771SStefano Zampini 
29429371c9d4SSatish Balay static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat) {
2943f26d0771SStefano Zampini   Mat                    lA;
2944e432b41dSStefano Zampini   Mat_IS                *matis = (Mat_IS *)(A->data);
2945f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
2946f26d0771SStefano Zampini   IS                     is;
2947f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
2948f26d0771SStefano Zampini   PetscInt               nrg;
2949f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
2950f26d0771SStefano Zampini 
2951f26d0771SStefano Zampini   PetscFunctionBegin;
29529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
29539566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
29549566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
29559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
295676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
295708401ef6SPierre 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);
295876bd3646SJed Brown   }
29599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
2960f26d0771SStefano Zampini   /* map from [0,nrl) to row */
2961f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
2962f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
29639566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
29649566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
29659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
29669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
29679566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2968f26d0771SStefano Zampini   /* compute new l2g map for columns */
2969e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
2970f26d0771SStefano Zampini     const PetscInt *cg, *cl;
2971f26d0771SStefano Zampini     PetscInt        ncg;
2972f26d0771SStefano Zampini     PetscInt        ncl;
2973f26d0771SStefano Zampini 
29749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
29759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
29769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
29779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
297876bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
297908401ef6SPierre 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);
298076bd3646SJed Brown     }
29819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
2982f26d0771SStefano Zampini     /* map from [0,ncl) to col */
2983f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
2984f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
29859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
29869566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
29879566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
29889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
29899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2990f26d0771SStefano Zampini   } else {
29919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
2992f26d0771SStefano Zampini     cl2g = rl2g;
2993f26d0771SStefano Zampini   }
2994f26d0771SStefano Zampini   /* create the MATIS submatrix */
29959566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
29969566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
29979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
29989566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
2999b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3000f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
30019566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
30029566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
30039566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
30049566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
30059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
30069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
30079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3009e432b41dSStefano Zampini 
3010f26d0771SStefano Zampini   /* remove unsupported ops */
30119566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3012f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3013f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3014f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3015f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3016f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3017f26d0771SStefano Zampini   PetscFunctionReturn(0);
3018f26d0771SStefano Zampini }
3019f26d0771SStefano Zampini 
30209371c9d4SSatish Balay static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject) {
3021872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
30228546b261SStefano Zampini   char      type[256];
30238546b261SStefano Zampini   PetscBool flg;
3024872cf891SStefano Zampini 
3025872cf891SStefano Zampini   PetscFunctionBegin;
3026d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3027d0dbe9f7SStefano Zampini   PetscCall(PetscOptionsBool("-matis_keepassembled", "Store an assembled version if needed", "MatISKeepAssembled", a->keepassembled, &a->keepassembled, NULL));
30289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
30299566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
30309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-matis_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
30311baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
30321baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3033d0609cedSBarry Smith   PetscOptionsHeadEnd();
3034872cf891SStefano Zampini   PetscFunctionReturn(0);
3035872cf891SStefano Zampini }
3036872cf891SStefano Zampini 
3037284134d9SBarry Smith /*@
303811a5261eSBarry Smith     MatCreateIS - Creates a "process" unassembled matrix, `MATIS`, assembled on each
3039284134d9SBarry Smith        process but not across processes.
3040284134d9SBarry Smith 
3041284134d9SBarry Smith    Input Parameters:
3042284134d9SBarry Smith +     comm    - MPI communicator that will share the matrix
3043e176bc59SStefano Zampini .     bs      - block size of the matrix
3044df3898eeSBarry Smith .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3045e176bc59SStefano Zampini .     rmap    - local to global map for rows
3046e176bc59SStefano Zampini -     cmap    - local to global map for cols
3047284134d9SBarry Smith 
3048284134d9SBarry Smith    Output Parameter:
3049284134d9SBarry Smith .    A - the resulting matrix
3050284134d9SBarry Smith 
30518e6c10adSSatish Balay    Level: advanced
30528e6c10adSSatish Balay 
305395452b02SPatrick Sanan    Notes:
3054fc989267SStefano 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
305511a5261eSBarry Smith     used in `MatMult()` operations. The sizes of rmap and cmap define the size of the local matrices.
305611a5261eSBarry Smith 
3057fc989267SStefano Zampini     If rmap (cmap) is NULL, then the local row (column) spaces matches the global space.
3058284134d9SBarry Smith 
3059db781477SPatrick Sanan .seealso: `MATIS`, `MatSetLocalToGlobalMapping()`
3060284134d9SBarry Smith @*/
30619371c9d4SSatish Balay PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A) {
3062284134d9SBarry Smith   PetscFunctionBegin;
30639566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
30649566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
306548a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
30669566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
30679566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
3068284134d9SBarry Smith   PetscFunctionReturn(0);
3069284134d9SBarry Smith }
3070284134d9SBarry Smith 
30719371c9d4SSatish Balay static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has) {
30728b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3073e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
30748b9382cfSStefano Zampini 
30758b9382cfSStefano Zampini   PetscFunctionBegin;
30768b9382cfSStefano Zampini   *has = PETSC_FALSE;
3077e26763e4SStefano Zampini   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(0);
3078d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
30799371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
30809371c9d4SSatish Balay     if (op == tobefiltered[i]) PetscFunctionReturn(0);
30819566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
30828b9382cfSStefano Zampini   PetscFunctionReturn(0);
30838b9382cfSStefano Zampini }
30848b9382cfSStefano Zampini 
30859371c9d4SSatish Balay static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode) {
3086e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3087e432b41dSStefano Zampini 
3088e432b41dSStefano Zampini   PetscFunctionBegin;
30899566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
30909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
30919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3092e432b41dSStefano Zampini   PetscFunctionReturn(0);
3093e432b41dSStefano Zampini }
3094e432b41dSStefano Zampini 
30959371c9d4SSatish Balay static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) {
3096e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3097e432b41dSStefano Zampini 
3098e432b41dSStefano Zampini   PetscFunctionBegin;
3099e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3100e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
31019566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3102e432b41dSStefano Zampini   } else {
31039566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3104e432b41dSStefano Zampini   }
31059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3106e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3107e432b41dSStefano Zampini   PetscFunctionReturn(0);
3108e432b41dSStefano Zampini }
3109e432b41dSStefano Zampini 
31109371c9d4SSatish Balay static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) {
3111e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3112e432b41dSStefano Zampini 
3113e432b41dSStefano Zampini   PetscFunctionBegin;
3114e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3115e432b41dSStefano 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);
3116e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo, coo_i, NULL, coo_i));
3117e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo, coo_j, NULL, coo_j));
3118e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
31199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3120e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3121e432b41dSStefano Zampini   PetscFunctionReturn(0);
3122e432b41dSStefano Zampini }
3123e432b41dSStefano Zampini 
31249371c9d4SSatish Balay static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA) {
3125d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3126d0dbe9f7SStefano Zampini   PetscObjectState Astate, aAstate       = PETSC_MIN_INT;
3127d0dbe9f7SStefano Zampini   PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT;
3128d0dbe9f7SStefano Zampini 
3129d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3130d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3131d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3132d0dbe9f7SStefano Zampini   if (a->assembledA) {
3133d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3134d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3135d0dbe9f7SStefano Zampini   }
3136d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3137d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3138d0dbe9f7SStefano Zampini     MatType     aAtype;
3139d0dbe9f7SStefano Zampini     PetscMPIInt size;
3140d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3141d0dbe9f7SStefano Zampini 
3142d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3143d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3144d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3145d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3146d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3147d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3148d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3149d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3150d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3151d0dbe9f7SStefano Zampini 
3152d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3153d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3154d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3155d0dbe9f7SStefano Zampini   }
3156d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3157d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3158d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
3159d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3160d0dbe9f7SStefano Zampini }
3161d0dbe9f7SStefano Zampini 
31629371c9d4SSatish Balay static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA) {
3163d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3164d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3165d0dbe9f7SStefano Zampini   *tA = NULL;
3166d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3167d0dbe9f7SStefano Zampini }
3168d0dbe9f7SStefano Zampini 
31699371c9d4SSatish Balay static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA) {
3170d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3171d0dbe9f7SStefano Zampini   PetscObjectState Astate, dAstate = PETSC_MIN_INT;
3172d0dbe9f7SStefano Zampini 
3173d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3174d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3175d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3176d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3177d0dbe9f7SStefano Zampini     Mat     tA;
3178d0dbe9f7SStefano Zampini     MatType ltype;
3179d0dbe9f7SStefano Zampini 
3180d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3181d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3182d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3183d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3184d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3185d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3186d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3187d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3188d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3189d0dbe9f7SStefano Zampini   }
3190d0dbe9f7SStefano Zampini   *dA = a->dA;
3191d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3192d0dbe9f7SStefano Zampini }
3193d0dbe9f7SStefano Zampini 
31949371c9d4SSatish Balay static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[]) {
3195d0dbe9f7SStefano Zampini   Mat tA;
3196d0dbe9f7SStefano Zampini 
3197d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3198d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3199d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3200d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3201d0dbe9f7SStefano Zampini #if 0
3202d0dbe9f7SStefano Zampini   {
3203d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3204d0dbe9f7SStefano Zampini     MatType   ltype;
3205d0dbe9f7SStefano Zampini     VecType   vtype;
3206d0dbe9f7SStefano Zampini     char      *flg;
3207d0dbe9f7SStefano Zampini 
3208d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3209d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3210d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3211d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3212d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3213d0dbe9f7SStefano Zampini     if (flg) {
3214d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3215d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3216d0dbe9f7SStefano Zampini 
3217d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3218d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3219d0dbe9f7SStefano Zampini       }
3220d0dbe9f7SStefano Zampini     }
3221d0dbe9f7SStefano Zampini   }
3222d0dbe9f7SStefano Zampini #endif
3223d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3224d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3225d0dbe9f7SStefano Zampini }
3226d0dbe9f7SStefano Zampini 
32279371c9d4SSatish Balay static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov) {
3228d0dbe9f7SStefano Zampini   Mat tA;
3229d0dbe9f7SStefano Zampini 
3230d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3231d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3232d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3233d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3234d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3235d0dbe9f7SStefano Zampini }
3236d0dbe9f7SStefano Zampini 
3237e432b41dSStefano Zampini /*@
323811a5261eSBarry Smith    MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3239e432b41dSStefano Zampini 
3240e432b41dSStefano Zampini    Not Collective
3241e432b41dSStefano Zampini 
3242e432b41dSStefano Zampini    Input Parameter:
3243e432b41dSStefano Zampini .  A - the matrix
3244e432b41dSStefano Zampini 
3245e432b41dSStefano Zampini    Output Parameters:
3246e432b41dSStefano Zampini +  rmapping - row mapping
3247e432b41dSStefano Zampini -  cmapping - column mapping
3248e432b41dSStefano Zampini 
324911a5261eSBarry Smith    Note:
325011a5261eSBarry Smith    The returned map can be different from the one used to construct the `MATIS` object, since it will not contain negative or repeated indices.
3251e432b41dSStefano Zampini 
3252e432b41dSStefano Zampini    Level: advanced
3253e432b41dSStefano Zampini 
325411a5261eSBarry Smith .seealso: `MatIS`, `MatSetLocalToGlobalMapping()`
3255e432b41dSStefano Zampini @*/
32569371c9d4SSatish Balay PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping) {
3257e432b41dSStefano Zampini   PetscFunctionBegin;
3258e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3259e432b41dSStefano Zampini   PetscValidType(A, 1);
3260e432b41dSStefano Zampini   if (rmapping) PetscValidPointer(rmapping, 2);
3261e432b41dSStefano Zampini   if (cmapping) PetscValidPointer(cmapping, 3);
3262cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
3263e432b41dSStefano Zampini   PetscFunctionReturn(0);
3264e432b41dSStefano Zampini }
3265e432b41dSStefano Zampini 
32669371c9d4SSatish Balay static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c) {
3267e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3268e432b41dSStefano Zampini 
3269e432b41dSStefano Zampini   PetscFunctionBegin;
3270e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3271e432b41dSStefano Zampini   if (c) *c = a->cmapping;
3272e432b41dSStefano Zampini   PetscFunctionReturn(0);
3273e432b41dSStefano Zampini }
3274e432b41dSStefano Zampini 
3275b4319ba4SBarry Smith /*MC
327611a5261eSBarry Smith    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
3277b89f26deSStefano Zampini    This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3278b4319ba4SBarry Smith    product is handled "implicitly".
3279b4319ba4SBarry Smith 
3280b4319ba4SBarry Smith    Options Database Keys:
328175d48cdbSStefano Zampini + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
328275d48cdbSStefano Zampini . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
328375d48cdbSStefano Zampini - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3284b4319ba4SBarry Smith 
328595452b02SPatrick Sanan    Notes:
328695452b02SPatrick Sanan    Options prefix for the inner matrix are given by -is_mat_xxx
3287b4319ba4SBarry Smith 
328811a5261eSBarry Smith    You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3289b4319ba4SBarry Smith 
3290b4319ba4SBarry Smith    You can do matrix preallocation on the local matrix after you obtain it with
329111a5261eSBarry Smith    `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()`
3292b4319ba4SBarry Smith 
3293b4319ba4SBarry Smith   Level: advanced
3294b4319ba4SBarry Smith 
329511a5261eSBarry Smith .seealso: `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3296b4319ba4SBarry Smith M*/
32979371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A) {
3298e432b41dSStefano Zampini   Mat_IS *a;
3299b4319ba4SBarry Smith 
3300b4319ba4SBarry Smith   PetscFunctionBegin;
33019566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A, &a));
33029566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3303e432b41dSStefano Zampini   A->data = (void *)a;
3304b4319ba4SBarry Smith 
3305e176bc59SStefano Zampini   /* matrix ops */
33069566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3307b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
33082e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
33092e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
33102e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3311b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3312b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
33132e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
331498921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3315b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3316f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
33172e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3318f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3319b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3320b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3321b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
33226726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
33232e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
33242e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
33256726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
332669796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
332769796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
332845471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3329ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
33306bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
33312b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3332659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
33337dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3334f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
33353fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
33363fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3337d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
33387fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3339ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3340872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3341fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
33428b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3343d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3344d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3345d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3346b4319ba4SBarry Smith 
3347b7ce53b6SStefano Zampini   /* special MATIS functions */
33489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
33499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
33509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
33519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
33529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", MatConvert_IS_XAIJ));
33539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
33549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
33559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
33569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
33579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
33589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
33599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
33609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
33619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
33629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
33639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
33649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
33659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
33669566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
3367b4319ba4SBarry Smith   PetscFunctionReturn(0);
3368b4319ba4SBarry Smith }
3369