xref: /petsc/src/mat/impls/is/matis.c (revision 076fee3429acdf5e802b065fe653628f00b92f71)
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*/
115042aa92SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
124f2d7cafSStefano Zampini #include <petsc/private/sfimpl.h>
13a72d46e8SStefano Zampini #include <petsc/private/vecimpl.h>
14e432b41dSStefano Zampini #include <petsc/private/hashseti.h>
1528f4e0baSStefano Zampini 
16f26d0771SStefano Zampini #define MATIS_MAX_ENTRIES_INSERTION 2048
17*076fee34SStefano Zampini 
18*076fee34SStefano Zampini /* copied from src/mat/impls/localref/mlocalref.c */
19*076fee34SStefano Zampini #define IndexSpaceGet(buf, nrow, ncol, irowm, icolm) \
20*076fee34SStefano Zampini   do { \
21*076fee34SStefano Zampini     if (nrow + ncol > (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) { \
22*076fee34SStefano Zampini       PetscCall(PetscMalloc2(nrow, &irowm, ncol, &icolm)); \
23*076fee34SStefano Zampini     } else { \
24*076fee34SStefano Zampini       irowm = &buf[0]; \
25*076fee34SStefano Zampini       icolm = &buf[nrow]; \
26*076fee34SStefano Zampini     } \
27*076fee34SStefano Zampini   } while (0)
28*076fee34SStefano Zampini 
29*076fee34SStefano Zampini #define IndexSpaceRestore(buf, nrow, ncol, irowm, icolm) \
30*076fee34SStefano Zampini   do { \
31*076fee34SStefano Zampini     if (nrow + ncol > (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) PetscCall(PetscFree2(irowm, icolm)); \
32*076fee34SStefano Zampini   } while (0)
33*076fee34SStefano Zampini 
34*076fee34SStefano Zampini static void BlockIndicesExpand(PetscInt n, const PetscInt idx[], PetscInt bs, PetscInt idxm[])
35*076fee34SStefano Zampini {
36*076fee34SStefano Zampini   for (PetscInt i = 0; i < n; i++) {
37*076fee34SStefano Zampini     for (PetscInt j = 0; j < bs; j++) idxm[i * bs + j] = idx[i] * bs + j;
38*076fee34SStefano Zampini   }
39*076fee34SStefano Zampini }
40*076fee34SStefano Zampini 
41b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
42b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
438546b261SStefano Zampini static PetscErrorCode MatISSetUpScatters_Private(Mat);
44f26d0771SStefano Zampini 
4549abdd8aSBarry Smith static PetscErrorCode MatISContainerDestroyPtAP_Private(void **ptr)
46d71ae5a4SJacob Faibussowitsch {
4749abdd8aSBarry Smith   MatISPtAP ptap = (MatISPtAP)*ptr;
4875d48cdbSStefano Zampini 
4975d48cdbSStefano Zampini   PetscFunctionBegin;
509566063dSJacob Faibussowitsch   PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP));
519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis0));
529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis1));
539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris0));
549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris1));
559566063dSJacob Faibussowitsch   PetscCall(PetscFree(ptap));
563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5775d48cdbSStefano Zampini }
5875d48cdbSStefano Zampini 
59d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
60d71ae5a4SJacob Faibussowitsch {
6175d48cdbSStefano Zampini   MatISPtAP      ptap;
6275d48cdbSStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
6375d48cdbSStefano Zampini   Mat            lA, lC;
6475d48cdbSStefano Zampini   MatReuse       reuse;
6575d48cdbSStefano Zampini   IS             ris[2], cis[2];
6675d48cdbSStefano Zampini   PetscContainer c;
6775d48cdbSStefano Zampini   PetscInt       n;
6875d48cdbSStefano Zampini 
6975d48cdbSStefano Zampini   PetscFunctionBegin;
709566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c));
7128b400f6SJacob Faibussowitsch   PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information");
729566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(c, (void **)&ptap));
7375d48cdbSStefano Zampini   ris[0] = ptap->ris0;
7475d48cdbSStefano Zampini   ris[1] = ptap->ris1;
7575d48cdbSStefano Zampini   cis[0] = ptap->cis0;
7675d48cdbSStefano Zampini   cis[1] = ptap->cis1;
7775d48cdbSStefano Zampini   n      = ptap->ris1 ? 2 : 1;
7875d48cdbSStefano Zampini   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
799566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP));
8075d48cdbSStefano Zampini 
819566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
829566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(C, &lC));
8375d48cdbSStefano Zampini   if (ptap->ris1) { /* unsymmetric A mapping */
8475d48cdbSStefano Zampini     Mat lPt;
8575d48cdbSStefano Zampini 
869566063dSJacob Faibussowitsch     PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt));
879566063dSJacob Faibussowitsch     PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC));
8857508eceSPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", (PetscObject)lPt));
899566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lPt));
9075d48cdbSStefano Zampini   } else {
919566063dSJacob Faibussowitsch     PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC));
9248a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0]));
9375d48cdbSStefano Zampini   }
9475d48cdbSStefano Zampini   if (reuse == MAT_INITIAL_MATRIX) {
959566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(C, lC));
969566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lC));
9775d48cdbSStefano Zampini   }
989566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
999566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
1003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10175d48cdbSStefano Zampini }
10275d48cdbSStefano Zampini 
103d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis)
104d71ae5a4SJacob Faibussowitsch {
10575d48cdbSStefano Zampini   Mat             Po, Pd;
10675d48cdbSStefano Zampini   IS              zd, zo;
10775d48cdbSStefano Zampini   const PetscInt *garray;
10875d48cdbSStefano Zampini   PetscInt       *aux, i, bs;
10975d48cdbSStefano Zampini   PetscInt        dc, stc, oc, ctd, cto;
11075d48cdbSStefano Zampini   PetscBool       ismpiaij, ismpibaij, isseqaij, isseqbaij;
11175d48cdbSStefano Zampini   MPI_Comm        comm;
11275d48cdbSStefano Zampini 
11375d48cdbSStefano Zampini   PetscFunctionBegin;
11475d48cdbSStefano Zampini   PetscValidHeaderSpecific(PT, MAT_CLASSID, 1);
1154f572ea9SToby Isaac   PetscAssertPointer(cis, 2);
1169566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)PT, &comm));
11775d48cdbSStefano Zampini   bs = 1;
1189566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij));
1199566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij));
1209566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij));
1219566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij));
12275d48cdbSStefano Zampini   if (isseqaij || isseqbaij) {
12375d48cdbSStefano Zampini     Pd     = PT;
12475d48cdbSStefano Zampini     Po     = NULL;
12575d48cdbSStefano Zampini     garray = NULL;
12675d48cdbSStefano Zampini   } else if (ismpiaij) {
1279566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray));
12875d48cdbSStefano Zampini   } else if (ismpibaij) {
1299566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray));
1309566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(PT, &bs));
13157508eceSPierre Jolivet   } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)PT)->type_name);
13275d48cdbSStefano Zampini 
13375d48cdbSStefano Zampini   /* identify any null columns in Pd or Po */
13422f7620eSStefano Zampini   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
13522f7620eSStefano Zampini      some of the columns are not really zero, but very close to */
13675d48cdbSStefano Zampini   zo = zd = NULL;
13748a46eb9SPierre Jolivet   if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo));
1389566063dSJacob Faibussowitsch   PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd));
13975d48cdbSStefano Zampini 
1409566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(PT, NULL, &dc));
1419566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL));
1429566063dSJacob Faibussowitsch   if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc));
14375d48cdbSStefano Zampini   else oc = 0;
1449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
14575d48cdbSStefano Zampini   if (zd) {
14675d48cdbSStefano Zampini     const PetscInt *idxs;
14775d48cdbSStefano Zampini     PetscInt        nz;
14875d48cdbSStefano Zampini 
14975d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1509566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zd, bs));
1519566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zd, &nz));
1529566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zd, &idxs));
15375d48cdbSStefano Zampini     ctd = nz / bs;
15475d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs;
1559566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zd, &idxs));
15675d48cdbSStefano Zampini   } else {
15775d48cdbSStefano Zampini     ctd = dc / bs;
15875d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = i + stc / bs;
15975d48cdbSStefano Zampini   }
16075d48cdbSStefano Zampini   if (zo) {
16175d48cdbSStefano Zampini     const PetscInt *idxs;
16275d48cdbSStefano Zampini     PetscInt        nz;
16375d48cdbSStefano Zampini 
16475d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1659566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zo, bs));
1669566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zo, &nz));
1679566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zo, &idxs));
16875d48cdbSStefano Zampini     cto = nz / bs;
16975d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs];
1709566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zo, &idxs));
17175d48cdbSStefano Zampini   } else {
17275d48cdbSStefano Zampini     cto = oc / bs;
17375d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[i];
17475d48cdbSStefano Zampini   }
1759566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis));
1769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zd));
1779566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zo));
1783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17975d48cdbSStefano Zampini }
18075d48cdbSStefano Zampini 
181d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C)
182d71ae5a4SJacob Faibussowitsch {
1838546b261SStefano Zampini   Mat                    PT, lA;
18475d48cdbSStefano Zampini   MatISPtAP              ptap;
18575d48cdbSStefano Zampini   ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g;
18675d48cdbSStefano Zampini   PetscContainer         c;
1878546b261SStefano Zampini   MatType                lmtype;
18875d48cdbSStefano Zampini   const PetscInt        *garray;
18975d48cdbSStefano Zampini   PetscInt               ibs, N, dc;
19075d48cdbSStefano Zampini   MPI_Comm               comm;
19175d48cdbSStefano Zampini 
19275d48cdbSStefano Zampini   PetscFunctionBegin;
1939566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1949566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATIS));
1959566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
1969566063dSJacob Faibussowitsch   PetscCall(MatGetType(lA, &lmtype));
1979566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(C, lmtype));
1989566063dSJacob Faibussowitsch   PetscCall(MatGetSize(P, NULL, &N));
1999566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(P, NULL, &dc));
2009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, dc, dc, N, N));
20175d48cdbSStefano Zampini   /* Not sure about this
2029566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSizes(P,NULL,&ibs));
2039566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(*C,ibs));
20475d48cdbSStefano Zampini */
20575d48cdbSStefano Zampini 
2069566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ptap));
2079566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
2089566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ptap));
20949abdd8aSBarry Smith   PetscCall(PetscContainerSetCtxDestroy(c, MatISContainerDestroyPtAP_Private));
2109566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c));
2119566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
21275d48cdbSStefano Zampini   ptap->fill = fill;
21375d48cdbSStefano Zampini 
2149566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g));
21575d48cdbSStefano Zampini 
2169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs));
2179566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N));
2189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray));
2199566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0));
2209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray));
22175d48cdbSStefano Zampini 
2229566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT));
2239566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0));
2249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g));
2259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&PT));
22675d48cdbSStefano Zampini 
22775d48cdbSStefano Zampini   Crl2g = NULL;
22875d48cdbSStefano Zampini   if (rl2g != cl2g) { /* unsymmetric A mapping */
22975d48cdbSStefano Zampini     PetscBool same, lsame = PETSC_FALSE;
23075d48cdbSStefano Zampini     PetscInt  N1, ibs1;
23175d48cdbSStefano Zampini 
2329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1));
2339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1));
2349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray));
2354f58015eSStefano Zampini     PetscCall(ISCreateBlock(comm, ibs, N1 / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1));
2369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray));
23775d48cdbSStefano Zampini     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
23875d48cdbSStefano Zampini       const PetscInt *i1, *i2;
23975d48cdbSStefano Zampini 
2409566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris0, &i1));
2419566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris1, &i2));
2429566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(i1, i2, N, &lsame));
24375d48cdbSStefano Zampini     }
2445440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(&lsame, &same, 1, MPI_C_BOOL, MPI_LAND, comm));
24575d48cdbSStefano Zampini     if (same) {
2469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ptap->ris1));
24775d48cdbSStefano Zampini     } else {
2489566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT));
2499566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1));
2509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g));
2519566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&PT));
25275d48cdbSStefano Zampini     }
25375d48cdbSStefano Zampini   }
25475d48cdbSStefano Zampini   /* Not sure about this
25575d48cdbSStefano Zampini   if (!Crl2g) {
2569566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(C,&ibs));
2579566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs));
25875d48cdbSStefano Zampini   }
25975d48cdbSStefano Zampini */
2609566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g));
2619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g));
2629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g));
26375d48cdbSStefano Zampini 
2644222ddf1SHong Zhang   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
2653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26675d48cdbSStefano Zampini }
26775d48cdbSStefano Zampini 
268d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
269d71ae5a4SJacob Faibussowitsch {
2704222ddf1SHong Zhang   Mat_Product *product = C->product;
2714222ddf1SHong Zhang   Mat          A = product->A, P = product->B;
2724222ddf1SHong Zhang   PetscReal    fill = product->fill;
27375d48cdbSStefano Zampini 
27475d48cdbSStefano Zampini   PetscFunctionBegin;
2759566063dSJacob Faibussowitsch   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
2764222ddf1SHong Zhang   C->ops->productnumeric = MatProductNumeric_PtAP;
2773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27875d48cdbSStefano Zampini }
27975d48cdbSStefano Zampini 
280d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
281d71ae5a4SJacob Faibussowitsch {
2824222ddf1SHong Zhang   PetscFunctionBegin;
2834222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
2843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2854222ddf1SHong Zhang }
2864222ddf1SHong Zhang 
287d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
288d71ae5a4SJacob Faibussowitsch {
2894222ddf1SHong Zhang   Mat_Product *product = C->product;
2904222ddf1SHong Zhang 
2914222ddf1SHong Zhang   PetscFunctionBegin;
29248a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2944222ddf1SHong Zhang }
2954222ddf1SHong Zhang 
29649abdd8aSBarry Smith static PetscErrorCode MatISContainerDestroyFields_Private(void **ptr)
297d71ae5a4SJacob Faibussowitsch {
29849abdd8aSBarry Smith   MatISLocalFields lf = (MatISLocalFields)*ptr;
2995b003df0Sstefano_zampini   PetscInt         i;
3005b003df0Sstefano_zampini 
301ab4d48faSStefano Zampini   PetscFunctionBegin;
30248a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
30348a46eb9SPierre Jolivet   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
3049566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lf->rf, lf->cf));
3059566063dSJacob Faibussowitsch   PetscCall(PetscFree(lf));
3063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3075b003df0Sstefano_zampini }
308a72627d2SStefano Zampini 
309d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
310d71ae5a4SJacob Faibussowitsch {
311c9225affSStefano Zampini   Mat B, lB;
312c9225affSStefano Zampini 
313c9225affSStefano Zampini   PetscFunctionBegin;
314c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
315c9225affSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
316c9225affSStefano Zampini     PetscInt               bs;
317c9225affSStefano Zampini     IS                     is;
318c9225affSStefano Zampini 
3199566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
3209566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
321c9225affSStefano Zampini     if (bs > 1) {
322c9225affSStefano Zampini       IS       is2;
323c9225affSStefano Zampini       PetscInt i, *aux;
324c9225affSStefano Zampini 
3259566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3269566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3279566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3289566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3299566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
330c9225affSStefano Zampini       is = is2;
331c9225affSStefano Zampini     }
3329566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3349566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3359566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
336c9225affSStefano Zampini     if (bs > 1) {
337c9225affSStefano Zampini       IS       is2;
338c9225affSStefano Zampini       PetscInt i, *aux;
339c9225affSStefano Zampini 
3409566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3429566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3449566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
345c9225affSStefano Zampini       is = is2;
346c9225affSStefano Zampini     }
3479566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3509566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
3519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3539566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
354c9225affSStefano Zampini     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
355c9225affSStefano Zampini   } else {
356c9225affSStefano Zampini     B = *newmat;
3579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
358c9225affSStefano Zampini     lB = A;
359c9225affSStefano Zampini   }
3609566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lB));
3619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lB));
3629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
36448a46eb9SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
3653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
366c9225affSStefano Zampini }
367c9225affSStefano Zampini 
368d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
369d71ae5a4SJacob Faibussowitsch {
370f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
371c9225affSStefano Zampini   PetscScalar    *aa;
372c9225affSStefano Zampini   const PetscInt *ii, *jj;
373c9225affSStefano Zampini   PetscInt        i, n, m;
374fabe8965SStefano Zampini   PetscInt       *ecount, **eneighs;
375c9225affSStefano Zampini   PetscBool       flg;
376c9225affSStefano Zampini 
377c9225affSStefano Zampini   PetscFunctionBegin;
3789566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
37908401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
3809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
38108401ef6SPierre Jolivet   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
3829566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
383c9225affSStefano Zampini   for (i = 0; i < n; i++) {
384fabe8965SStefano Zampini     if (ecount[i] > 1) {
385c9225affSStefano Zampini       PetscInt j;
386c9225affSStefano Zampini 
387c9225affSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
388c9225affSStefano Zampini         PetscInt  i2   = jj[j], p, p2;
389fabe8965SStefano Zampini         PetscReal scal = 0.0;
390c9225affSStefano Zampini 
391c9225affSStefano Zampini         for (p = 0; p < ecount[i]; p++) {
392c9225affSStefano Zampini           for (p2 = 0; p2 < ecount[i2]; p2++) {
3939371c9d4SSatish Balay             if (eneighs[i][p] == eneighs[i2][p2]) {
3949371c9d4SSatish Balay               scal += 1.0;
3959371c9d4SSatish Balay               break;
3969371c9d4SSatish Balay             }
397c9225affSStefano Zampini           }
398c9225affSStefano Zampini         }
399fabe8965SStefano Zampini         if (scal) aa[j] /= scal;
400c9225affSStefano Zampini       }
401c9225affSStefano Zampini     }
402c9225affSStefano Zampini   }
4039566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
4049566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
4059566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
40608401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
4073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
408c9225affSStefano Zampini }
409c9225affSStefano Zampini 
4109371c9d4SSatish Balay typedef enum {
4119371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_NATURAL,
4129371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_MAT,
4139371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_ND
4149371c9d4SSatish Balay } MatISDisassemblel2gType;
415fabe8965SStefano Zampini 
416d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
417d71ae5a4SJacob Faibussowitsch {
418fabe8965SStefano Zampini   Mat                     Ad, Ao;
419fabe8965SStefano Zampini   IS                      is, ndmap, ndsub;
420c9225affSStefano Zampini   MPI_Comm                comm;
421fabe8965SStefano Zampini   const PetscInt         *garray, *ndmapi;
422fabe8965SStefano Zampini   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
423fabe8965SStefano Zampini   PetscBool               ismpiaij, ismpibaij;
424f4259b30SLisandro Dalcin   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
425fabe8965SStefano Zampini   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
426fabe8965SStefano Zampini   MatPartitioning         part;
427fabe8965SStefano Zampini   PetscSF                 sf;
42891d376acSStefano Zampini   PetscObject             dm;
429c9225affSStefano Zampini 
430c9225affSStefano Zampini   PetscFunctionBegin;
431d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
4329566063dSJacob 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));
433d0609cedSBarry Smith   PetscOptionsEnd();
434fabe8965SStefano Zampini   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
4359566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
4363ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
437c9225affSStefano Zampini   }
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4399566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
4409566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
4419566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
442fabe8965SStefano Zampini   switch (mode) {
443fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_ND:
4449566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(comm, &part));
4459566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(part, A));
4469566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
4479566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(part));
4489566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApplyND(part, &ndmap));
4499566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&part));
4509566063dSJacob Faibussowitsch     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
4519566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
4529566063dSJacob Faibussowitsch     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
4539566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
454fabe8965SStefano Zampini 
455fabe8965SStefano Zampini     /* it may happen that a separator node is not properly shared */
4569566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
4579566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &sf));
4589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
4599566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
4609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
4619566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
4629566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4639566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4649566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
4659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ndmap, &ndmapi));
466fabe8965SStefano Zampini     for (i = 0, cnt = 0; i < A->rmap->n; i++)
4679371c9d4SSatish Balay       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
468fabe8965SStefano Zampini 
469462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
470fabe8965SStefano Zampini     if (i) { /* we detected isolated separator nodes */
471fabe8965SStefano Zampini       Mat                    A2, A3;
472fabe8965SStefano Zampini       IS                    *workis, is2;
473fabe8965SStefano Zampini       PetscScalar           *vals;
474fabe8965SStefano Zampini       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
475fabe8965SStefano Zampini       ISLocalToGlobalMapping ll2g;
476fabe8965SStefano Zampini       PetscBool              flg;
477fabe8965SStefano Zampini       const PetscInt        *ii, *jj;
478fabe8965SStefano Zampini 
479fabe8965SStefano Zampini       /* communicate global id of separators */
480d0609cedSBarry Smith       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
4819371c9d4SSatish Balay       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
482fabe8965SStefano Zampini 
4839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl, &lndmapi));
4849566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
485fabe8965SStefano Zampini 
486fabe8965SStefano Zampini       /* compute adjacency of isolated separators node */
4879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(gcnt, &workis));
488fabe8965SStefano Zampini       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
48948a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
490fabe8965SStefano Zampini       }
49148a46eb9SPierre Jolivet       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
492fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4939566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
4949566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
495fabe8965SStefano Zampini       }
496fabe8965SStefano Zampini 
497fabe8965SStefano Zampini       /* no communications since all the ISes correspond to locally owned rows */
4989566063dSJacob Faibussowitsch       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
499fabe8965SStefano Zampini 
500fabe8965SStefano Zampini       /* end communicate global id of separators */
5019566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
502fabe8965SStefano Zampini 
503fabe8965SStefano Zampini       /* communicate new layers : create a matrix and transpose it */
5049566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(dnz, A->rmap->n));
5059566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(onz, A->rmap->n));
506fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) {
507fabe8965SStefano Zampini         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
508fabe8965SStefano Zampini           const PetscInt *idxs;
509fabe8965SStefano Zampini           PetscInt        s;
510fabe8965SStefano Zampini 
5119566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(workis[j], &s));
5129566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5139566063dSJacob Faibussowitsch           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
514fabe8965SStefano Zampini           j++;
515fabe8965SStefano Zampini         }
516fabe8965SStefano Zampini       }
51708401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
518fabe8965SStefano Zampini 
519fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
5209566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
5219566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
522fabe8965SStefano Zampini       }
523fabe8965SStefano Zampini 
524fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
5259566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(j, &vals));
526fabe8965SStefano Zampini       for (i = 0; i < j; i++) vals[i] = 1.0;
527fabe8965SStefano Zampini 
5289566063dSJacob Faibussowitsch       PetscCall(MatCreate(comm, &A2));
5299566063dSJacob Faibussowitsch       PetscCall(MatSetType(A2, MATMPIAIJ));
5309566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
5319566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
5329566063dSJacob Faibussowitsch       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
533fabe8965SStefano Zampini       for (i = 0, j = 0; i < A2->rmap->n; i++) {
534fabe8965SStefano Zampini         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
535fabe8965SStefano Zampini         const PetscInt *idxs;
536fabe8965SStefano Zampini 
537fabe8965SStefano Zampini         if (s) {
5389566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5399566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
5409566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(workis[j], &idxs));
541fabe8965SStefano Zampini           j++;
542fabe8965SStefano Zampini         }
543fabe8965SStefano Zampini       }
54408401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
5459566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
5469566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
5479566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
5489566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
549fabe8965SStefano Zampini 
550fabe8965SStefano Zampini       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
551fabe8965SStefano Zampini       for (i = 0, j = 0; i < nl; i++)
552fabe8965SStefano Zampini         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
5539566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
5549566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
5559566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5569566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A2));
557fabe8965SStefano Zampini 
558fabe8965SStefano Zampini       /* extend local to global map to include connected isolated separators */
5599566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
56028b400f6SJacob Faibussowitsch       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
5619566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
5629566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
56328b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5649566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
5659566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
56628b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5679566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
5689566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
570fabe8965SStefano Zampini 
571fabe8965SStefano Zampini       /* add new nodes to the local-to-global map */
5729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
5739566063dSJacob Faibussowitsch       PetscCall(ISExpand(ndsub, is2, &is));
5749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is2));
5759566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5769566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
577fabe8965SStefano Zampini 
5789566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A3));
5799566063dSJacob Faibussowitsch       PetscCall(PetscFree(lndmapi));
580d0609cedSBarry Smith       MatPreallocateEnd(dnz, onz);
58148a46eb9SPierre Jolivet       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
5829566063dSJacob Faibussowitsch       PetscCall(PetscFree(workis));
583fabe8965SStefano Zampini     }
5849566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
5859566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
5869566063dSJacob Faibussowitsch     PetscCall(PetscFree(ndmapc));
5879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndmap));
5889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndsub));
5899566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
5904f58015eSStefano Zampini     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-mat_is_nd_l2g_view"));
591fabe8965SStefano Zampini     break;
592fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
593835f2295SStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", &dm));
59491d376acSStefano Zampini     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
59591d376acSStefano Zampini       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
59691d376acSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*l2g));
5973ba16761SJacob Faibussowitsch       if (*l2g) PetscFunctionReturn(PETSC_SUCCESS);
59891d376acSStefano Zampini     }
599fabe8965SStefano Zampini     if (ismpiaij) {
6009566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
601fabe8965SStefano Zampini     } else if (ismpibaij) {
6029566063dSJacob Faibussowitsch       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
60398921bdaSJacob Faibussowitsch     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
604c9225affSStefano Zampini     if (A->rmap->n) {
605fabe8965SStefano Zampini       PetscInt dc, oc, stc, *aux;
606c9225affSStefano Zampini 
607ebf8cefbSJunchao Zhang       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
6089566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
609d0dbe9f7SStefano Zampini       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
6109566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
6119566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
612c9225affSStefano Zampini       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
613ebf8cefbSJunchao Zhang       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
6149566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
615c9225affSStefano Zampini     } else {
6169566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
617c9225affSStefano Zampini     }
6189566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
6199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
620fabe8965SStefano Zampini     break;
621d71ae5a4SJacob Faibussowitsch   default:
622d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
623c9225affSStefano Zampini   }
6243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
625c9225affSStefano Zampini }
626c9225affSStefano Zampini 
627d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
628d71ae5a4SJacob Faibussowitsch {
629c9225affSStefano Zampini   Mat                    lA, Ad, Ao, B = NULL;
6306989cf23SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
6316989cf23SStefano Zampini   IS                     is;
6326989cf23SStefano Zampini   MPI_Comm               comm;
6336989cf23SStefano Zampini   void                  *ptrs[2];
6346989cf23SStefano Zampini   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
635c9225affSStefano Zampini   const PetscInt        *garray;
6366989cf23SStefano Zampini   PetscScalar           *dd, *od, *aa, *data;
637c9225affSStefano Zampini   const PetscInt        *di, *dj, *oi, *oj;
638c9225affSStefano Zampini   const PetscInt        *odi, *odj, *ooi, *ooj;
6396989cf23SStefano Zampini   PetscInt              *aux, *ii, *jj;
640a50ef18cSStefano Zampini   PetscInt               rbs, cbs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
641a50ef18cSStefano Zampini   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE, cong;
642c9225affSStefano Zampini   PetscMPIInt            size;
6436989cf23SStefano Zampini 
644ab4d48faSStefano Zampini   PetscFunctionBegin;
6459566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
6469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
647c9225affSStefano Zampini   if (size == 1) {
6489566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
6493ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
650c9225affSStefano Zampini   }
651a50ef18cSStefano Zampini   PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
652a50ef18cSStefano Zampini   PetscCall(MatHasCongruentLayouts(A, &cong));
653a50ef18cSStefano Zampini   if (reuse != MAT_REUSE_MATRIX && cong && rbs == cbs) {
6549566063dSJacob Faibussowitsch     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
6559566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
6569566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
657a50ef18cSStefano Zampini     PetscCall(MatSetSizes(B, A->rmap->n, A->rmap->n, A->rmap->N, A->rmap->N));
6589566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
659a50ef18cSStefano Zampini     PetscCall(MatSetBlockSizes(B, rbs, rbs));
6609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
661c9225affSStefano Zampini     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
662c9225affSStefano Zampini     reuse = MAT_REUSE_MATRIX;
663c9225affSStefano Zampini   }
664c9225affSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
665c9225affSStefano Zampini     Mat            *newlA, lA;
666c9225affSStefano Zampini     IS              rows, cols;
667c9225affSStefano Zampini     const PetscInt *ridx, *cidx;
668a50ef18cSStefano Zampini     PetscInt        nr, nc;
669c9225affSStefano Zampini 
670c9225affSStefano Zampini     if (!B) B = *newmat;
6719566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
6729566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
6739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
6749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
6759566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
6769566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
6779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
6789566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
679c9225affSStefano Zampini     if (rl2g != cl2g) {
6809566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
681c9225affSStefano Zampini     } else {
6829566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)rows));
683c9225affSStefano Zampini       cols = rows;
684c9225affSStefano Zampini     }
6859566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(B, &lA));
6869566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
6879566063dSJacob Faibussowitsch     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
6889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
6899566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
6909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rows));
6919566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cols));
692c9225affSStefano Zampini     if (!lA->preallocated) { /* first time */
6939566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
6949566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(B, lA));
6959566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)lA));
696c9225affSStefano Zampini     }
6979566063dSJacob Faibussowitsch     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
6989566063dSJacob Faibussowitsch     PetscCall(MatDestroySubMatrices(1, &newlA));
6999566063dSJacob Faibussowitsch     PetscCall(MatISScaleDisassembling_Private(B));
7009566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
7019566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
7029566063dSJacob Faibussowitsch     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
703c9225affSStefano Zampini     else *newmat = B;
7043ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
705c9225affSStefano Zampini   }
706a50ef18cSStefano Zampini   /* general case, just compress out the column space */
7079566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
7089566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
709c9225affSStefano Zampini   if (ismpiaij) {
710a50ef18cSStefano Zampini     cbs = 1; /* We cannot guarantee the off-process matrix will respect the column block size */
7119566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
712c9225affSStefano Zampini   } else if (ismpibaij) {
7139566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
7149566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
7159566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
71698921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
7179566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ad, &dd));
7189566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ao, &od));
7196989cf23SStefano Zampini 
7206989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
7219566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
7229566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
723a50ef18cSStefano Zampini   PetscCall(MatGetLocalSize(Ad, &dr, &dc));
7249566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
725d72e20dbSStefano Zampini   PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
726d72e20dbSStefano Zampini 
7279566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
72828b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
7299566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
73028b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
731c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
732c9225affSStefano Zampini   /* store original pointers to be restored later */
7339371c9d4SSatish Balay   odi = di;
7349371c9d4SSatish Balay   odj = dj;
7359371c9d4SSatish Balay   ooi = oi;
7369371c9d4SSatish Balay   ooj = oj;
7376989cf23SStefano Zampini 
7386989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
739a50ef18cSStefano Zampini   PetscCall(ISCreateStride(comm, dr / rbs, str / rbs, 1, &is));
740a50ef18cSStefano Zampini   if (rbs > 1) {
741c9225affSStefano Zampini     IS is2;
742c9225affSStefano Zampini 
7439566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
745a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, rbs, i, aux, PETSC_COPY_VALUES, &is2));
7469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
748c9225affSStefano Zampini     is = is2;
749c9225affSStefano Zampini   }
7509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
752e363d98aSStefano Zampini   if (dr) {
753a50ef18cSStefano Zampini     PetscCall(PetscMalloc1((dc + oc) / cbs, &aux));
754a50ef18cSStefano Zampini     for (i = 0; i < dc / cbs; i++) aux[i] = i + stc / cbs;
755a50ef18cSStefano Zampini     for (i = 0; i < oc / cbs; i++) aux[i + dc / cbs] = garray[i];
756a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, cbs, (dc + oc) / cbs, aux, PETSC_OWN_POINTER, &is));
757e363d98aSStefano Zampini     lc = dc + oc;
758e363d98aSStefano Zampini   } else {
759a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, cbs, 0, NULL, PETSC_OWN_POINTER, &is));
760e363d98aSStefano Zampini     lc = 0;
761e363d98aSStefano Zampini   }
7629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7639566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7646989cf23SStefano Zampini 
7656989cf23SStefano Zampini   /* create MATIS object */
7669566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7679566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7689566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
769a50ef18cSStefano Zampini   PetscCall(MatSetBlockSizes(B, rbs, cbs));
7709566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7736989cf23SStefano Zampini 
7746989cf23SStefano Zampini   /* merge local matrices */
7759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7776989cf23SStefano Zampini   ii  = aux;
7786989cf23SStefano Zampini   jj  = aux + dr + 1;
7796989cf23SStefano Zampini   aa  = data;
7806989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7819371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7829371c9d4SSatish Balay     for (; jd < *di; jd++) {
7839371c9d4SSatish Balay       *jj++ = *dj++;
7849371c9d4SSatish Balay       *aa++ = *dd++;
7859371c9d4SSatish Balay     }
7869371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7879371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7889371c9d4SSatish Balay       *aa++ = *od++;
7899371c9d4SSatish Balay     }
7906989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7916989cf23SStefano Zampini   }
7926989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
793c9225affSStefano Zampini 
7949566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
79528b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7969566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
79728b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7989566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7999566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
800c9225affSStefano Zampini 
8016989cf23SStefano Zampini   ii = aux;
8026989cf23SStefano Zampini   jj = aux + dr + 1;
8036989cf23SStefano Zampini   aa = data;
8049566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
8056989cf23SStefano Zampini 
8066989cf23SStefano Zampini   /* create containers to destroy the data */
8076989cf23SStefano Zampini   ptrs[0] = aux;
8086989cf23SStefano Zampini   ptrs[1] = data;
80949abdd8aSBarry Smith   for (i = 0; i < 2; i++) PetscCall(PetscObjectContainerCompose((PetscObject)lA, names[i], ptrs[i], PetscCtxDestroyDefault));
810c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
8119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
8129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
813c9225affSStefano Zampini   }
8146989cf23SStefano Zampini 
8156989cf23SStefano Zampini   /* finalize matrix */
8169566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
8179566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
8189566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
8199566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
820ac530a7eSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
821ac530a7eSPierre Jolivet   else *newmat = B;
8223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8236989cf23SStefano Zampini }
8246989cf23SStefano Zampini 
825d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
826d71ae5a4SJacob Faibussowitsch {
8275e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8285e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8295e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8305e3038f0Sstefano_zampini   MPI_Comm               comm;
8315b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8325b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8339e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8344f58015eSStefano Zampini   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
8355e3038f0Sstefano_zampini 
836ab4d48faSStefano Zampini   PetscFunctionBegin;
8379566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8385e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8395e3038f0Sstefano_zampini   rnest  = NULL;
8405e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8415e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8425e3038f0Sstefano_zampini 
8439566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
844f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8459566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8469566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8475e3038f0Sstefano_zampini     if (isnest) {
8489566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8495e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8505e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8515e3038f0Sstefano_zampini     }
8525e3038f0Sstefano_zampini   }
8539566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8549566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8559566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8569566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8575e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8585e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8594f58015eSStefano Zampini       PetscBool ismatis, sallow;
8609e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8615e3038f0Sstefano_zampini 
8625e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8635e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8645e3038f0Sstefano_zampini 
8655e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
866013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8679e7b2b25Sstefano_zampini       if (istrans[ij]) {
8689e7b2b25Sstefano_zampini         Mat T, lT;
8699566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8709566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
87128b400f6SJacob 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);
8724f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(T, &sallow));
8739566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8749566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8759e7b2b25Sstefano_zampini       } else {
8769566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
87728b400f6SJacob 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);
8784f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
8799566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8809e7b2b25Sstefano_zampini       }
8814f58015eSStefano Zampini       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
8824f58015eSStefano Zampini       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
8835e3038f0Sstefano_zampini 
8845e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8859566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8869566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8875e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
888aed4548fSBarry 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);
889aed4548fSBarry 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);
8905e3038f0Sstefano_zampini       lr[i] = l1;
8915e3038f0Sstefano_zampini       lc[j] = l2;
8925e3038f0Sstefano_zampini 
893da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8945e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8955e3038f0Sstefano_zampini     }
8965e3038f0Sstefano_zampini   }
8975e3038f0Sstefano_zampini 
89876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8995e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
9005e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
9015e3038f0Sstefano_zampini       rl2g = NULL;
9025e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
9035e3038f0Sstefano_zampini         PetscInt n1, n2;
9045e3038f0Sstefano_zampini 
9055e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
9069e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
9079e7b2b25Sstefano_zampini           Mat T;
9089e7b2b25Sstefano_zampini 
9099566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
9109566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
9119e7b2b25Sstefano_zampini         } else {
9129566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
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 row l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, 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 row l2gmap", i, j);
9305e3038f0Sstefano_zampini         }
9315e3038f0Sstefano_zampini       }
9325e3038f0Sstefano_zampini     }
9335e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9345e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9355e3038f0Sstefano_zampini       rl2g = NULL;
9365e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9375e3038f0Sstefano_zampini         PetscInt n1, n2;
9385e3038f0Sstefano_zampini 
9395e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9409e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9419e7b2b25Sstefano_zampini           Mat T;
9429e7b2b25Sstefano_zampini 
9439566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9449566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9459e7b2b25Sstefano_zampini         } else {
9469566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9479e7b2b25Sstefano_zampini         }
9489566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9495e3038f0Sstefano_zampini         if (!n1) continue;
9505e3038f0Sstefano_zampini         if (!rl2g) {
9515e3038f0Sstefano_zampini           rl2g = cl2g;
9525e3038f0Sstefano_zampini         } else {
9535e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9545e3038f0Sstefano_zampini           PetscBool       same;
9555e3038f0Sstefano_zampini 
9569566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
95708401ef6SPierre 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);
9589566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9599566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9609566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9619566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9629566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
96328b400f6SJacob 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);
9645e3038f0Sstefano_zampini         }
9655e3038f0Sstefano_zampini       }
9665e3038f0Sstefano_zampini     }
96776bd3646SJed Brown   }
9685e3038f0Sstefano_zampini 
9695e3038f0Sstefano_zampini   B = NULL;
9705e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9715b003df0Sstefano_zampini     PetscInt stl;
9725b003df0Sstefano_zampini 
9735e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9745e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9765b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9775e3038f0Sstefano_zampini       Mat             usedmat;
9785e3038f0Sstefano_zampini       Mat_IS         *matis;
9795e3038f0Sstefano_zampini       const PetscInt *idxs;
9805e3038f0Sstefano_zampini 
9815e3038f0Sstefano_zampini       /* local IS for local NEST */
9829566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9835e3038f0Sstefano_zampini 
9845e3038f0Sstefano_zampini       /* l2gmap */
9855e3038f0Sstefano_zampini       j       = 0;
9865e3038f0Sstefano_zampini       usedmat = nest[i][j];
9879e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
98828b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9899e7b2b25Sstefano_zampini 
9909e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9919e7b2b25Sstefano_zampini         Mat T;
9929566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9939e7b2b25Sstefano_zampini         usedmat = T;
9949e7b2b25Sstefano_zampini       }
995f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9969566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9979e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9989566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9999566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10009e7b2b25Sstefano_zampini       } else {
10019566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10029566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10039e7b2b25Sstefano_zampini       }
10049566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
10055e3038f0Sstefano_zampini       stl += lr[i];
10065e3038f0Sstefano_zampini     }
10079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
10085e3038f0Sstefano_zampini 
10095e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
10105e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
10119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
10125b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
10135e3038f0Sstefano_zampini       Mat             usedmat;
10145e3038f0Sstefano_zampini       Mat_IS         *matis;
10155e3038f0Sstefano_zampini       const PetscInt *idxs;
10165e3038f0Sstefano_zampini 
10175e3038f0Sstefano_zampini       /* local IS for local NEST */
10189566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10195e3038f0Sstefano_zampini 
10205e3038f0Sstefano_zampini       /* l2gmap */
10215e3038f0Sstefano_zampini       j       = 0;
10225e3038f0Sstefano_zampini       usedmat = nest[j][i];
10239e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
102428b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10259e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10269e7b2b25Sstefano_zampini         Mat T;
10279566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10289e7b2b25Sstefano_zampini         usedmat = T;
10299e7b2b25Sstefano_zampini       }
1030f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10319566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10329e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10339566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10349566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10359e7b2b25Sstefano_zampini       } else {
10369566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10379566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10389e7b2b25Sstefano_zampini       }
10399566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10405e3038f0Sstefano_zampini       stl += lc[i];
10415e3038f0Sstefano_zampini     }
10429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10435e3038f0Sstefano_zampini 
10445e3038f0Sstefano_zampini     /* Create MATIS */
10459566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10469566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10479566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10489566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10499566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10509566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10514f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
10528546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1053f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
10540d2733adSStefano Zampini       matis->islocalref = B;
10558546b261SStefano Zampini     }
10569566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10579566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10599566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10609566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10619e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
106248a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10639e7b2b25Sstefano_zampini     }
10649566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10659566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10668546b261SStefano Zampini     { /* hack : setup of scatters done here */
1067f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10688546b261SStefano Zampini 
10690d2733adSStefano Zampini       matis->islocalref = NULL;
10709566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10718546b261SStefano Zampini     }
10729566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10739566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10745e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10759566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10765e3038f0Sstefano_zampini     } else {
10775e3038f0Sstefano_zampini       *newmat = B;
10785e3038f0Sstefano_zampini     }
10795e3038f0Sstefano_zampini   } else {
10805e3038f0Sstefano_zampini     if (lreuse) {
10819566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10825e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10835e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10845e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10859566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
108648a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10875e3038f0Sstefano_zampini           }
10885e3038f0Sstefano_zampini         }
10895e3038f0Sstefano_zampini       }
10905e3038f0Sstefano_zampini     } else {
10915b003df0Sstefano_zampini       PetscInt stl;
10925b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10939566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10945b003df0Sstefano_zampini         stl += lr[i];
10955e3038f0Sstefano_zampini       }
10965b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10979566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10985b003df0Sstefano_zampini         stl += lc[i];
10995e3038f0Sstefano_zampini       }
11009566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1101ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
110248a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1103ab4d48faSStefano Zampini       }
11049566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
11059566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
11065e3038f0Sstefano_zampini     }
11079566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
11089566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
11095e3038f0Sstefano_zampini   }
11105e3038f0Sstefano_zampini 
11115b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
11125b003df0Sstefano_zampini   convert = PETSC_FALSE;
11134f58015eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
11145b003df0Sstefano_zampini   if (convert) {
11155b003df0Sstefano_zampini     Mat              M;
11165b003df0Sstefano_zampini     MatISLocalFields lf;
11175b003df0Sstefano_zampini 
11189566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
11199566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
11209566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
11219566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
11225b003df0Sstefano_zampini 
11235b003df0Sstefano_zampini     /* attach local fields to the matrix */
11249566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11265b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11275b003df0Sstefano_zampini       PetscInt n, st;
11285b003df0Sstefano_zampini 
11299566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11309566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11325b003df0Sstefano_zampini     }
11335b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11345b003df0Sstefano_zampini       PetscInt n, st;
11355b003df0Sstefano_zampini 
11369566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11379566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11389566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11395b003df0Sstefano_zampini     }
11405b003df0Sstefano_zampini     lf->nr = nr;
11415b003df0Sstefano_zampini     lf->nc = nc;
114203e76207SPierre Jolivet     PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private));
11435b003df0Sstefano_zampini   }
11445b003df0Sstefano_zampini 
11455e3038f0Sstefano_zampini   /* Free workspace */
114648a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
114748a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11489566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11499566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11515e3038f0Sstefano_zampini }
11525e3038f0Sstefano_zampini 
1153d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1154d71ae5a4SJacob Faibussowitsch {
1155ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1156ad219c80Sstefano_zampini   Vec                ll, rr;
1157ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1158ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1159ad219c80Sstefano_zampini 
1160ad219c80Sstefano_zampini   PetscFunctionBegin;
1161ad219c80Sstefano_zampini   if (l) {
1162ad219c80Sstefano_zampini     ll = matis->y;
11639566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11649566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1166ad219c80Sstefano_zampini   } else {
1167ad219c80Sstefano_zampini     ll = NULL;
1168ad219c80Sstefano_zampini   }
1169ad219c80Sstefano_zampini   if (r) {
1170ad219c80Sstefano_zampini     rr = matis->x;
11719566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11729566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11739566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1174ad219c80Sstefano_zampini   } else {
1175ad219c80Sstefano_zampini     rr = NULL;
1176ad219c80Sstefano_zampini   }
1177ad219c80Sstefano_zampini   if (ll) {
11789566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11799566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11809566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1181ad219c80Sstefano_zampini   }
1182ad219c80Sstefano_zampini   if (rr) {
11839566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11849566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11859566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1186ad219c80Sstefano_zampini   }
11879566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1189ad219c80Sstefano_zampini }
1190ad219c80Sstefano_zampini 
1191d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1192d71ae5a4SJacob Faibussowitsch {
11937fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11947fa8f2d3SStefano Zampini   MatInfo        info;
11953966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11967fa8f2d3SStefano Zampini   PetscInt       bs;
11977fa8f2d3SStefano Zampini 
11987fa8f2d3SStefano Zampini   PetscFunctionBegin;
11999566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1200a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
12019566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
12027fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
12037fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
12047fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
12057fa8f2d3SStefano Zampini     isend[3] = info.memory;
12067fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1207a2ccb5f9Sstefano_zampini   } else {
1208a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1209a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1210a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1211a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1212a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1213a2ccb5f9Sstefano_zampini   }
1214314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
12157fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
12167fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
12177fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
12187fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
12197fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
12207fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1221314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
12227fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
1223462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12247fa8f2d3SStefano Zampini 
12257fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12267fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12277fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12287fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12297fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1230314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12317fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
1232462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12337fa8f2d3SStefano Zampini 
12347fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12357fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12367fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12377fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12387fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12397fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12407fa8f2d3SStefano Zampini   }
12417fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12427fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12437fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12447fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12465e3038f0Sstefano_zampini }
12475e3038f0Sstefano_zampini 
1248d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1249d71ae5a4SJacob Faibussowitsch {
1250d7f69cd0SStefano Zampini   Mat C, lC, lA;
1251d7f69cd0SStefano Zampini 
1252d7f69cd0SStefano Zampini   PetscFunctionBegin;
12537fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1254cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1255cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12564f58015eSStefano Zampini     PetscBool              allow_repeated;
12574f58015eSStefano Zampini 
12589566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12599566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
126058b7e2c1SStefano Zampini     PetscCall(MatSetBlockSizes(C, A->cmap->bs, A->rmap->bs));
12619566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12624f58015eSStefano Zampini     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
12634f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
12649566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12659566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1266e432b41dSStefano Zampini   } else C = *B;
1267d7f69cd0SStefano Zampini 
1268d7f69cd0SStefano Zampini   /* perform local transposition */
12699566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12709566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12719566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12729566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1274d7f69cd0SStefano Zampini 
1275cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1276d7f69cd0SStefano Zampini     *B = C;
1277d7f69cd0SStefano Zampini   } else {
12789566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1279d7f69cd0SStefano Zampini   }
12809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1283d7f69cd0SStefano Zampini }
1284d7f69cd0SStefano Zampini 
1285d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1286d71ae5a4SJacob Faibussowitsch {
12873fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12883fd1c9e7SStefano Zampini 
12893fd1c9e7SStefano Zampini   PetscFunctionBegin;
12904f58015eSStefano Zampini   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
12914b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12929566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12939566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12943fd1c9e7SStefano Zampini   }
12959566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12969566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12983fd1c9e7SStefano Zampini }
12993fd1c9e7SStefano Zampini 
1300d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1301d71ae5a4SJacob Faibussowitsch {
13024b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
13033fd1c9e7SStefano Zampini 
13043fd1c9e7SStefano Zampini   PetscFunctionBegin;
13059566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
13069566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
13073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13083fd1c9e7SStefano Zampini }
13093fd1c9e7SStefano Zampini 
1310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1311d71ae5a4SJacob Faibussowitsch {
1312*076fee34SStefano Zampini   PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL;
1313f26d0771SStefano Zampini 
1314f26d0771SStefano Zampini   PetscFunctionBegin;
1315*076fee34SStefano Zampini   IndexSpaceGet(buf, m, n, rows_l, cols_l);
13169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
13179566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
13189566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1319*076fee34SStefano Zampini   IndexSpaceRestore(buf, m, n, rows_l, cols_l);
13203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1321f26d0771SStefano Zampini }
1322f26d0771SStefano Zampini 
1323d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1324d71ae5a4SJacob Faibussowitsch {
1325*076fee34SStefano Zampini   PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL, rbs, cbs;
1326f26d0771SStefano Zampini 
1327f26d0771SStefano Zampini   PetscFunctionBegin;
1328*076fee34SStefano Zampini   /* We cannot guarantee the local matrix will have the same block size of the original matrix */
1329*076fee34SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockSize(A->rmap->mapping, &rbs));
1330*076fee34SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockSize(A->cmap->mapping, &cbs));
1331*076fee34SStefano Zampini   IndexSpaceGet(buf, m * rbs, n * cbs, rows_l, cols_l);
1332*076fee34SStefano Zampini   BlockIndicesExpand(m, rows, rbs, rows_l);
1333*076fee34SStefano Zampini   BlockIndicesExpand(n, cols, cbs, cols_l);
1334*076fee34SStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m * rbs, rows_l, rows_l));
1335*076fee34SStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n * cbs, cols_l, cols_l));
1336*076fee34SStefano Zampini   PetscCall(MatSetValuesLocal_IS(A, m * rbs, rows_l, n * cbs, cols_l, values, addv));
1337*076fee34SStefano Zampini   IndexSpaceRestore(buf, m * rbs, n * cbs, rows_l, cols_l);
13383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1339f26d0771SStefano Zampini }
1340f26d0771SStefano Zampini 
13410d2733adSStefano Zampini static PetscErrorCode MatZeroRowsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
13420d2733adSStefano Zampini {
13430d2733adSStefano Zampini   PetscInt *rows_l;
13440d2733adSStefano Zampini   Mat_IS   *is = (Mat_IS *)A->data;
13450d2733adSStefano Zampini 
13460d2733adSStefano Zampini   PetscFunctionBegin;
13470d2733adSStefano Zampini   PetscCall(PetscMalloc1(n, &rows_l));
13480d2733adSStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l));
13490d2733adSStefano Zampini   PetscCall(MatZeroRowsLocal(is->islocalref, n, rows_l, diag, x, b));
13500d2733adSStefano Zampini   PetscCall(PetscFree(rows_l));
13510d2733adSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
13520d2733adSStefano Zampini }
13530d2733adSStefano Zampini 
13540d2733adSStefano Zampini static PetscErrorCode MatZeroRowsColumnsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
13550d2733adSStefano Zampini {
13560d2733adSStefano Zampini   PetscInt *rows_l;
13570d2733adSStefano Zampini   Mat_IS   *is = (Mat_IS *)A->data;
13580d2733adSStefano Zampini 
13590d2733adSStefano Zampini   PetscFunctionBegin;
13600d2733adSStefano Zampini   PetscCall(PetscMalloc1(n, &rows_l));
13610d2733adSStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l));
13620d2733adSStefano Zampini   PetscCall(MatZeroRowsColumnsLocal(is->islocalref, n, rows_l, diag, x, b));
13630d2733adSStefano Zampini   PetscCall(PetscFree(rows_l));
13640d2733adSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
13650d2733adSStefano Zampini }
13660d2733adSStefano Zampini 
1367d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1368d71ae5a4SJacob Faibussowitsch {
1369a8116848SStefano Zampini   Mat             locmat, newlocmat;
1370a8116848SStefano Zampini   Mat_IS         *newmatis;
1371a8116848SStefano Zampini   const PetscInt *idxs;
1372a8116848SStefano Zampini   PetscInt        i, m, n;
1373a8116848SStefano Zampini 
1374a8116848SStefano Zampini   PetscFunctionBegin;
1375a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1376a8116848SStefano Zampini     PetscBool ismatis;
1377a8116848SStefano Zampini 
13789566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
137928b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1380a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
138128b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
138228b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1383a8116848SStefano Zampini   }
1384a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
138576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
138676bd3646SJed Brown     Vec                rtest, ltest;
138776bd3646SJed Brown     const PetscScalar *array;
138876bd3646SJed Brown 
13899566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13909566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13919566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
139248a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13939566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13949566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13959566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13969566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13979566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1398aed4548fSBarry 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]));
13999566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
14009566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
14019566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
14029566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
140348a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
14049566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
14059566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
14069566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
14079566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
14089566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1409aed4548fSBarry 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]));
14109566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
14119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
14129566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
14139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
141476bd3646SJed Brown   }
1415a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1416a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1417a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1418a8116848SStefano Zampini     IS                     is;
1419a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1420306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
142194342113SStefano Zampini     PetscBool              cong;
1422a8116848SStefano Zampini     MPI_Comm               comm;
1423a8116848SStefano Zampini 
14249566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
14259566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
14269566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
14279566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1428306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1429306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
14309566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
14319566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
14329566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
14339566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
14344f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
14359566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
14369566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1437a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
14389566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
14399566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
14409566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
14419566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1442a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14439566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
14449566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
14459566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14469566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14479371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
14489371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
14499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
14509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
14513d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1452a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1453a8116848SStefano Zampini         lidxs[newloc]      = i;
1454a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1455a8116848SStefano Zampini       }
14569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14579566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1460a8116848SStefano Zampini     /* local is to extract local submatrix */
1461a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14639566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
146494342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14659566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14669566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1467a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1468a8116848SStefano Zampini     } else {
1469a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1470a8116848SStefano Zampini 
1471a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14729566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14739566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14749566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14759566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1476a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14779566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14789566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14799566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14809566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14819371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14829371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14853d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1486a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1487a8116848SStefano Zampini           lidxs[newloc]      = i;
1488a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1489a8116848SStefano Zampini         }
14909566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14919566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14929566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14939566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1494a8116848SStefano Zampini       /* local is to extract local submatrix */
14959566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14969566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1498a8116848SStefano Zampini     }
14999566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1500a8116848SStefano Zampini   } else {
15019566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1502a8116848SStefano Zampini   }
15039566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1504a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
15059566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1506a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
15079566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
15089566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1509a8116848SStefano Zampini   }
15109566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
15119566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
15123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1513a8116848SStefano Zampini }
1514a8116848SStefano Zampini 
1515d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1516d71ae5a4SJacob Faibussowitsch {
15172b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
15182b404112SStefano Zampini   PetscBool ismatis;
15192b404112SStefano Zampini 
15202b404112SStefano Zampini   PetscFunctionBegin;
15219566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
152228b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
15232b404112SStefano Zampini   b = (Mat_IS *)B->data;
15249566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
15259566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
15263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15272b404112SStefano Zampini }
15282b404112SStefano Zampini 
1529d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1530d71ae5a4SJacob Faibussowitsch {
1531527b2640SStefano Zampini   Vec                v;
1532527b2640SStefano Zampini   const PetscScalar *array;
1533527b2640SStefano Zampini   PetscInt           i, n;
15346bd84002SStefano Zampini 
15356bd84002SStefano Zampini   PetscFunctionBegin;
1536527b2640SStefano Zampini   *missing = PETSC_FALSE;
15379566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
15389566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
15399566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
15409566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
15419371c9d4SSatish Balay   for (i = 0; i < n; i++)
15429371c9d4SSatish Balay     if (array[i] == 0.) break;
15439566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
15449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1545527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1546527b2640SStefano Zampini   if (d) {
1547527b2640SStefano Zampini     *d = -1;
1548527b2640SStefano Zampini     if (*missing) {
1549527b2640SStefano Zampini       PetscInt rstart;
15509566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1551527b2640SStefano Zampini       *d = i + rstart;
1552527b2640SStefano Zampini     }
1553527b2640SStefano Zampini   }
15543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15556bd84002SStefano Zampini }
15566bd84002SStefano Zampini 
1557d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1558d71ae5a4SJacob Faibussowitsch {
1559f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
156028f4e0baSStefano Zampini   const PetscInt *gidxs;
15614f2d7cafSStefano Zampini   PetscInt        nleaves;
156228f4e0baSStefano Zampini 
156328f4e0baSStefano Zampini   PetscFunctionBegin;
15643ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15659566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15679566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15689566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1571e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15729566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15739566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15759566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15769566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1578a8116848SStefano Zampini   } else {
1579a8116848SStefano Zampini     matis->csf          = matis->sf;
1580a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1581a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1582a8116848SStefano Zampini   }
15833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
158428f4e0baSStefano Zampini }
15852e1947a5SStefano Zampini 
1586eb82efa4SStefano Zampini /*@
15874f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15884f58015eSStefano Zampini 
15894f58015eSStefano Zampini   Not Collective
15904f58015eSStefano Zampini 
15914f58015eSStefano Zampini   Input Parameter:
15924f58015eSStefano Zampini . A - the matrix
15934f58015eSStefano Zampini 
15944f58015eSStefano Zampini   Output Parameter:
15954f58015eSStefano Zampini . flg - the boolean flag
15964f58015eSStefano Zampini 
15974f58015eSStefano Zampini   Level: intermediate
15984f58015eSStefano Zampini 
15994f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
16004f58015eSStefano Zampini @*/
16014f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
16024f58015eSStefano Zampini {
16034f58015eSStefano Zampini   PetscBool ismatis;
16044f58015eSStefano Zampini 
16054f58015eSStefano Zampini   PetscFunctionBegin;
16064f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
16074f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
16084f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
16094f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
16104f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
16114f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16124f58015eSStefano Zampini }
16134f58015eSStefano Zampini 
16144f58015eSStefano Zampini /*@
16154f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
16164f58015eSStefano Zampini 
16174f58015eSStefano Zampini   Logically Collective
16184f58015eSStefano Zampini 
16194f58015eSStefano Zampini   Input Parameters:
16204f58015eSStefano Zampini + A   - the matrix
16214f58015eSStefano Zampini - flg - the boolean flag
16224f58015eSStefano Zampini 
16234f58015eSStefano Zampini   Level: intermediate
16244f58015eSStefano Zampini 
16254f58015eSStefano Zampini   Notes:
16264f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
16274f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
16284f58015eSStefano Zampini   if `flg` is different from the previously set value.
16294f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
16304f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
16314f58015eSStefano Zampini 
16324f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
16334f58015eSStefano Zampini @*/
16344f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
16354f58015eSStefano Zampini {
16364f58015eSStefano Zampini   PetscFunctionBegin;
16374f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
16384f58015eSStefano Zampini   PetscValidType(A, 1);
16394f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
16404f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
16414f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16424f58015eSStefano Zampini }
16434f58015eSStefano Zampini 
16444f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
16454f58015eSStefano Zampini {
16464f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
16474f58015eSStefano Zampini   Mat                    lA    = NULL;
16484f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
16494f58015eSStefano Zampini 
16504f58015eSStefano Zampini   PetscFunctionBegin;
16514f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
16524f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
16534f58015eSStefano Zampini     matis->allow_repeated = flg;
16544f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
16554f58015eSStefano Zampini   }
16564f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16574f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16584f58015eSStefano Zampini     lA = matis->A;
16594f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16604f58015eSStefano Zampini   }
16614f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16624f58015eSStefano Zampini   matis->allow_repeated = flg;
16634f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16644f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16654f58015eSStefano Zampini     Mat nA = matis->A;
16664f58015eSStefano Zampini 
16674f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16684f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16694f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16704f58015eSStefano Zampini     } else {
16714f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16724f58015eSStefano Zampini       MatProductType ptype;
16734f58015eSStefano Zampini 
16744f58015eSStefano Zampini       if (lrmap == lcmap) {
16754f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16764f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16774f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16784f58015eSStefano Zampini       } else {
16794f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16804f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16814f58015eSStefano Zampini         if (R && P) {
16824f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16834f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16844f58015eSStefano Zampini         } else if (R) {
16854f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16864f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16874f58015eSStefano Zampini         } else {
16884f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16894f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16904f58015eSStefano Zampini         }
16914f58015eSStefano Zampini       }
16924f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16934f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16944f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16954f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16964f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16974f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16984f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16994f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
17004f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
17014f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
17024f58015eSStefano Zampini     }
17034f58015eSStefano Zampini   }
17044f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
17054f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
17064f58015eSStefano Zampini }
17074f58015eSStefano Zampini 
17084f58015eSStefano Zampini /*@
17092ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
171075d48cdbSStefano Zampini 
17114f58015eSStefano Zampini   Logically Collective
171275d48cdbSStefano Zampini 
171375d48cdbSStefano Zampini   Input Parameters:
171475d48cdbSStefano Zampini + A     - the matrix
171575d48cdbSStefano Zampini - store - the boolean flag
171675d48cdbSStefano Zampini 
171775d48cdbSStefano Zampini   Level: advanced
171875d48cdbSStefano Zampini 
17191cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
172075d48cdbSStefano Zampini @*/
1721d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1722d71ae5a4SJacob Faibussowitsch {
172375d48cdbSStefano Zampini   PetscFunctionBegin;
172475d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
172575d48cdbSStefano Zampini   PetscValidType(A, 1);
172675d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1727cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
17283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172975d48cdbSStefano Zampini }
173075d48cdbSStefano Zampini 
1731d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1732d71ae5a4SJacob Faibussowitsch {
1733f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
173475d48cdbSStefano Zampini 
173575d48cdbSStefano Zampini   PetscFunctionBegin;
173675d48cdbSStefano Zampini   matis->storel2l = store;
173757508eceSPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
17383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
173975d48cdbSStefano Zampini }
174075d48cdbSStefano Zampini 
174175d48cdbSStefano Zampini /*@
1742f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1743f03112d0SStefano Zampini 
17444f58015eSStefano Zampini   Logically Collective
1745f03112d0SStefano Zampini 
1746f03112d0SStefano Zampini   Input Parameters:
1747f03112d0SStefano Zampini + A   - the matrix
1748f03112d0SStefano Zampini - fix - the boolean flag
1749f03112d0SStefano Zampini 
1750f03112d0SStefano Zampini   Level: advanced
1751f03112d0SStefano Zampini 
175211a5261eSBarry Smith   Note:
17532fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1754f03112d0SStefano Zampini 
17551cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1756f03112d0SStefano Zampini @*/
1757d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1758d71ae5a4SJacob Faibussowitsch {
1759f03112d0SStefano Zampini   PetscFunctionBegin;
1760f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1761f03112d0SStefano Zampini   PetscValidType(A, 1);
1762f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1763cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1765f03112d0SStefano Zampini }
1766f03112d0SStefano Zampini 
1767d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1768d71ae5a4SJacob Faibussowitsch {
1769f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1770f03112d0SStefano Zampini 
1771f03112d0SStefano Zampini   PetscFunctionBegin;
1772f03112d0SStefano Zampini   matis->locempty = fix;
17733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1774f03112d0SStefano Zampini }
1775f03112d0SStefano Zampini 
1776f03112d0SStefano Zampini /*@
177711a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1778a88811baSStefano Zampini 
1779d083f849SBarry Smith   Collective
1780a88811baSStefano Zampini 
1781a88811baSStefano Zampini   Input Parameters:
1782a88811baSStefano Zampini + B     - the matrix
1783a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1784a88811baSStefano Zampini            (same value is used for all local rows)
1785a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1786a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17872ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17882ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1789a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1790a88811baSStefano Zampini            the diagonal entry even if it is zero.
1791a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1792a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1793a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1794a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17952ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1796a88811baSStefano Zampini            structure. The size of this array is equal to the number
17972ef1f0ffSBarry Smith            of local rows, i.e `m`.
1798a88811baSStefano Zampini 
1799a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1800a88811baSStefano Zampini 
1801a88811baSStefano Zampini   Level: intermediate
1802a88811baSStefano Zampini 
180311a5261eSBarry Smith   Note:
180411a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
180511a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1806a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1807a88811baSStefano Zampini 
18081cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1809a88811baSStefano Zampini @*/
1810d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1811d71ae5a4SJacob Faibussowitsch {
18122e1947a5SStefano Zampini   PetscFunctionBegin;
18132e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
18142e1947a5SStefano Zampini   PetscValidType(B, 1);
1815cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
18163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18172e1947a5SStefano Zampini }
18182e1947a5SStefano Zampini 
1819523895eeSPierre Jolivet static PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1820d71ae5a4SJacob Faibussowitsch {
1821f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
182228f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
18232e1947a5SStefano Zampini 
18242e1947a5SStefano Zampini   PetscFunctionBegin;
18259566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
18269371c9d4SSatish Balay   if (!d_nnz)
18279371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
18289371c9d4SSatish Balay   else
18299371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
18304f2d7cafSStefano Zampini 
18319371c9d4SSatish Balay   if (!o_nnz)
18329371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
18339371c9d4SSatish Balay   else
18349371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
18354f2d7cafSStefano Zampini 
18369566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18379566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
18389566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
18399566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18404f2d7cafSStefano Zampini 
18414f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
18429566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
18430f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
18449566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
18450f2f62c7SStefano Zampini #endif
18464f2d7cafSStefano Zampini 
1847fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1848fc989267SStefano Zampini     PetscInt b;
1849fc989267SStefano Zampini 
1850fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1851ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1852fc989267SStefano Zampini   }
18539566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18544f2d7cafSStefano Zampini 
185500a59248SStefano Zampini   nlocalcols /= bs;
185600a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18579566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18580f2f62c7SStefano Zampini 
18590f2f62c7SStefano Zampini   /* for other matrix types */
18609566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18622e1947a5SStefano Zampini }
1863b4319ba4SBarry Smith 
1864d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1865d71ae5a4SJacob Faibussowitsch {
1866f4f49eeaSPierre Jolivet   Mat_IS            *matis     = (Mat_IS *)mat->data;
1867ac7f1a8bSStefano Zampini   Mat                local_mat = NULL, MT;
186853b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1869b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1870b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1871f03112d0SStefano Zampini   PetscMPIInt        size;
18721683a169SBarry Smith   const PetscScalar *array;
1873b7ce53b6SStefano Zampini 
1874b7ce53b6SStefano Zampini   PetscFunctionBegin;
18759566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
18764f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
18771670daf9Sstefano_zampini     Mat      B;
187853b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1879487b449aSStefano Zampini     PetscInt rbs, cbs;
18801670daf9Sstefano_zampini 
18819566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
188353b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
188453b44cf5SStefano Zampini       IS              rows, cols;
188553b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
18864f58015eSStefano Zampini       PetscInt        i, nw;
18874f58015eSStefano Zampini       PetscBT         work;
188853b44cf5SStefano Zampini 
18899566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18909566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
189153b44cf5SStefano Zampini       nw = nw / rbs;
18924f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
18934f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
18949371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18954f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
189653b44cf5SStefano Zampini       if (i == nw) {
18979566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18989566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18999566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
19009566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
190153b44cf5SStefano Zampini       }
19029566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
19034f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
1904e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
19059566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
19069566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
190753b44cf5SStefano Zampini         nw = nw / cbs;
19084f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
19094f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
19109371c9d4SSatish Balay         for (i = 0; i < nw; i++)
19114f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
191253b44cf5SStefano Zampini         if (i == nw) {
19139566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
19149566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
19159566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
19169566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
191753b44cf5SStefano Zampini         }
19189566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
19194f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
192053b44cf5SStefano Zampini       } else if (irows) {
19219566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
192253b44cf5SStefano Zampini         icols = irows;
192353b44cf5SStefano Zampini       }
192453b44cf5SStefano Zampini     } else {
1925f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
1926f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
19279566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
19289566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
192953b44cf5SStefano Zampini     }
193053b44cf5SStefano Zampini     if (!irows || !icols) {
19319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
19329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
193353b44cf5SStefano Zampini       goto general_assembly;
193453b44cf5SStefano Zampini     }
19359566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1936487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
19379566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
1938f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
1939f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1940487b449aSStefano Zampini     } else {
1941487b449aSStefano Zampini       Mat C;
1942487b449aSStefano Zampini 
19439566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
19449566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1945487b449aSStefano Zampini     }
19469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
19479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
19489566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
19493ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19507c03b4e8SStefano Zampini   }
195153b44cf5SStefano Zampini general_assembly:
19529566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19559566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19569566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19579566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19589566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19599566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19609566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1961f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
196276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
196376bd3646SJed Brown     PetscBool lb[4], bb[4];
196476bd3646SJed Brown 
1965b9ed4604SStefano Zampini     lb[0] = isseqdense;
1966b9ed4604SStefano Zampini     lb[1] = isseqaij;
1967b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1968b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
19695440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1970aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
197176bd3646SJed Brown   }
1972b7ce53b6SStefano Zampini 
1973487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
1974ac7f1a8bSStefano Zampini     PetscCount ncoo;
1975ac7f1a8bSStefano Zampini     PetscInt  *coo_i, *coo_j;
1976ac7f1a8bSStefano Zampini 
19779566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19789566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19799566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19809566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
1981ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
1982ac7f1a8bSStefano Zampini       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1983ac7f1a8bSStefano Zampini     } else {
1984ac7f1a8bSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
1985ac7f1a8bSStefano Zampini       local_mat = matis->A;
1986ac7f1a8bSStefano Zampini     }
1987ac7f1a8bSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1988ac7f1a8bSStefano Zampini     if (isseqdense) {
1989ac7f1a8bSStefano Zampini       PetscInt nr, nc;
1990ac7f1a8bSStefano Zampini 
1991ac7f1a8bSStefano Zampini       PetscCall(MatGetSize(local_mat, &nr, &nc));
1992ac7f1a8bSStefano Zampini       ncoo = nr * nc;
1993ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1994ac7f1a8bSStefano Zampini       for (PetscInt j = 0; j < nc; j++) {
1995ac7f1a8bSStefano Zampini         for (PetscInt i = 0; i < nr; i++) {
1996ac7f1a8bSStefano Zampini           coo_i[j * nr + i] = i;
1997ac7f1a8bSStefano Zampini           coo_j[j * nr + i] = j;
1998ac7f1a8bSStefano Zampini         }
1999ac7f1a8bSStefano Zampini       }
2000ac7f1a8bSStefano Zampini     } else {
2001ac7f1a8bSStefano Zampini       const PetscInt *ii, *jj;
2002ac7f1a8bSStefano Zampini       PetscInt        nr;
2003ac7f1a8bSStefano Zampini       PetscBool       done;
2004ac7f1a8bSStefano Zampini 
2005ac7f1a8bSStefano Zampini       PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
2006ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
2007ac7f1a8bSStefano Zampini       ncoo = ii[nr];
2008ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
2009ac7f1a8bSStefano Zampini       PetscCall(PetscArraycpy(coo_j, jj, ncoo));
2010ac7f1a8bSStefano Zampini       for (PetscInt i = 0; i < nr; i++) {
2011ac7f1a8bSStefano Zampini         for (PetscInt j = ii[i]; j < ii[i + 1]; j++) coo_i[j] = i;
2012ac7f1a8bSStefano Zampini       }
2013ac7f1a8bSStefano Zampini       PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
2014ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
2015ac7f1a8bSStefano Zampini     }
2016ac7f1a8bSStefano Zampini     PetscCall(MatSetPreallocationCOOLocal(MT, ncoo, coo_i, coo_j));
2017ac7f1a8bSStefano Zampini     PetscCall(PetscFree2(coo_i, coo_j));
2018b7ce53b6SStefano Zampini   } else {
201953b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
2020487b449aSStefano Zampini 
2021b7ce53b6SStefano Zampini     /* some checks */
2022487b449aSStefano Zampini     MT = *M;
20239566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
20249566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
20259566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
202608401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
202708401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
202808401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
202908401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
203008401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
203108401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
20329566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
2033ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
20349566063dSJacob Faibussowitsch       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
2035d9a9e74cSStefano Zampini     } else {
20369566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)matis->A));
2037d9a9e74cSStefano Zampini       local_mat = matis->A;
2038d9a9e74cSStefano Zampini     }
2039ac7f1a8bSStefano Zampini   }
2040686e3a49SStefano Zampini 
2041b7ce53b6SStefano Zampini   /* Set values */
2042ac7f1a8bSStefano Zampini   if (isseqdense) {
20439566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
2044ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
20459566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
20466afe12f5SStefano Zampini   } else {
2047ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(local_mat, &array));
2048ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
2049ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(local_mat, &array));
2050b7ce53b6SStefano Zampini   }
20519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20524f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20539566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
2054487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20559566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2056487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2057487b449aSStefano Zampini     *M = MT;
2058b7ce53b6SStefano Zampini   }
20593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2060b7ce53b6SStefano Zampini }
2061b7ce53b6SStefano Zampini 
2062d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2063d71ae5a4SJacob Faibussowitsch {
2064f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2065c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2066ad6194a2SStefano Zampini   Mat      B, localmat;
2067ad6194a2SStefano Zampini 
2068ad6194a2SStefano Zampini   PetscFunctionBegin;
20699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20719566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20729566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20739566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20749566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20759566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20769566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20779566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20784f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
20799566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20809566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
20819566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
20829566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
20839566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
20849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
20859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2086ad6194a2SStefano Zampini   *newmat = B;
20873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2088ad6194a2SStefano Zampini }
2089ad6194a2SStefano Zampini 
2090d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2091d71ae5a4SJacob Faibussowitsch {
209269796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
209369796d55SStefano Zampini   PetscBool local_sym;
209469796d55SStefano Zampini 
209569796d55SStefano Zampini   PetscFunctionBegin;
20969566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
20975440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
209969796d55SStefano Zampini }
210069796d55SStefano Zampini 
2101d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2102d71ae5a4SJacob Faibussowitsch {
210369796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
210469796d55SStefano Zampini   PetscBool local_sym;
210569796d55SStefano Zampini 
210669796d55SStefano Zampini   PetscFunctionBegin;
2107e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2108e432b41dSStefano Zampini     *flg = PETSC_FALSE;
21093ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2110e432b41dSStefano Zampini   }
21119566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
21125440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
21133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
211469796d55SStefano Zampini }
211569796d55SStefano Zampini 
2116d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2117d71ae5a4SJacob Faibussowitsch {
211845471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
211945471136SStefano Zampini   PetscBool local_sym;
212045471136SStefano Zampini 
212145471136SStefano Zampini   PetscFunctionBegin;
2122e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
212345471136SStefano Zampini     *flg = PETSC_FALSE;
21243ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
212545471136SStefano Zampini   }
21269566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
21275440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
21283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
212945471136SStefano Zampini }
213045471136SStefano Zampini 
2131d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2132d71ae5a4SJacob Faibussowitsch {
2133b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2134b4319ba4SBarry Smith 
2135b4319ba4SBarry Smith   PetscFunctionBegin;
21369566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21379566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21399566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21409566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21419566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2146a8116848SStefano Zampini   if (b->sf != b->csf) {
21479566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21489566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2149f03112d0SStefano Zampini   } else b->csf = NULL;
21509566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2154d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2155d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21569566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21579566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21612e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
21764f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
21773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2178b4319ba4SBarry Smith }
2179b4319ba4SBarry Smith 
2180d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2181d71ae5a4SJacob Faibussowitsch {
2182b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2183b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2184b4319ba4SBarry Smith 
2185b4319ba4SBarry Smith   PetscFunctionBegin;
2186b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
21879566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
21889566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2189b4319ba4SBarry Smith 
2190b4319ba4SBarry Smith   /* multiply the local matrix */
21919566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2192b4319ba4SBarry Smith 
2193b4319ba4SBarry Smith   /* scatter product back into global memory */
21949566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
21959566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21969566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2198b4319ba4SBarry Smith }
2199b4319ba4SBarry Smith 
2200d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2201d71ae5a4SJacob Faibussowitsch {
2202650997f4SStefano Zampini   Vec temp_vec;
22032e74eeadSLisandro Dalcin 
22042e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2205650997f4SStefano Zampini   if (v3 != v2) {
22069566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
22079566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2208650997f4SStefano Zampini   } else {
22099566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22109566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
22119566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22129566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2214650997f4SStefano Zampini   }
22153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22162e74eeadSLisandro Dalcin }
22172e74eeadSLisandro Dalcin 
2218d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2219d71ae5a4SJacob Faibussowitsch {
22202e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
22212e74eeadSLisandro Dalcin 
2222e176bc59SStefano Zampini   PetscFunctionBegin;
22232e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
22249566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22259566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22262e74eeadSLisandro Dalcin 
22272e74eeadSLisandro Dalcin   /* multiply the local matrix */
22289566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
22292e74eeadSLisandro Dalcin 
22302e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22319566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22329566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22339566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22352e74eeadSLisandro Dalcin }
22362e74eeadSLisandro Dalcin 
2237d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2238d71ae5a4SJacob Faibussowitsch {
2239650997f4SStefano Zampini   Vec temp_vec;
22402e74eeadSLisandro Dalcin 
22412e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2242650997f4SStefano Zampini   if (v3 != v2) {
22439566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22449566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2245650997f4SStefano Zampini   } else {
22469566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22479566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22489566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22499566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2251650997f4SStefano Zampini   }
22523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22532e74eeadSLisandro Dalcin }
22542e74eeadSLisandro Dalcin 
2255a3ef7f04SStefano Zampini static PetscErrorCode ISLocalToGlobalMappingView_Multi(ISLocalToGlobalMapping mapping, PetscInt lsize, PetscInt gsize, const PetscInt vblocks[], PetscViewer viewer)
2256a3ef7f04SStefano Zampini {
2257a3ef7f04SStefano Zampini   PetscInt        tr[3], n;
2258a3ef7f04SStefano Zampini   const PetscInt *indices;
2259a3ef7f04SStefano Zampini 
2260a3ef7f04SStefano Zampini   PetscFunctionBegin;
2261a3ef7f04SStefano Zampini   tr[0] = IS_LTOGM_FILE_CLASSID;
2262a3ef7f04SStefano Zampini   tr[1] = 1;
2263a3ef7f04SStefano Zampini   tr[2] = gsize;
2264a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT));
2265a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWriteAll(viewer, vblocks, lsize, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
2266a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetSize(mapping, &n));
2267a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &indices));
2268a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWriteAll(viewer, indices, n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
2269a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &indices));
2270a3ef7f04SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2271a3ef7f04SStefano Zampini }
2272a3ef7f04SStefano Zampini 
2273d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2274d71ae5a4SJacob Faibussowitsch {
2275b4319ba4SBarry Smith   Mat_IS                *a = (Mat_IS *)A->data;
2276b4319ba4SBarry Smith   PetscViewer            sviewer;
22775042aa92SStefano Zampini   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
22785042aa92SStefano Zampini   PetscViewerFormat      format;
22795042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2280b4319ba4SBarry Smith 
2281b4319ba4SBarry Smith   PetscFunctionBegin;
22829566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
22835042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
22849566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
22855042aa92SStefano Zampini   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
22865042aa92SStefano Zampini   if (native) {
22875042aa92SStefano Zampini     rmap = A->rmap->mapping;
22885042aa92SStefano Zampini     cmap = A->cmap->mapping;
22895042aa92SStefano Zampini   } else {
22905042aa92SStefano Zampini     rmap = a->rmapping;
22915042aa92SStefano Zampini     cmap = a->cmapping;
2292ee2491ecSStefano Zampini   }
22935042aa92SStefano Zampini   if (isascii) {
22945042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
22955042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
22965042aa92SStefano Zampini   } else if (isbinary) {
2297a3ef7f04SStefano Zampini     PetscInt        tr[6], nr, nc, lsize = 0;
22985042aa92SStefano Zampini     char            lmattype[64] = {'\0'};
22995042aa92SStefano Zampini     PetscMPIInt     size;
2300a3ef7f04SStefano Zampini     PetscBool       skipHeader, vbs = PETSC_FALSE;
23015042aa92SStefano Zampini     IS              is;
2302a3ef7f04SStefano Zampini     const PetscInt *vblocks = NULL;
23035042aa92SStefano Zampini 
23045042aa92SStefano Zampini     PetscCall(PetscViewerSetUp(viewer));
2305a3ef7f04SStefano Zampini     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_view_variableblocksizes", &vbs, NULL));
2306a3ef7f04SStefano Zampini     if (vbs) {
2307a3ef7f04SStefano Zampini       PetscCall(MatGetVariableBlockSizes(a->A, &lsize, &vblocks));
2308a3ef7f04SStefano Zampini       PetscCall(PetscMPIIntCast(lsize, &size));
2309a3ef7f04SStefano Zampini       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &size, 1, MPI_INT, MPI_SUM, PetscObjectComm((PetscObject)viewer)));
2310a3ef7f04SStefano Zampini     } else {
23115042aa92SStefano Zampini       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2312a3ef7f04SStefano Zampini     }
23135042aa92SStefano Zampini     tr[0] = MAT_FILE_CLASSID;
23145042aa92SStefano Zampini     tr[1] = A->rmap->N;
23155042aa92SStefano Zampini     tr[2] = A->cmap->N;
23165042aa92SStefano Zampini     tr[3] = -size; /* AIJ stores nnz here */
23175042aa92SStefano Zampini     tr[4] = (PetscInt)(rmap == cmap);
23185042aa92SStefano Zampini     tr[5] = a->allow_repeated;
23195042aa92SStefano Zampini     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
23205042aa92SStefano Zampini 
23215042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
23225042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
23235042aa92SStefano Zampini 
23245042aa92SStefano Zampini     /* first dump l2g info (we need the header for proper loading on different number of processes) */
23255042aa92SStefano Zampini     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
23265042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
2327a3ef7f04SStefano Zampini     if (vbs) {
2328a3ef7f04SStefano Zampini       PetscCall(ISLocalToGlobalMappingView_Multi(rmap, lsize, size, vblocks, viewer));
2329a3ef7f04SStefano Zampini       if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView_Multi(cmap, lsize, size, vblocks, viewer));
2330a3ef7f04SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), lsize, vblocks, PETSC_USE_POINTER, &is));
2331a3ef7f04SStefano Zampini       PetscCall(ISView(is, viewer));
2332a3ef7f04SStefano Zampini       PetscCall(ISView(is, viewer));
2333a3ef7f04SStefano Zampini       PetscCall(ISDestroy(&is));
2334a3ef7f04SStefano Zampini     } else {
23355042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23365042aa92SStefano Zampini       if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23375042aa92SStefano Zampini 
23385042aa92SStefano Zampini       /* then the sizes of the local matrices */
23395042aa92SStefano Zampini       PetscCall(MatGetSize(a->A, &nr, &nc));
23405042aa92SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
23415042aa92SStefano Zampini       PetscCall(ISView(is, viewer));
23425042aa92SStefano Zampini       PetscCall(ISDestroy(&is));
23435042aa92SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
23445042aa92SStefano Zampini       PetscCall(ISView(is, viewer));
23455042aa92SStefano Zampini       PetscCall(ISDestroy(&is));
2346a3ef7f04SStefano Zampini     }
23475042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
23485042aa92SStefano Zampini   }
23495042aa92SStefano Zampini   if (format == PETSC_VIEWER_ASCII_MATLAB) {
23505042aa92SStefano Zampini     char        name[64];
23515042aa92SStefano Zampini     PetscMPIInt size, rank;
23525042aa92SStefano Zampini 
23535042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
23545042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
23555042aa92SStefano Zampini     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
23565042aa92SStefano Zampini     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
23575042aa92SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
23585042aa92SStefano Zampini   }
23595042aa92SStefano Zampini 
23605042aa92SStefano Zampini   /* Dump the local matrices */
23615042aa92SStefano Zampini   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
23625042aa92SStefano Zampini     PetscBool   isaij;
23635042aa92SStefano Zampini     PetscInt    nr, nc;
23645042aa92SStefano Zampini     Mat         lA, B;
23655042aa92SStefano Zampini     Mat_MPIAIJ *b;
23665042aa92SStefano Zampini 
23675042aa92SStefano Zampini     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
23685042aa92SStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
23695042aa92SStefano Zampini     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
23705042aa92SStefano Zampini     else {
23715042aa92SStefano Zampini       PetscCall(PetscObjectReference((PetscObject)a->A));
23725042aa92SStefano Zampini       lA = a->A;
23735042aa92SStefano Zampini     }
23745042aa92SStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
23755042aa92SStefano Zampini     PetscCall(MatSetType(B, MATMPIAIJ));
23765042aa92SStefano Zampini     PetscCall(MatGetSize(lA, &nr, &nc));
23775042aa92SStefano Zampini     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
23785042aa92SStefano Zampini     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
23795042aa92SStefano Zampini 
23805042aa92SStefano Zampini     b = (Mat_MPIAIJ *)B->data;
23815042aa92SStefano Zampini     PetscCall(MatDestroy(&b->A));
23825042aa92SStefano Zampini     b->A = lA;
23835042aa92SStefano Zampini 
23845042aa92SStefano Zampini     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
23855042aa92SStefano Zampini     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
23865042aa92SStefano Zampini     PetscCall(MatView(B, viewer));
23875042aa92SStefano Zampini     PetscCall(MatDestroy(&B));
23885042aa92SStefano Zampini   } else {
23899566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23909566063dSJacob Faibussowitsch     PetscCall(MatView(a->A, sviewer));
23919566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23925042aa92SStefano Zampini   }
23935042aa92SStefano Zampini 
23945042aa92SStefano Zampini   /* with ASCII, we dump the l2gmaps at the end */
23955042aa92SStefano Zampini   if (viewl2g) {
23965042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
23975042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
23985042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23995042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
24005042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24015042aa92SStefano Zampini     } else {
24025042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24035042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24045042aa92SStefano Zampini     }
24055042aa92SStefano Zampini   }
24065042aa92SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
24075042aa92SStefano Zampini }
24085042aa92SStefano Zampini 
2409a3ef7f04SStefano Zampini static PetscErrorCode ISLocalToGlobalMappingHasRepeatedLocal_Private(ISLocalToGlobalMapping map, PetscBool *has)
2410a3ef7f04SStefano Zampini {
2411a3ef7f04SStefano Zampini   const PetscInt *idxs;
2412a3ef7f04SStefano Zampini   PetscHSetI      ht;
2413a3ef7f04SStefano Zampini   PetscInt        n, bs;
2414a3ef7f04SStefano Zampini 
2415a3ef7f04SStefano Zampini   PetscFunctionBegin;
2416a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
2417a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
2418a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
2419a3ef7f04SStefano Zampini   PetscCall(PetscHSetICreate(&ht));
2420a3ef7f04SStefano Zampini   *has = PETSC_FALSE;
2421a3ef7f04SStefano Zampini   for (PetscInt i = 0; i < n / bs; i++) {
2422a3ef7f04SStefano Zampini     PetscBool missing = PETSC_TRUE;
2423a3ef7f04SStefano Zampini     if (idxs[i] < 0) continue;
2424a3ef7f04SStefano Zampini     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2425a3ef7f04SStefano Zampini     if (!missing) {
2426a3ef7f04SStefano Zampini       *has = PETSC_TRUE;
2427a3ef7f04SStefano Zampini       break;
2428a3ef7f04SStefano Zampini     }
2429a3ef7f04SStefano Zampini   }
2430a3ef7f04SStefano Zampini   PetscCall(PetscHSetIDestroy(&ht));
2431a3ef7f04SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2432a3ef7f04SStefano Zampini }
2433a3ef7f04SStefano Zampini 
24345042aa92SStefano Zampini static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
24355042aa92SStefano Zampini {
24365042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
24375042aa92SStefano Zampini   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
24385042aa92SStefano Zampini   PetscBool              isbinary, samel, allow, isbaij;
24395042aa92SStefano Zampini   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
24405042aa92SStefano Zampini   const PetscInt        *idx;
24415042aa92SStefano Zampini   PetscMPIInt            size;
24425042aa92SStefano Zampini   char                   lmattype[64];
24435042aa92SStefano Zampini   Mat                    dA, lA;
24445042aa92SStefano Zampini   IS                     is;
24455042aa92SStefano Zampini 
24465042aa92SStefano Zampini   PetscFunctionBegin;
24475042aa92SStefano Zampini   PetscCheckSameComm(A, 1, viewer, 2);
24485042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
24495042aa92SStefano Zampini   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
24505042aa92SStefano Zampini 
24515042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
24525042aa92SStefano Zampini   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
24535042aa92SStefano Zampini   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24545042aa92SStefano Zampini   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24555042aa92SStefano Zampini   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24565042aa92SStefano Zampini   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24575042aa92SStefano Zampini   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24585042aa92SStefano Zampini   M     = tr[1];
24595042aa92SStefano Zampini   N     = tr[2];
24605042aa92SStefano Zampini   Asize = -tr[3];
24615042aa92SStefano Zampini   samel = (PetscBool)tr[4];
24625042aa92SStefano Zampini   allow = (PetscBool)tr[5];
24635042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
24645042aa92SStefano Zampini 
24655042aa92SStefano Zampini   /* if we are loading from a larger set of processes, allow repeated entries */
24665042aa92SStefano Zampini   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
24675042aa92SStefano Zampini   if (Asize > size) allow = PETSC_TRUE;
24685042aa92SStefano Zampini 
24695042aa92SStefano Zampini   /* set global sizes if not set already */
24705042aa92SStefano Zampini   if (A->rmap->N < 0) A->rmap->N = M;
24715042aa92SStefano Zampini   if (A->cmap->N < 0) A->cmap->N = N;
24725042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->rmap));
24735042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->cmap));
24745042aa92SStefano Zampini   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
24755042aa92SStefano Zampini   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
24765042aa92SStefano Zampini 
24775042aa92SStefano Zampini   /* load l2g maps */
24785042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
24795042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
24805042aa92SStefano Zampini   if (!samel) {
24815042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
24825042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
24835042aa92SStefano Zampini   } else {
24845042aa92SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)rmap));
24855042aa92SStefano Zampini     cmap = rmap;
24865042aa92SStefano Zampini   }
24875042aa92SStefano Zampini 
24885042aa92SStefano Zampini   /* load sizes of local matrices */
24895042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
24905042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
24915042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
24925042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
24935042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
24945042aa92SStefano Zampini   nr = 0;
24955042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
24965042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
24975042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
24985042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
24995042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
25005042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
25015042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
25025042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
25035042aa92SStefano Zampini   nc = 0;
25045042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
25055042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
25065042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
25075042aa92SStefano Zampini 
25085042aa92SStefano Zampini   /* now load the unassembled operator */
25095042aa92SStefano Zampini   PetscCall(MatCreate(comm, &dA));
25105042aa92SStefano Zampini   PetscCall(MatSetType(dA, MATMPIAIJ));
25115042aa92SStefano Zampini   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
25125042aa92SStefano Zampini   PetscCall(MatLoad(dA, viewer));
25135042aa92SStefano Zampini   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
25145042aa92SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)lA));
25155042aa92SStefano Zampini   PetscCall(MatDestroy(&dA));
25165042aa92SStefano Zampini 
25175042aa92SStefano Zampini   /* and convert to the desired format */
25185042aa92SStefano Zampini   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
25195042aa92SStefano Zampini   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
25205042aa92SStefano Zampini   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
25215042aa92SStefano Zampini 
2522a3ef7f04SStefano Zampini   /* check if we actually have repeated entries */
2523a3ef7f04SStefano Zampini   if (allow) {
2524a3ef7f04SStefano Zampini     PetscBool rhas, chas, hasrepeated;
2525a3ef7f04SStefano Zampini 
2526a3ef7f04SStefano Zampini     PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(rmap, &rhas));
2527a3ef7f04SStefano Zampini     if (rmap != cmap) PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(cmap, &chas));
2528a3ef7f04SStefano Zampini     else chas = rhas;
2529a3ef7f04SStefano Zampini     hasrepeated = (PetscBool)(rhas || chas);
25305440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &hasrepeated, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2531a3ef7f04SStefano Zampini     if (!hasrepeated) allow = PETSC_FALSE;
2532a3ef7f04SStefano Zampini   }
2533a3ef7f04SStefano Zampini 
25345042aa92SStefano Zampini   /* assemble the MATIS object */
25355042aa92SStefano Zampini   PetscCall(MatISSetAllowRepeated(A, allow));
25365042aa92SStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
25375042aa92SStefano Zampini   PetscCall(MatISSetLocalMat(A, lA));
25385042aa92SStefano Zampini   PetscCall(MatDestroy(&lA));
25395042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
25405042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
25415042aa92SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
25425042aa92SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
25433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2544b4319ba4SBarry Smith }
2545b4319ba4SBarry Smith 
2546d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2547d71ae5a4SJacob Faibussowitsch {
2548b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2549b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2550b89f26deSStefano Zampini   const PetscScalar *lv;
2551b89f26deSStefano Zampini   PetscInt           bs;
2552835f2295SStefano Zampini   PetscMPIInt        mbs;
2553b89f26deSStefano Zampini 
2554b89f26deSStefano Zampini   PetscFunctionBegin;
25559566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
25569566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
25579566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
255848a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2559835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(bs, &mbs));
2560835f2295SStefano Zampini   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
25619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
25629566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
25639566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
25649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2565b89f26deSStefano Zampini   if (values) *values = is->bdiag;
25663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2567b89f26deSStefano Zampini }
2568b89f26deSStefano Zampini 
2569d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2570d71ae5a4SJacob Faibussowitsch {
2571e176bc59SStefano Zampini   Vec             cglobal, rglobal;
25728546b261SStefano Zampini   IS              from;
25738546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2574b89f26deSStefano Zampini   PetscScalar     sum;
25758546b261SStefano Zampini   const PetscInt *garray;
25768546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2577e432b41dSStefano Zampini   VecType         rtype;
2578b4319ba4SBarry Smith 
2579b4319ba4SBarry Smith   PetscFunctionBegin;
25809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
25819566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
25829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
25839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
25849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
25859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
25869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
25879566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
25889566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
25899566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
25909566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
25919566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
25929566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
25939566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
25949566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
25959566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
25969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
25979566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
25989566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
25999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
26009566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2601e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
26029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
26039566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
26049566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
26059566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
26069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
26078546b261SStefano Zampini   } else {
26089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
26098546b261SStefano Zampini     is->cctx = is->rctx;
26108546b261SStefano Zampini   }
26119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2612b89f26deSStefano Zampini 
26138546b261SStefano Zampini   /* interface counter vector (local) */
26149566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
26159566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
26169566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
26179566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26189566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26199566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26209566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26219566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
26229566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2623b89f26deSStefano Zampini 
2624b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
26259566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2626b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2627e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
26289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2629b0cc1f67SStefano Zampini 
2630b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
26319566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
26323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26338546b261SStefano Zampini }
26348546b261SStefano Zampini 
2635d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2636d71ae5a4SJacob Faibussowitsch {
26374f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2638e432b41dSStefano Zampini   IS                         is;
2639e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2640e432b41dSStefano Zampini   const PetscInt            *idxs;
2641e432b41dSStefano Zampini   PetscHSetI                 ht;
2642e432b41dSStefano Zampini   PetscInt                  *nidxs;
2643e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2644e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2645e432b41dSStefano Zampini 
2646e432b41dSStefano Zampini   PetscFunctionBegin;
26479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
26489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
26499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
26509566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
26519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2652e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
26534f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
26549371c9d4SSatish Balay     if (idxs[i] < 0) {
26559371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
26569371c9d4SSatish Balay       continue;
26579371c9d4SSatish Balay     }
26584f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2659e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2660e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2661e432b41dSStefano Zampini   }
26629566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
26635440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2664e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2665e432b41dSStefano Zampini     *nmap = NULL;
2666e432b41dSStefano Zampini     *lmap = NULL;
26679566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
26689566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
26693ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2670e432b41dSStefano Zampini   }
2671e432b41dSStefano Zampini 
26724f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
26739566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
26749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
26759566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
26769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
26779566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2678e432b41dSStefano Zampini 
26794f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
26809566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
26819566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
26829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
26839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
26849566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
26859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
26863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2687e432b41dSStefano Zampini }
2688e432b41dSStefano Zampini 
2689d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2690d71ae5a4SJacob Faibussowitsch {
26918546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2692e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2693e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
26944f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
26958546b261SStefano Zampini 
26968546b261SStefano Zampini   PetscFunctionBegin;
2697fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2698fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2699e432b41dSStefano Zampini 
27009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
27019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
27029566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
27039566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
27049566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2705e432b41dSStefano Zampini 
2706fc989267SStefano Zampini   /* If NULL, local space matches global space */
2707fc989267SStefano Zampini   if (!rmapping) {
2708fc989267SStefano Zampini     IS is;
2709fc989267SStefano Zampini 
27109566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
27119566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
271258b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
27139566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2714e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2715e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2716e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
27179566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2718e432b41dSStefano Zampini     if (rmapping == cmapping) {
27199566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2720e432b41dSStefano Zampini       is->cmapping = is->rmapping;
27219566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2722e432b41dSStefano Zampini       localcmapping = localrmapping;
2723fc989267SStefano Zampini     }
2724fc989267SStefano Zampini   }
2725fc989267SStefano Zampini   if (!cmapping) {
2726fc989267SStefano Zampini     IS is;
2727fc989267SStefano Zampini 
27289566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
27299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
273058b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
27319566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2732e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2733e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
27349566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2735e432b41dSStefano Zampini   }
2736e432b41dSStefano Zampini   if (!is->rmapping) {
27379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2738e432b41dSStefano Zampini     is->rmapping = rmapping;
2739e432b41dSStefano Zampini   }
2740e432b41dSStefano Zampini   if (!is->cmapping) {
27419566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2742e432b41dSStefano Zampini     is->cmapping = cmapping;
2743fc989267SStefano Zampini   }
2744fc989267SStefano Zampini 
2745fc989267SStefano Zampini   /* Clean up */
27464f58015eSStefano Zampini   is->lnnzstate = 0;
27474f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
27484f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
27499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2750872cf891SStefano Zampini   if (is->csf != is->sf) {
27519566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
27529566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2753f03112d0SStefano Zampini   } else is->csf = NULL;
27549566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
27559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
27569566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
27573bbff08aSStefano Zampini 
2758fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2759fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
27609566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
27619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
27629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
27639566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2764e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2765e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
27666625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
27676625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
27686625354bSStefano Zampini 
27699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
27709566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
27719566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
27729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
27739566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
27746625354bSStefano Zampini     }
27755440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2776e432b41dSStefano Zampini     if (same) {
27779566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
27789566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2779e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2780e432b41dSStefano Zampini     }
27816625354bSStefano Zampini   }
27829566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
27839566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2784e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
27859566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
27869566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
27879566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
27889566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
27896625354bSStefano Zampini 
279039b6f3f9SStefano Zampini   if (!is->islocalref) {
27916625354bSStefano Zampini     /* Create the local matrix A */
27929566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
27939566063dSJacob Faibussowitsch     PetscCall(MatSetType(is->A, is->lmattype));
27949566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
27959566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
27969566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(is->A, "is_"));
27979566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
27989566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->rmap));
27999566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->cmap));
28009566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
28019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
28029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2803fc989267SStefano Zampini     /* setup scatters and local vectors for MatMult */
280439b6f3f9SStefano Zampini     PetscCall(MatISSetUpScatters_Private(A));
280539b6f3f9SStefano Zampini   }
2806fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
28073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2808fc989267SStefano Zampini }
2809fc989267SStefano Zampini 
2810d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2811d71ae5a4SJacob Faibussowitsch {
281229f134acSStefano Zampini   Mat_IS                *is = (Mat_IS *)A->data;
2813fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2814fc989267SStefano Zampini 
2815fc989267SStefano Zampini   PetscFunctionBegin;
281629f134acSStefano Zampini   if (!is->sf) {
28179566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
281829f134acSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
281929f134acSStefano Zampini   }
28203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2821b4319ba4SBarry Smith }
2822b4319ba4SBarry Smith 
2823d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2824d71ae5a4SJacob Faibussowitsch {
28252e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2826*076fee34SStefano Zampini   PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL;
28272e74eeadSLisandro Dalcin 
28282e74eeadSLisandro Dalcin   PetscFunctionBegin;
2829*076fee34SStefano Zampini   IndexSpaceGet(buf, m, n, rows_l, cols_l);
28309566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2831e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
28329566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28339566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2834e432b41dSStefano Zampini   } else {
28359566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2836e432b41dSStefano Zampini   }
2837*076fee34SStefano Zampini   IndexSpaceRestore(buf, m, n, rows_l, cols_l);
28383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28392e74eeadSLisandro Dalcin }
28402e74eeadSLisandro Dalcin 
2841d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2842d71ae5a4SJacob Faibussowitsch {
284397563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2844*076fee34SStefano Zampini   PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL;
284597563a80SStefano Zampini 
284697563a80SStefano Zampini   PetscFunctionBegin;
2847*076fee34SStefano Zampini   IndexSpaceGet(buf, m, n, rows_l, cols_l);
28489566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2849e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
285084a95373SStefano Zampini     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28519566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2852e432b41dSStefano Zampini   } else {
285384a95373SStefano Zampini     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2854e432b41dSStefano Zampini   }
2855*076fee34SStefano Zampini   IndexSpaceRestore(buf, m, n, rows_l, cols_l);
28563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
285797563a80SStefano Zampini }
285897563a80SStefano Zampini 
2859d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2860d71ae5a4SJacob Faibussowitsch {
2861b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2862b4319ba4SBarry Smith 
2863b4319ba4SBarry Smith   PetscFunctionBegin;
2864e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
28659566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2866872cf891SStefano Zampini   } else {
28679566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2868872cf891SStefano Zampini   }
28693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2870b4319ba4SBarry Smith }
2871b4319ba4SBarry Smith 
2872d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2873d71ae5a4SJacob Faibussowitsch {
2874f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2875f0006bf2SLisandro Dalcin 
2876f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2877e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
28789566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2879b4f971dfSStefano Zampini   } else {
28809566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2881b4f971dfSStefano Zampini   }
28823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2883f0006bf2SLisandro Dalcin }
2884f0006bf2SLisandro Dalcin 
2885d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2886d71ae5a4SJacob Faibussowitsch {
2887f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2888f0ae7da4SStefano Zampini 
2889f0ae7da4SStefano Zampini   PetscFunctionBegin;
28900d2733adSStefano Zampini   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
2891f0ae7da4SStefano Zampini   is->pure_neumann = PETSC_FALSE;
2892f0ae7da4SStefano Zampini 
2893f0ae7da4SStefano Zampini   if (columns) {
28949566063dSJacob Faibussowitsch     PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2895f0ae7da4SStefano Zampini   } else {
28969566063dSJacob Faibussowitsch     PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2897f0ae7da4SStefano Zampini   }
2898f0ae7da4SStefano Zampini   if (diag != 0.) {
2899f0ae7da4SStefano Zampini     const PetscScalar *array;
29000d2733adSStefano Zampini 
29019566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(is->counter, &array));
29020d2733adSStefano Zampini     for (PetscInt i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
29039566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(is->counter, &array));
29049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
29059566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2906f0ae7da4SStefano Zampini   }
29073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2908f0ae7da4SStefano Zampini }
2909f0ae7da4SStefano Zampini 
2910d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2911d71ae5a4SJacob Faibussowitsch {
29126e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
29130d2733adSStefano Zampini   PetscInt  nr, nl, len;
29140d2733adSStefano Zampini   PetscInt *lrows = NULL;
29152e74eeadSLisandro Dalcin 
29162e74eeadSLisandro Dalcin   PetscFunctionBegin;
2917cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2918f0ae7da4SStefano Zampini     PetscBool cong;
291926b0207aSStefano Zampini 
29209566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
292126b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
292208401ef6SPierre 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");
2923aed4548fSBarry 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");
2924aed4548fSBarry 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");
2925f0ae7da4SStefano Zampini   }
29260d2733adSStefano Zampini   PetscCall(MatGetSize(matis->A, &nl, NULL));
29276e520ac8SStefano Zampini   /* get locally owned rows */
29289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2929dd8e379bSPierre Jolivet   /* fix right-hand side if needed */
29306e520ac8SStefano Zampini   if (x && b) {
29316e520ac8SStefano Zampini     const PetscScalar *xx;
29326e520ac8SStefano Zampini     PetscScalar       *bb;
29336e520ac8SStefano Zampini 
29349566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
29359566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
29360d2733adSStefano Zampini     for (PetscInt i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
29379566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
29389566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
29392e74eeadSLisandro Dalcin   }
29406e520ac8SStefano Zampini   /* get rows associated to the local matrices */
29419566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
29429566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
29430d2733adSStefano Zampini   for (PetscInt i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
29449566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29459566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29469566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
29480d2733adSStefano Zampini   nr = 0;
29490d2733adSStefano Zampini   for (PetscInt i = 0; i < nl; i++)
29509371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
29519566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
29529566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29542e74eeadSLisandro Dalcin }
29552e74eeadSLisandro Dalcin 
2956d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2957d71ae5a4SJacob Faibussowitsch {
2958b4319ba4SBarry Smith   PetscFunctionBegin;
29599566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
29603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2961f0ae7da4SStefano Zampini }
29622205254eSKarl Rupp 
2963d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2964d71ae5a4SJacob Faibussowitsch {
2965f0ae7da4SStefano Zampini   PetscFunctionBegin;
29669566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
29673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2968b4319ba4SBarry Smith }
2969b4319ba4SBarry Smith 
2970d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2971d71ae5a4SJacob Faibussowitsch {
2972b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2973b4319ba4SBarry Smith 
2974b4319ba4SBarry Smith   PetscFunctionBegin;
29759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
29763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2977b4319ba4SBarry Smith }
2978b4319ba4SBarry Smith 
2979d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2980d71ae5a4SJacob Faibussowitsch {
2981b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2982d0dbe9f7SStefano Zampini   PetscBool lnnz;
2983b4319ba4SBarry Smith 
2984b4319ba4SBarry Smith   PetscFunctionBegin;
29859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2986872cf891SStefano Zampini   /* fix for local empty rows/cols */
2987872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2988872cf891SStefano Zampini     Mat                    newlA;
2989f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2990f03112d0SStefano Zampini     IS                     nzr, nzc;
2991f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2992f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2993872cf891SStefano Zampini 
29949566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
29959566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
299648a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
29979566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
299848a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
29999566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
30009566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
3001e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
3002f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
30035440e5dcSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
3004f03112d0SStefano Zampini 
3005872cf891SStefano Zampini       /* extract valid submatrix */
30069566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
3007f03112d0SStefano Zampini     } else { /* local matrix fully populated */
3008f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
30095440e5dcSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
30109566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
3011f03112d0SStefano Zampini       newlA = is->A;
3012f03112d0SStefano Zampini     }
3013e432b41dSStefano Zampini 
3014f03112d0SStefano Zampini     /* attach new global l2g map if needed */
3015f03112d0SStefano Zampini     if (newl2g) {
3016e432b41dSStefano Zampini       IS              zr, zc;
3017e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
3018e432b41dSStefano Zampini       PetscInt       *nidxs, i;
3019f03112d0SStefano Zampini 
30209566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
30219566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
30229566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
30239566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
30249566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
30259566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
30269566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
30279566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
30289566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
3029e432b41dSStefano Zampini 
30309566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
3031e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
30329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
30339566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
3034e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
30359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
3036e432b41dSStefano Zampini 
30379566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
30389566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
30399566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
30409566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
30419566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
30429566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
30439566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
30449566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
30459566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
30469566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
30479566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3049f03112d0SStefano Zampini     }
30509566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
30519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
30529566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
30539566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
3054872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
3055f03112d0SStefano Zampini   }
3056d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
3057d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
30585440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
30594f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
30603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3061b4319ba4SBarry Smith }
3062b4319ba4SBarry Smith 
3063d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
3064d71ae5a4SJacob Faibussowitsch {
3065b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
3066b4319ba4SBarry Smith 
3067b4319ba4SBarry Smith   PetscFunctionBegin;
3068b4319ba4SBarry Smith   *local = is->A;
30693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3070b4319ba4SBarry Smith }
3071b4319ba4SBarry Smith 
3072d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
3073d71ae5a4SJacob Faibussowitsch {
30743b3b1effSJed Brown   PetscFunctionBegin;
30753b3b1effSJed Brown   *local = NULL;
30763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30773b3b1effSJed Brown }
30783b3b1effSJed Brown 
3079b4319ba4SBarry Smith /*@
308011a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
3081b4319ba4SBarry Smith 
30824f58015eSStefano Zampini   Not Collective.
30834f58015eSStefano Zampini 
3084b4319ba4SBarry Smith   Input Parameter:
3085b4319ba4SBarry Smith . mat - the matrix
3086b4319ba4SBarry Smith 
3087b4319ba4SBarry Smith   Output Parameter:
3088eb82efa4SStefano Zampini . local - the local matrix
3089b4319ba4SBarry Smith 
30904f58015eSStefano Zampini   Level: intermediate
3091b4319ba4SBarry Smith 
3092b4319ba4SBarry Smith   Notes:
3093b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
3094b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
309511a5261eSBarry Smith   of the `MatSetValues()` operation.
3096b4319ba4SBarry Smith 
309711a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
309896a6f129SJed Brown 
30991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
3100b4319ba4SBarry Smith @*/
3101d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
3102d71ae5a4SJacob Faibussowitsch {
3103b4319ba4SBarry Smith   PetscFunctionBegin;
31040700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31054f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3106cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
31073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3108b4319ba4SBarry Smith }
3109b4319ba4SBarry Smith 
31103b3b1effSJed Brown /*@
311111a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
31123b3b1effSJed Brown 
31134f58015eSStefano Zampini   Not Collective.
31144f58015eSStefano Zampini 
31152ef1f0ffSBarry Smith   Input Parameters:
31162ef1f0ffSBarry Smith + mat   - the matrix
31172ef1f0ffSBarry Smith - local - the local matrix
31183b3b1effSJed Brown 
31194f58015eSStefano Zampini   Level: intermediate
31203b3b1effSJed Brown 
31211cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
31223b3b1effSJed Brown @*/
3123d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
3124d71ae5a4SJacob Faibussowitsch {
31253b3b1effSJed Brown   PetscFunctionBegin;
31263b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31274f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3128cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
31293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31303b3b1effSJed Brown }
31313b3b1effSJed Brown 
3132d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3133d71ae5a4SJacob Faibussowitsch {
31348546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
31358546b261SStefano Zampini 
31368546b261SStefano Zampini   PetscFunctionBegin;
31371baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
31389566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
31399566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
31403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31418546b261SStefano Zampini }
31428546b261SStefano Zampini 
31435d83a8b1SBarry Smith /*@
314411a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
31458546b261SStefano Zampini 
31464f58015eSStefano Zampini   Logically Collective.
31474f58015eSStefano Zampini 
3148d8d19677SJose E. Roman   Input Parameters:
3149a2b725a8SWilliam Gropp + mat   - the matrix
3150a2b725a8SWilliam Gropp - mtype - the local matrix type
31518546b261SStefano Zampini 
31524f58015eSStefano Zampini   Level: intermediate
31538546b261SStefano Zampini 
31541cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
31558546b261SStefano Zampini @*/
3156d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3157d71ae5a4SJacob Faibussowitsch {
31588546b261SStefano Zampini   PetscFunctionBegin;
31598546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3160cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
31613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31628546b261SStefano Zampini }
31638546b261SStefano Zampini 
3164d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3165d71ae5a4SJacob Faibussowitsch {
31663b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
31673b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
31688546b261SStefano Zampini   MatType   mtype, otype;
31698546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
31703b03a366Sstefano_zampini 
31713b03a366Sstefano_zampini   PetscFunctionBegin;
3172e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
31739566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
31749566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
31755042aa92SStefano Zampini     PetscCheck(orows == nrows && ocols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)", orows, ocols, nrows, ncols);
31769566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
31779566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
31789566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
31794e4c7dbeSStefano Zampini   }
31809566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
31819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
31823b03a366Sstefano_zampini   is->A = local;
31839566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
31849566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
318548a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
31864f58015eSStefano Zampini   is->lnnzstate = 0;
31873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31883b03a366Sstefano_zampini }
31893b03a366Sstefano_zampini 
31903b03a366Sstefano_zampini /*@
319111a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
31923b03a366Sstefano_zampini 
31934f58015eSStefano Zampini   Not Collective
31948546b261SStefano Zampini 
3195d8d19677SJose E. Roman   Input Parameters:
3196a2b725a8SWilliam Gropp + mat   - the matrix
3197a2b725a8SWilliam Gropp - local - the local matrix
31983b03a366Sstefano_zampini 
31994f58015eSStefano Zampini   Level: intermediate
320011a5261eSBarry Smith 
32011cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
32023b03a366Sstefano_zampini @*/
3203d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3204d71ae5a4SJacob Faibussowitsch {
32053b03a366Sstefano_zampini   PetscFunctionBegin;
32063b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3207b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3208cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
32093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32103b03a366Sstefano_zampini }
32113b03a366Sstefano_zampini 
3212d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3213d71ae5a4SJacob Faibussowitsch {
32146726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32156726f965SBarry Smith 
32166726f965SBarry Smith   PetscFunctionBegin;
32179566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
32183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32196726f965SBarry Smith }
32206726f965SBarry Smith 
3221d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3222d71ae5a4SJacob Faibussowitsch {
32232e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32242e74eeadSLisandro Dalcin 
32252e74eeadSLisandro Dalcin   PetscFunctionBegin;
32269566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
32273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32282e74eeadSLisandro Dalcin }
32292e74eeadSLisandro Dalcin 
3230d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3231d71ae5a4SJacob Faibussowitsch {
32322e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32332e74eeadSLisandro Dalcin 
32342e74eeadSLisandro Dalcin   PetscFunctionBegin;
32352e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
32369566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
32372e74eeadSLisandro Dalcin 
32382e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
32399566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
32409566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32419566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32432e74eeadSLisandro Dalcin }
32442e74eeadSLisandro Dalcin 
3245d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3246d71ae5a4SJacob Faibussowitsch {
32476726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32486726f965SBarry Smith 
32496726f965SBarry Smith   PetscFunctionBegin;
32509566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
32513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32526726f965SBarry Smith }
32536726f965SBarry Smith 
3254d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3255d71ae5a4SJacob Faibussowitsch {
3256f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3257f26d0771SStefano Zampini   Mat_IS *x;
3258f26d0771SStefano Zampini 
3259f26d0771SStefano Zampini   PetscFunctionBegin;
326076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
326176bd3646SJed Brown     PetscBool ismatis;
32629566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
326328b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
326476bd3646SJed Brown   }
3265f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
32669566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
32673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3268f26d0771SStefano Zampini }
3269f26d0771SStefano Zampini 
3270d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3271d71ae5a4SJacob Faibussowitsch {
3272f26d0771SStefano Zampini   Mat                    lA;
3273f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3274f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3275f26d0771SStefano Zampini   IS                     is;
3276f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3277*076fee34SStefano Zampini   PetscInt               nrg, rbs, cbs;
3278f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3279f26d0771SStefano Zampini 
3280f26d0771SStefano Zampini   PetscFunctionBegin;
3281*076fee34SStefano Zampini   PetscCall(ISGetBlockSize(row, &rbs));
3282*076fee34SStefano Zampini   PetscCall(ISGetBlockSize(col, &cbs));
32839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
32849566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
32859566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
32869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
328776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3288e87b5d96SPierre 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 than maximum possible %" PetscInt_FMT, i, rl[i], nrg);
328976bd3646SJed Brown   }
3290*076fee34SStefano Zampini   if (nrg % rbs) nrg = rbs * (nrg / rbs + 1);
32919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3292f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3293f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3294f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
32959566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
32969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
32979566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
32989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3299*076fee34SStefano Zampini   PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
33009566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3301f26d0771SStefano Zampini   /* compute new l2g map for columns */
3302e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3303f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3304f26d0771SStefano Zampini     PetscInt        ncg;
3305f26d0771SStefano Zampini     PetscInt        ncl;
3306f26d0771SStefano Zampini 
33079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
33089566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
33099566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
33109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
331176bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
3312e87b5d96SPierre 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 than maximum possible %" PetscInt_FMT, i, cl[i], ncg);
331376bd3646SJed Brown     }
3314*076fee34SStefano Zampini     if (ncg % cbs) ncg = cbs * (ncg / cbs + 1);
33159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3316f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3317f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3318f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
33199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
33209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
33219566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
33229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3323*076fee34SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
33249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3325f26d0771SStefano Zampini   } else {
33269566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3327f26d0771SStefano Zampini     cl2g = rl2g;
3328f26d0771SStefano Zampini   }
33290d2733adSStefano Zampini 
3330f26d0771SStefano Zampini   /* create the MATIS submatrix */
33319566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
33329566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
33339566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
33349566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3335b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
33360d2733adSStefano Zampini   matis->islocalref = A;
33379566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
33389566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
33399566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
33409566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
33419566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3342e432b41dSStefano Zampini 
3343f26d0771SStefano Zampini   /* remove unsupported ops */
33449566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3345f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3346f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3347f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
33480d2733adSStefano Zampini   (*submat)->ops->zerorowslocal         = MatZeroRowsLocal_SubMat_IS;
33490d2733adSStefano Zampini   (*submat)->ops->zerorowscolumnslocal  = MatZeroRowsColumnsLocal_SubMat_IS;
335039b6f3f9SStefano Zampini   (*submat)->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_IS;
33513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3352f26d0771SStefano Zampini }
3353f26d0771SStefano Zampini 
3354ce78bad3SBarry Smith static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject)
3355d71ae5a4SJacob Faibussowitsch {
3356872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
33578546b261SStefano Zampini   char      type[256];
33588546b261SStefano Zampini   PetscBool flg;
3359872cf891SStefano Zampini 
3360872cf891SStefano Zampini   PetscFunctionBegin;
3361d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
33624f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
33634f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
33644f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
33654f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
33664f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
33674f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
33684f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
33694f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
33704f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
33711baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
33721baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3373d0609cedSBarry Smith   PetscOptionsHeadEnd();
33743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3375872cf891SStefano Zampini }
3376872cf891SStefano Zampini 
3377284134d9SBarry Smith /*@
33784f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
33794f58015eSStefano Zampini 
33804f58015eSStefano Zampini   Collective.
3381284134d9SBarry Smith 
3382284134d9SBarry Smith   Input Parameters:
3383284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3384e176bc59SStefano Zampini . bs   - block size of the matrix
33852920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
33862920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
33872920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
33882920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3389e176bc59SStefano Zampini . rmap - local to global map for rows
3390e176bc59SStefano Zampini - cmap - local to global map for cols
3391284134d9SBarry Smith 
3392284134d9SBarry Smith   Output Parameter:
3393284134d9SBarry Smith . A - the resulting matrix
3394284134d9SBarry Smith 
33954f58015eSStefano Zampini   Level: intermediate
33968e6c10adSSatish Balay 
339795452b02SPatrick Sanan   Notes:
33982ef1f0ffSBarry Smith   `m` and `n` are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
33994f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
340011a5261eSBarry Smith 
34012ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3402284134d9SBarry Smith 
34031cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3404284134d9SBarry Smith @*/
3405d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3406d71ae5a4SJacob Faibussowitsch {
3407284134d9SBarry Smith   PetscFunctionBegin;
34089566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
34099566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
341048a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
34119566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
34129566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
34133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3414284134d9SBarry Smith }
3415284134d9SBarry Smith 
3416d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3417d71ae5a4SJacob Faibussowitsch {
34188b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3419e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
34208b9382cfSStefano Zampini 
34218b9382cfSStefano Zampini   PetscFunctionBegin;
34228b9382cfSStefano Zampini   *has = PETSC_FALSE;
34233ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3424d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
34259371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
34263ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
34279566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
34283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34298b9382cfSStefano Zampini }
34308b9382cfSStefano Zampini 
3431d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3432d71ae5a4SJacob Faibussowitsch {
3433e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3434e432b41dSStefano Zampini 
3435e432b41dSStefano Zampini   PetscFunctionBegin;
34369566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
34379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
34389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
34393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3440e432b41dSStefano Zampini }
3441e432b41dSStefano Zampini 
3442d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3443d71ae5a4SJacob Faibussowitsch {
3444e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3445e432b41dSStefano Zampini 
3446e432b41dSStefano Zampini   PetscFunctionBegin;
3447e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3448e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
34499566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3450e432b41dSStefano Zampini   } else {
34519566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3452e432b41dSStefano Zampini   }
34539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3454e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3456e432b41dSStefano Zampini }
3457e432b41dSStefano Zampini 
3458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3459d71ae5a4SJacob Faibussowitsch {
3460e432b41dSStefano Zampini   Mat_IS  *a = (Mat_IS *)A->data;
3461835f2295SStefano Zampini   PetscInt ncoo_i;
3462e432b41dSStefano Zampini 
3463e432b41dSStefano Zampini   PetscFunctionBegin;
3464e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3465835f2295SStefano Zampini   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3466835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3467835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3468e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
34699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3470e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3472e432b41dSStefano Zampini }
3473e432b41dSStefano Zampini 
3474d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3475d71ae5a4SJacob Faibussowitsch {
3476d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
34771690c2aeSBarry Smith   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
34781690c2aeSBarry Smith   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3479d0dbe9f7SStefano Zampini 
3480d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3481d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3482d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3483d0dbe9f7SStefano Zampini   if (a->assembledA) {
3484d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3485d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3486d0dbe9f7SStefano Zampini   }
3487d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3488d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3489d0dbe9f7SStefano Zampini     MatType     aAtype;
3490d0dbe9f7SStefano Zampini     PetscMPIInt size;
3491d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3492d0dbe9f7SStefano Zampini 
3493d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3494d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3495d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3496d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3497d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3498d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3499d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3500d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3501d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3502d0dbe9f7SStefano Zampini 
3503d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3504d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3505d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3506d0dbe9f7SStefano Zampini   }
3507d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3508d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3509d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
35103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3511d0dbe9f7SStefano Zampini }
3512d0dbe9f7SStefano Zampini 
3513d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3514d71ae5a4SJacob Faibussowitsch {
3515d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3516d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3517d0dbe9f7SStefano Zampini   *tA = NULL;
35183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3519d0dbe9f7SStefano Zampini }
3520d0dbe9f7SStefano Zampini 
3521d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3522d71ae5a4SJacob Faibussowitsch {
3523d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
35241690c2aeSBarry Smith   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3525d0dbe9f7SStefano Zampini 
3526d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3527d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3528d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3529d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3530d0dbe9f7SStefano Zampini     Mat     tA;
3531d0dbe9f7SStefano Zampini     MatType ltype;
3532d0dbe9f7SStefano Zampini 
3533d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3534d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3535d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3536d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3537d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3538d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3539d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3540d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3541d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3542d0dbe9f7SStefano Zampini   }
3543d0dbe9f7SStefano Zampini   *dA = a->dA;
35443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3545d0dbe9f7SStefano Zampini }
3546d0dbe9f7SStefano Zampini 
3547d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3548d71ae5a4SJacob Faibussowitsch {
3549d0dbe9f7SStefano Zampini   Mat tA;
3550d0dbe9f7SStefano Zampini 
3551d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3552d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3553d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3554d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3555d0dbe9f7SStefano Zampini #if 0
3556d0dbe9f7SStefano Zampini   {
3557d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3558d0dbe9f7SStefano Zampini     MatType   ltype;
3559d0dbe9f7SStefano Zampini     VecType   vtype;
3560d0dbe9f7SStefano Zampini     char      *flg;
3561d0dbe9f7SStefano Zampini 
3562d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3563d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3564d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3565d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3566d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3567d0dbe9f7SStefano Zampini     if (flg) {
3568d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3569d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3570d0dbe9f7SStefano Zampini 
3571d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3572d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3573d0dbe9f7SStefano Zampini       }
3574d0dbe9f7SStefano Zampini     }
3575d0dbe9f7SStefano Zampini   }
3576d0dbe9f7SStefano Zampini #endif
3577d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
35783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3579d0dbe9f7SStefano Zampini }
3580d0dbe9f7SStefano Zampini 
3581d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3582d71ae5a4SJacob Faibussowitsch {
3583d0dbe9f7SStefano Zampini   Mat tA;
3584d0dbe9f7SStefano Zampini 
3585d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3586d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3587d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3588d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
35893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3590d0dbe9f7SStefano Zampini }
3591d0dbe9f7SStefano Zampini 
3592e432b41dSStefano Zampini /*@
359311a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3594e432b41dSStefano Zampini 
3595e432b41dSStefano Zampini   Not Collective
3596e432b41dSStefano Zampini 
3597e432b41dSStefano Zampini   Input Parameter:
3598e432b41dSStefano Zampini . A - the matrix
3599e432b41dSStefano Zampini 
3600e432b41dSStefano Zampini   Output Parameters:
3601e432b41dSStefano Zampini + rmapping - row mapping
3602e432b41dSStefano Zampini - cmapping - column mapping
3603e432b41dSStefano Zampini 
36042ef1f0ffSBarry Smith   Level: advanced
36052ef1f0ffSBarry Smith 
360611a5261eSBarry Smith   Note:
360711a5261eSBarry 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.
3608e432b41dSStefano Zampini 
3609bfe80ac4SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3610e432b41dSStefano Zampini @*/
3611d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3612d71ae5a4SJacob Faibussowitsch {
3613e432b41dSStefano Zampini   PetscFunctionBegin;
3614e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3615e432b41dSStefano Zampini   PetscValidType(A, 1);
36164f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
36174f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3618cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
36193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3620e432b41dSStefano Zampini }
3621e432b41dSStefano Zampini 
3622d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3623d71ae5a4SJacob Faibussowitsch {
3624e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3625e432b41dSStefano Zampini 
3626e432b41dSStefano Zampini   PetscFunctionBegin;
3627e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3628e432b41dSStefano Zampini   if (c) *c = a->cmapping;
36293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3630e432b41dSStefano Zampini }
3631e432b41dSStefano Zampini 
3632a50ef18cSStefano Zampini static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3633a50ef18cSStefano Zampini {
3634a50ef18cSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3635a50ef18cSStefano Zampini 
3636a50ef18cSStefano Zampini   PetscFunctionBegin;
3637a50ef18cSStefano Zampini   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3638a50ef18cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
3639a50ef18cSStefano Zampini }
3640a50ef18cSStefano Zampini 
3641b4319ba4SBarry Smith /*MC
36424f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
36434f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3644b4319ba4SBarry Smith 
3645b4319ba4SBarry Smith   Options Database Keys:
36464f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
36474f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
36484f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
36494f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
36502ef1f0ffSBarry Smith 
36514f58015eSStefano Zampini   Level: intermediate
3652b4319ba4SBarry Smith 
365395452b02SPatrick Sanan   Notes:
36542ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3655b4319ba4SBarry Smith 
365611a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3657b4319ba4SBarry Smith 
3658b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
36594f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3660b4319ba4SBarry Smith 
36611cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3662b4319ba4SBarry Smith M*/
3663d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3664d71ae5a4SJacob Faibussowitsch {
3665e432b41dSStefano Zampini   Mat_IS *a;
3666b4319ba4SBarry Smith 
3667b4319ba4SBarry Smith   PetscFunctionBegin;
36684dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
36699566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3670e432b41dSStefano Zampini   A->data = (void *)a;
3671b4319ba4SBarry Smith 
3672e176bc59SStefano Zampini   /* matrix ops */
36739566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3674b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
36752e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
36762e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
36772e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3678b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3679b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
36802e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
368198921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3682b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3683f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
36842e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3685f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3686b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3687b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3688b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
36895042aa92SStefano Zampini   A->ops->load                    = MatLoad_IS;
36906726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
36912e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
36922e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
36936726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
369469796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
369569796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
369645471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3697ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
36986bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
36992b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3700659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
37017dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3702f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
37033fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
37043fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3705d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
37067fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3707ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3708872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3709fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
37108b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3711d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3712d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3713d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3714a50ef18cSStefano Zampini   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3715b4319ba4SBarry Smith 
3716b7ce53b6SStefano Zampini   /* special MATIS functions */
37179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
37189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
37199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
37209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
37219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
37224f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
37239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
37249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
37259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
37269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
37279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
37289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
37299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
37309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
37319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
37329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
37339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
37349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
37359566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
37363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3737b4319ba4SBarry Smith }
3738