xref: /petsc/src/mat/impls/is/matis.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
1b4319ba4SBarry Smith /*
2b4319ba4SBarry Smith     Creates a matrix class for using the Neumann-Neumann type preconditioners.
3b4319ba4SBarry Smith     This stores the matrices in globally unassembled form. Each processor
4b4319ba4SBarry Smith     assembles only its local Neumann problem and the parallel matrix vector
5b4319ba4SBarry Smith     product is handled "implicitly".
6b4319ba4SBarry Smith 
7b4319ba4SBarry Smith     Currently this allows for only one subdomain per processor.
8b4319ba4SBarry Smith */
9b4319ba4SBarry Smith 
10d0dbe9f7SStefano Zampini #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/
114f2d7cafSStefano Zampini #include <petsc/private/sfimpl.h>
12a72d46e8SStefano Zampini #include <petsc/private/vecimpl.h>
13e432b41dSStefano Zampini #include <petsc/private/hashseti.h>
1428f4e0baSStefano Zampini 
15f26d0771SStefano Zampini #define MATIS_MAX_ENTRIES_INSERTION 2048
16b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
17b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
188546b261SStefano Zampini static PetscErrorCode MatISSetUpScatters_Private(Mat);
19f26d0771SStefano Zampini 
20d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr)
21d71ae5a4SJacob Faibussowitsch {
2275d48cdbSStefano Zampini   MatISPtAP ptap = (MatISPtAP)ptr;
2375d48cdbSStefano Zampini 
2475d48cdbSStefano Zampini   PetscFunctionBegin;
259566063dSJacob Faibussowitsch   PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP));
269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis0));
279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis1));
289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris0));
299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris1));
309566063dSJacob Faibussowitsch   PetscCall(PetscFree(ptap));
3175d48cdbSStefano Zampini   PetscFunctionReturn(0);
3275d48cdbSStefano Zampini }
3375d48cdbSStefano Zampini 
34d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
35d71ae5a4SJacob Faibussowitsch {
3675d48cdbSStefano Zampini   MatISPtAP      ptap;
3775d48cdbSStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
3875d48cdbSStefano Zampini   Mat            lA, lC;
3975d48cdbSStefano Zampini   MatReuse       reuse;
4075d48cdbSStefano Zampini   IS             ris[2], cis[2];
4175d48cdbSStefano Zampini   PetscContainer c;
4275d48cdbSStefano Zampini   PetscInt       n;
4375d48cdbSStefano Zampini 
4475d48cdbSStefano Zampini   PetscFunctionBegin;
459566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c));
4628b400f6SJacob Faibussowitsch   PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information");
479566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(c, (void **)&ptap));
4875d48cdbSStefano Zampini   ris[0] = ptap->ris0;
4975d48cdbSStefano Zampini   ris[1] = ptap->ris1;
5075d48cdbSStefano Zampini   cis[0] = ptap->cis0;
5175d48cdbSStefano Zampini   cis[1] = ptap->cis1;
5275d48cdbSStefano Zampini   n      = ptap->ris1 ? 2 : 1;
5375d48cdbSStefano Zampini   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
549566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP));
5575d48cdbSStefano Zampini 
569566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
579566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(C, &lC));
5875d48cdbSStefano Zampini   if (ptap->ris1) { /* unsymmetric A mapping */
5975d48cdbSStefano Zampini     Mat lPt;
6075d48cdbSStefano Zampini 
619566063dSJacob Faibussowitsch     PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt));
629566063dSJacob Faibussowitsch     PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC));
6348a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", (PetscObject)lPt));
649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lPt));
6575d48cdbSStefano Zampini   } else {
669566063dSJacob Faibussowitsch     PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC));
6748a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0]));
6875d48cdbSStefano Zampini   }
6975d48cdbSStefano Zampini   if (reuse == MAT_INITIAL_MATRIX) {
709566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(C, lC));
719566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lC));
7275d48cdbSStefano Zampini   }
739566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
7575d48cdbSStefano Zampini   PetscFunctionReturn(0);
7675d48cdbSStefano Zampini }
7775d48cdbSStefano Zampini 
78d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis)
79d71ae5a4SJacob Faibussowitsch {
8075d48cdbSStefano Zampini   Mat             Po, Pd;
8175d48cdbSStefano Zampini   IS              zd, zo;
8275d48cdbSStefano Zampini   const PetscInt *garray;
8375d48cdbSStefano Zampini   PetscInt       *aux, i, bs;
8475d48cdbSStefano Zampini   PetscInt        dc, stc, oc, ctd, cto;
8575d48cdbSStefano Zampini   PetscBool       ismpiaij, ismpibaij, isseqaij, isseqbaij;
8675d48cdbSStefano Zampini   MPI_Comm        comm;
8775d48cdbSStefano Zampini 
8875d48cdbSStefano Zampini   PetscFunctionBegin;
8975d48cdbSStefano Zampini   PetscValidHeaderSpecific(PT, MAT_CLASSID, 1);
9075d48cdbSStefano Zampini   PetscValidPointer(cis, 2);
919566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)PT, &comm));
9275d48cdbSStefano Zampini   bs = 1;
939566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij));
949566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij));
959566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij));
969566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij));
9775d48cdbSStefano Zampini   if (isseqaij || isseqbaij) {
9875d48cdbSStefano Zampini     Pd     = PT;
9975d48cdbSStefano Zampini     Po     = NULL;
10075d48cdbSStefano Zampini     garray = NULL;
10175d48cdbSStefano Zampini   } else if (ismpiaij) {
1029566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray));
10375d48cdbSStefano Zampini   } else if (ismpibaij) {
1049566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray));
1059566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(PT, &bs));
10698921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(PT))->type_name);
10775d48cdbSStefano Zampini 
10875d48cdbSStefano Zampini   /* identify any null columns in Pd or Po */
10922f7620eSStefano Zampini   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
11022f7620eSStefano Zampini      some of the columns are not really zero, but very close to */
11175d48cdbSStefano Zampini   zo = zd = NULL;
11248a46eb9SPierre Jolivet   if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo));
1139566063dSJacob Faibussowitsch   PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd));
11475d48cdbSStefano Zampini 
1159566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(PT, NULL, &dc));
1169566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL));
1179566063dSJacob Faibussowitsch   if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc));
11875d48cdbSStefano Zampini   else oc = 0;
1199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
12075d48cdbSStefano Zampini   if (zd) {
12175d48cdbSStefano Zampini     const PetscInt *idxs;
12275d48cdbSStefano Zampini     PetscInt        nz;
12375d48cdbSStefano Zampini 
12475d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1259566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zd, bs));
1269566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zd, &nz));
1279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zd, &idxs));
12875d48cdbSStefano Zampini     ctd = nz / bs;
12975d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs;
1309566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zd, &idxs));
13175d48cdbSStefano Zampini   } else {
13275d48cdbSStefano Zampini     ctd = dc / bs;
13375d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = i + stc / bs;
13475d48cdbSStefano Zampini   }
13575d48cdbSStefano Zampini   if (zo) {
13675d48cdbSStefano Zampini     const PetscInt *idxs;
13775d48cdbSStefano Zampini     PetscInt        nz;
13875d48cdbSStefano Zampini 
13975d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1409566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zo, bs));
1419566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zo, &nz));
1429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zo, &idxs));
14375d48cdbSStefano Zampini     cto = nz / bs;
14475d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs];
1459566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zo, &idxs));
14675d48cdbSStefano Zampini   } else {
14775d48cdbSStefano Zampini     cto = oc / bs;
14875d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[i];
14975d48cdbSStefano Zampini   }
1509566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis));
1519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zd));
1529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zo));
15375d48cdbSStefano Zampini   PetscFunctionReturn(0);
15475d48cdbSStefano Zampini }
15575d48cdbSStefano Zampini 
156d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C)
157d71ae5a4SJacob Faibussowitsch {
1588546b261SStefano Zampini   Mat                    PT, lA;
15975d48cdbSStefano Zampini   MatISPtAP              ptap;
16075d48cdbSStefano Zampini   ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g;
16175d48cdbSStefano Zampini   PetscContainer         c;
1628546b261SStefano Zampini   MatType                lmtype;
16375d48cdbSStefano Zampini   const PetscInt        *garray;
16475d48cdbSStefano Zampini   PetscInt               ibs, N, dc;
16575d48cdbSStefano Zampini   MPI_Comm               comm;
16675d48cdbSStefano Zampini 
16775d48cdbSStefano Zampini   PetscFunctionBegin;
1689566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1699566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATIS));
1709566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
1719566063dSJacob Faibussowitsch   PetscCall(MatGetType(lA, &lmtype));
1729566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(C, lmtype));
1739566063dSJacob Faibussowitsch   PetscCall(MatGetSize(P, NULL, &N));
1749566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(P, NULL, &dc));
1759566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, dc, dc, N, N));
17675d48cdbSStefano Zampini   /* Not sure about this
1779566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSizes(P,NULL,&ibs));
1789566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(*C,ibs));
17975d48cdbSStefano Zampini */
18075d48cdbSStefano Zampini 
1819566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ptap));
1829566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1839566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ptap));
1849566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyPtAP_Private));
1859566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c));
1869566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
18775d48cdbSStefano Zampini   ptap->fill = fill;
18875d48cdbSStefano Zampini 
1899566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g));
19075d48cdbSStefano Zampini 
1919566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs));
1929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N));
1939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray));
1949566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0));
1959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray));
19675d48cdbSStefano Zampini 
1979566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT));
1989566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0));
1999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g));
2009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&PT));
20175d48cdbSStefano Zampini 
20275d48cdbSStefano Zampini   Crl2g = NULL;
20375d48cdbSStefano Zampini   if (rl2g != cl2g) { /* unsymmetric A mapping */
20475d48cdbSStefano Zampini     PetscBool same, lsame = PETSC_FALSE;
20575d48cdbSStefano Zampini     PetscInt  N1, ibs1;
20675d48cdbSStefano Zampini 
2079566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1));
2089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1));
2099566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray));
2109566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1));
2119566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray));
21275d48cdbSStefano Zampini     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
21375d48cdbSStefano Zampini       const PetscInt *i1, *i2;
21475d48cdbSStefano Zampini 
2159566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris0, &i1));
2169566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris1, &i2));
2179566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(i1, i2, N, &lsame));
21875d48cdbSStefano Zampini     }
2191c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lsame, &same, 1, MPIU_BOOL, MPI_LAND, comm));
22075d48cdbSStefano Zampini     if (same) {
2219566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ptap->ris1));
22275d48cdbSStefano Zampini     } else {
2239566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT));
2249566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1));
2259566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g));
2269566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&PT));
22775d48cdbSStefano Zampini     }
22875d48cdbSStefano Zampini   }
22975d48cdbSStefano Zampini   /* Not sure about this
23075d48cdbSStefano Zampini   if (!Crl2g) {
2319566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(C,&ibs));
2329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs));
23375d48cdbSStefano Zampini   }
23475d48cdbSStefano Zampini */
2359566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g));
2369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g));
2379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g));
23875d48cdbSStefano Zampini 
2394222ddf1SHong Zhang   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
24075d48cdbSStefano Zampini   PetscFunctionReturn(0);
24175d48cdbSStefano Zampini }
24275d48cdbSStefano Zampini 
2434222ddf1SHong Zhang /* ----------------------------------------- */
244d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
245d71ae5a4SJacob Faibussowitsch {
2464222ddf1SHong Zhang   Mat_Product *product = C->product;
2474222ddf1SHong Zhang   Mat          A = product->A, P = product->B;
2484222ddf1SHong Zhang   PetscReal    fill = product->fill;
24975d48cdbSStefano Zampini 
25075d48cdbSStefano Zampini   PetscFunctionBegin;
2519566063dSJacob Faibussowitsch   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
2524222ddf1SHong Zhang   C->ops->productnumeric = MatProductNumeric_PtAP;
25375d48cdbSStefano Zampini   PetscFunctionReturn(0);
25475d48cdbSStefano Zampini }
25575d48cdbSStefano Zampini 
256d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
257d71ae5a4SJacob Faibussowitsch {
2584222ddf1SHong Zhang   PetscFunctionBegin;
2594222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
2604222ddf1SHong Zhang   PetscFunctionReturn(0);
2614222ddf1SHong Zhang }
2624222ddf1SHong Zhang 
263d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
264d71ae5a4SJacob Faibussowitsch {
2654222ddf1SHong Zhang   Mat_Product *product = C->product;
2664222ddf1SHong Zhang 
2674222ddf1SHong Zhang   PetscFunctionBegin;
26848a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
2694222ddf1SHong Zhang   PetscFunctionReturn(0);
2704222ddf1SHong Zhang }
2714222ddf1SHong Zhang 
2724222ddf1SHong Zhang /* ----------------------------------------- */
273d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
274d71ae5a4SJacob Faibussowitsch {
2755b003df0Sstefano_zampini   MatISLocalFields lf = (MatISLocalFields)ptr;
2765b003df0Sstefano_zampini   PetscInt         i;
2775b003df0Sstefano_zampini 
278ab4d48faSStefano Zampini   PetscFunctionBegin;
27948a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
28048a46eb9SPierre Jolivet   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
2819566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lf->rf, lf->cf));
2829566063dSJacob Faibussowitsch   PetscCall(PetscFree(lf));
2835b003df0Sstefano_zampini   PetscFunctionReturn(0);
2845b003df0Sstefano_zampini }
285a72627d2SStefano Zampini 
286d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
287d71ae5a4SJacob Faibussowitsch {
288c9225affSStefano Zampini   Mat B, lB;
289c9225affSStefano Zampini 
290c9225affSStefano Zampini   PetscFunctionBegin;
291c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
292c9225affSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
293c9225affSStefano Zampini     PetscInt               bs;
294c9225affSStefano Zampini     IS                     is;
295c9225affSStefano Zampini 
2969566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
2979566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
298c9225affSStefano Zampini     if (bs > 1) {
299c9225affSStefano Zampini       IS       is2;
300c9225affSStefano Zampini       PetscInt i, *aux;
301c9225affSStefano Zampini 
3029566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3039566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3049566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3059566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3069566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
307c9225affSStefano Zampini       is = is2;
308c9225affSStefano Zampini     }
3099566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3129566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
313c9225affSStefano Zampini     if (bs > 1) {
314c9225affSStefano Zampini       IS       is2;
315c9225affSStefano Zampini       PetscInt i, *aux;
316c9225affSStefano Zampini 
3179566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3189566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3199566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3209566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3219566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
322c9225affSStefano Zampini       is = is2;
323c9225affSStefano Zampini     }
3249566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3269566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3279566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
3289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3309566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
331c9225affSStefano Zampini     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
332c9225affSStefano Zampini   } else {
333c9225affSStefano Zampini     B = *newmat;
3349566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
335c9225affSStefano Zampini     lB = A;
336c9225affSStefano Zampini   }
3379566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lB));
3389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lB));
3399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
34148a46eb9SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
342c9225affSStefano Zampini   PetscFunctionReturn(0);
343c9225affSStefano Zampini }
344c9225affSStefano Zampini 
345d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
346d71ae5a4SJacob Faibussowitsch {
347c9225affSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(A->data);
348c9225affSStefano Zampini   PetscScalar    *aa;
349c9225affSStefano Zampini   const PetscInt *ii, *jj;
350c9225affSStefano Zampini   PetscInt        i, n, m;
351fabe8965SStefano Zampini   PetscInt       *ecount, **eneighs;
352c9225affSStefano Zampini   PetscBool       flg;
353c9225affSStefano Zampini 
354c9225affSStefano Zampini   PetscFunctionBegin;
3559566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
35608401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
3579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
35808401ef6SPierre Jolivet   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
3599566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
360c9225affSStefano Zampini   for (i = 0; i < n; i++) {
361fabe8965SStefano Zampini     if (ecount[i] > 1) {
362c9225affSStefano Zampini       PetscInt j;
363c9225affSStefano Zampini 
364c9225affSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
365c9225affSStefano Zampini         PetscInt  i2   = jj[j], p, p2;
366fabe8965SStefano Zampini         PetscReal scal = 0.0;
367c9225affSStefano Zampini 
368c9225affSStefano Zampini         for (p = 0; p < ecount[i]; p++) {
369c9225affSStefano Zampini           for (p2 = 0; p2 < ecount[i2]; p2++) {
3709371c9d4SSatish Balay             if (eneighs[i][p] == eneighs[i2][p2]) {
3719371c9d4SSatish Balay               scal += 1.0;
3729371c9d4SSatish Balay               break;
3739371c9d4SSatish Balay             }
374c9225affSStefano Zampini           }
375c9225affSStefano Zampini         }
376fabe8965SStefano Zampini         if (scal) aa[j] /= scal;
377c9225affSStefano Zampini       }
378c9225affSStefano Zampini     }
379c9225affSStefano Zampini   }
3809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
3819566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
3829566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
38308401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
384c9225affSStefano Zampini   PetscFunctionReturn(0);
385c9225affSStefano Zampini }
386c9225affSStefano Zampini 
3879371c9d4SSatish Balay typedef enum {
3889371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_NATURAL,
3899371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_MAT,
3909371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_ND
3919371c9d4SSatish Balay } MatISDisassemblel2gType;
392fabe8965SStefano Zampini 
393d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
394d71ae5a4SJacob Faibussowitsch {
395fabe8965SStefano Zampini   Mat                     Ad, Ao;
396fabe8965SStefano Zampini   IS                      is, ndmap, ndsub;
397c9225affSStefano Zampini   MPI_Comm                comm;
398fabe8965SStefano Zampini   const PetscInt         *garray, *ndmapi;
399fabe8965SStefano Zampini   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
400fabe8965SStefano Zampini   PetscBool               ismpiaij, ismpibaij;
401f4259b30SLisandro Dalcin   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
402fabe8965SStefano Zampini   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
403fabe8965SStefano Zampini   MatPartitioning         part;
404fabe8965SStefano Zampini   PetscSF                 sf;
40591d376acSStefano Zampini   PetscObject             dm;
406c9225affSStefano Zampini 
407c9225affSStefano Zampini   PetscFunctionBegin;
408d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
4099566063dSJacob 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));
410d0609cedSBarry Smith   PetscOptionsEnd();
411fabe8965SStefano Zampini   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
4129566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
413c9225affSStefano Zampini     PetscFunctionReturn(0);
414c9225affSStefano Zampini   }
4159566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4169566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
4179566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
4189566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
419fabe8965SStefano Zampini   switch (mode) {
420fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_ND:
4219566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(comm, &part));
4229566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(part, A));
4239566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
4249566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(part));
4259566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApplyND(part, &ndmap));
4269566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&part));
4279566063dSJacob Faibussowitsch     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
4289566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
4299566063dSJacob Faibussowitsch     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
4309566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
431fabe8965SStefano Zampini 
432fabe8965SStefano Zampini     /* it may happen that a separator node is not properly shared */
4339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
4349566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &sf));
4359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
4369566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
4379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
4389566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
4399566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4409566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4419566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
4429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ndmap, &ndmapi));
443fabe8965SStefano Zampini     for (i = 0, cnt = 0; i < A->rmap->n; i++)
4449371c9d4SSatish Balay       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
445fabe8965SStefano Zampini 
4461c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
447fabe8965SStefano Zampini     if (i) { /* we detected isolated separator nodes */
448fabe8965SStefano Zampini       Mat                    A2, A3;
449fabe8965SStefano Zampini       IS                    *workis, is2;
450fabe8965SStefano Zampini       PetscScalar           *vals;
451fabe8965SStefano Zampini       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
452fabe8965SStefano Zampini       ISLocalToGlobalMapping ll2g;
453fabe8965SStefano Zampini       PetscBool              flg;
454fabe8965SStefano Zampini       const PetscInt        *ii, *jj;
455fabe8965SStefano Zampini 
456fabe8965SStefano Zampini       /* communicate global id of separators */
457d0609cedSBarry Smith       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
4589371c9d4SSatish Balay       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
459fabe8965SStefano Zampini 
4609566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl, &lndmapi));
4619566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
462fabe8965SStefano Zampini 
463fabe8965SStefano Zampini       /* compute adjacency of isolated separators node */
4649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(gcnt, &workis));
465fabe8965SStefano Zampini       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
46648a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
467fabe8965SStefano Zampini       }
46848a46eb9SPierre Jolivet       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
469fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4709566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
4719566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
472fabe8965SStefano Zampini       }
473fabe8965SStefano Zampini 
474fabe8965SStefano Zampini       /* no communications since all the ISes correspond to locally owned rows */
4759566063dSJacob Faibussowitsch       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
476fabe8965SStefano Zampini 
477fabe8965SStefano Zampini       /* end communicate global id of separators */
4789566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
479fabe8965SStefano Zampini 
480fabe8965SStefano Zampini       /* communicate new layers : create a matrix and transpose it */
4819566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(dnz, A->rmap->n));
4829566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(onz, A->rmap->n));
483fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) {
484fabe8965SStefano Zampini         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
485fabe8965SStefano Zampini           const PetscInt *idxs;
486fabe8965SStefano Zampini           PetscInt        s;
487fabe8965SStefano Zampini 
4889566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(workis[j], &s));
4899566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
4909566063dSJacob Faibussowitsch           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
491fabe8965SStefano Zampini           j++;
492fabe8965SStefano Zampini         }
493fabe8965SStefano Zampini       }
49408401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
495fabe8965SStefano Zampini 
496fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4979566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
4989566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
499fabe8965SStefano Zampini       }
500fabe8965SStefano Zampini 
501fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
5029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(j, &vals));
503fabe8965SStefano Zampini       for (i = 0; i < j; i++) vals[i] = 1.0;
504fabe8965SStefano Zampini 
5059566063dSJacob Faibussowitsch       PetscCall(MatCreate(comm, &A2));
5069566063dSJacob Faibussowitsch       PetscCall(MatSetType(A2, MATMPIAIJ));
5079566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
5089566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
5099566063dSJacob Faibussowitsch       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
510fabe8965SStefano Zampini       for (i = 0, j = 0; i < A2->rmap->n; i++) {
511fabe8965SStefano Zampini         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
512fabe8965SStefano Zampini         const PetscInt *idxs;
513fabe8965SStefano Zampini 
514fabe8965SStefano Zampini         if (s) {
5159566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5169566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
5179566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(workis[j], &idxs));
518fabe8965SStefano Zampini           j++;
519fabe8965SStefano Zampini         }
520fabe8965SStefano Zampini       }
52108401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
5229566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
5239566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
5249566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
5259566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
526fabe8965SStefano Zampini 
527fabe8965SStefano Zampini       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
528fabe8965SStefano Zampini       for (i = 0, j = 0; i < nl; i++)
529fabe8965SStefano Zampini         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
5309566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
5319566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
5329566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5339566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A2));
534fabe8965SStefano Zampini 
535fabe8965SStefano Zampini       /* extend local to global map to include connected isolated separators */
5369566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
53728b400f6SJacob Faibussowitsch       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
5389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
5399566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
54028b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5419566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
5429566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
54328b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5449566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
5459566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5469566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
547fabe8965SStefano Zampini 
548fabe8965SStefano Zampini       /* add new nodes to the local-to-global map */
5499566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
5509566063dSJacob Faibussowitsch       PetscCall(ISExpand(ndsub, is2, &is));
5519566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is2));
5529566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5539566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
554fabe8965SStefano Zampini 
5559566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A3));
5569566063dSJacob Faibussowitsch       PetscCall(PetscFree(lndmapi));
557d0609cedSBarry Smith       MatPreallocateEnd(dnz, onz);
55848a46eb9SPierre Jolivet       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
5599566063dSJacob Faibussowitsch       PetscCall(PetscFree(workis));
560fabe8965SStefano Zampini     }
5619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
5629566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
5639566063dSJacob Faibussowitsch     PetscCall(PetscFree(ndmapc));
5649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndmap));
5659566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndsub));
5669566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
5679566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-matis_nd_l2g_view"));
568fabe8965SStefano Zampini     break;
569fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
57091d376acSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)&dm));
57191d376acSStefano Zampini     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
57291d376acSStefano Zampini       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
57391d376acSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*l2g));
57491d376acSStefano Zampini       if (*l2g) PetscFunctionReturn(0);
57591d376acSStefano Zampini     }
576fabe8965SStefano Zampini     if (ismpiaij) {
5779566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
578fabe8965SStefano Zampini     } else if (ismpibaij) {
5799566063dSJacob Faibussowitsch       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
58098921bdaSJacob Faibussowitsch     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
581c9225affSStefano Zampini     if (A->rmap->n) {
582fabe8965SStefano Zampini       PetscInt dc, oc, stc, *aux;
583c9225affSStefano Zampini 
584ebf8cefbSJunchao Zhang       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
5859566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
586d0dbe9f7SStefano Zampini       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
5879566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
5889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
589c9225affSStefano Zampini       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
590ebf8cefbSJunchao Zhang       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
5919566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
592c9225affSStefano Zampini     } else {
5939566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
594c9225affSStefano Zampini     }
5959566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
597fabe8965SStefano Zampini     break;
598d71ae5a4SJacob Faibussowitsch   default:
599d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
600c9225affSStefano Zampini   }
601c9225affSStefano Zampini   PetscFunctionReturn(0);
602c9225affSStefano Zampini }
603c9225affSStefano Zampini 
604d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
605d71ae5a4SJacob Faibussowitsch {
606c9225affSStefano Zampini   Mat                    lA, Ad, Ao, B = NULL;
6076989cf23SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
6086989cf23SStefano Zampini   IS                     is;
6096989cf23SStefano Zampini   MPI_Comm               comm;
6106989cf23SStefano Zampini   void                  *ptrs[2];
6116989cf23SStefano Zampini   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
612c9225affSStefano Zampini   const PetscInt        *garray;
6136989cf23SStefano Zampini   PetscScalar           *dd, *od, *aa, *data;
614c9225affSStefano Zampini   const PetscInt        *di, *dj, *oi, *oj;
615c9225affSStefano Zampini   const PetscInt        *odi, *odj, *ooi, *ooj;
6166989cf23SStefano Zampini   PetscInt              *aux, *ii, *jj;
617c9225affSStefano Zampini   PetscInt               bs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
618c9225affSStefano Zampini   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE;
619c9225affSStefano Zampini   PetscMPIInt            size;
6206989cf23SStefano Zampini 
621ab4d48faSStefano Zampini   PetscFunctionBegin;
6229566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
6239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
624c9225affSStefano Zampini   if (size == 1) {
6259566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
626c9225affSStefano Zampini     PetscFunctionReturn(0);
627c9225affSStefano Zampini   }
628c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
6299566063dSJacob Faibussowitsch     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
6309566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
6319566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
6329566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
6339566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
6349566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6359566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSize(B, bs));
6369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
637c9225affSStefano Zampini     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
638c9225affSStefano Zampini     reuse = MAT_REUSE_MATRIX;
639c9225affSStefano Zampini   }
640c9225affSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
641c9225affSStefano Zampini     Mat            *newlA, lA;
642c9225affSStefano Zampini     IS              rows, cols;
643c9225affSStefano Zampini     const PetscInt *ridx, *cidx;
644c9225affSStefano Zampini     PetscInt        rbs, cbs, nr, nc;
645c9225affSStefano Zampini 
646c9225affSStefano Zampini     if (!B) B = *newmat;
6479566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
6489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
6499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
6509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
6519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
6529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
6539566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
6549566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
655c9225affSStefano Zampini     if (rl2g != cl2g) {
6569566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
657c9225affSStefano Zampini     } else {
6589566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)rows));
659c9225affSStefano Zampini       cols = rows;
660c9225affSStefano Zampini     }
6619566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(B, &lA));
6629566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
6639566063dSJacob Faibussowitsch     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
6649566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
6659566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
6669566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rows));
6679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cols));
668c9225affSStefano Zampini     if (!lA->preallocated) { /* first time */
6699566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
6709566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(B, lA));
6719566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)lA));
672c9225affSStefano Zampini     }
6739566063dSJacob Faibussowitsch     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
6749566063dSJacob Faibussowitsch     PetscCall(MatDestroySubMatrices(1, &newlA));
6759566063dSJacob Faibussowitsch     PetscCall(MatISScaleDisassembling_Private(B));
6769566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
6779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
6789566063dSJacob Faibussowitsch     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
679c9225affSStefano Zampini     else *newmat = B;
680c9225affSStefano Zampini     PetscFunctionReturn(0);
681c9225affSStefano Zampini   }
682c9225affSStefano Zampini   /* rectangular case, just compress out the column space */
6839566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
6849566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
685c9225affSStefano Zampini   if (ismpiaij) {
686c9225affSStefano Zampini     bs = 1;
6879566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
688c9225affSStefano Zampini   } else if (ismpibaij) {
6899566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6909566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
6919566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
6929566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
69398921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
6949566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ad, &dd));
6959566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ao, &od));
69628b400f6SJacob Faibussowitsch   PetscCheck(garray, comm, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
6976989cf23SStefano Zampini 
6986989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
6999566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
7009566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
7019566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &dr, &dc));
7029566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
7039566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
70428b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
7059566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
70628b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
707c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
708c9225affSStefano Zampini   /* store original pointers to be restored later */
7099371c9d4SSatish Balay   odi = di;
7109371c9d4SSatish Balay   odj = dj;
7119371c9d4SSatish Balay   ooi = oi;
7129371c9d4SSatish Balay   ooj = oj;
7136989cf23SStefano Zampini 
7146989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
7159566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(comm, dr / bs, str / bs, 1, &is));
716c9225affSStefano Zampini   if (bs > 1) {
717c9225affSStefano Zampini     IS is2;
718c9225affSStefano Zampini 
7199566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7209566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
7219566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, i, aux, PETSC_COPY_VALUES, &is2));
7229566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
724c9225affSStefano Zampini     is = is2;
725c9225affSStefano Zampini   }
7269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
728e363d98aSStefano Zampini   if (dr) {
7299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
730c9225affSStefano Zampini     for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
731c9225affSStefano Zampini     for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = garray[i];
7329566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
733e363d98aSStefano Zampini     lc = dc + oc;
734e363d98aSStefano Zampini   } else {
7359566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, 0, NULL, PETSC_OWN_POINTER, &is));
736e363d98aSStefano Zampini     lc = 0;
737e363d98aSStefano Zampini   }
7389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7406989cf23SStefano Zampini 
7416989cf23SStefano Zampini   /* create MATIS object */
7429566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7439566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7449566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
7459566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, bs));
7469566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7496989cf23SStefano Zampini 
7506989cf23SStefano Zampini   /* merge local matrices */
7519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7536989cf23SStefano Zampini   ii  = aux;
7546989cf23SStefano Zampini   jj  = aux + dr + 1;
7556989cf23SStefano Zampini   aa  = data;
7566989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7579371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7589371c9d4SSatish Balay     for (; jd < *di; jd++) {
7599371c9d4SSatish Balay       *jj++ = *dj++;
7609371c9d4SSatish Balay       *aa++ = *dd++;
7619371c9d4SSatish Balay     }
7629371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7639371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7649371c9d4SSatish Balay       *aa++ = *od++;
7659371c9d4SSatish Balay     }
7666989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7676989cf23SStefano Zampini   }
7686989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
769c9225affSStefano Zampini 
7709566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
77128b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7729566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
77328b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7759566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
776c9225affSStefano Zampini 
7776989cf23SStefano Zampini   ii = aux;
7786989cf23SStefano Zampini   jj = aux + dr + 1;
7796989cf23SStefano Zampini   aa = data;
7809566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
7816989cf23SStefano Zampini 
7826989cf23SStefano Zampini   /* create containers to destroy the data */
7836989cf23SStefano Zampini   ptrs[0] = aux;
7846989cf23SStefano Zampini   ptrs[1] = data;
7856989cf23SStefano Zampini   for (i = 0; i < 2; i++) {
7866989cf23SStefano Zampini     PetscContainer c;
7876989cf23SStefano Zampini 
7889566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
7899566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, ptrs[i]));
7909566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
7919566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)lA, names[i], (PetscObject)c));
7929566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
7936989cf23SStefano Zampini   }
794c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7969566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
797c9225affSStefano Zampini   }
7986989cf23SStefano Zampini 
7996989cf23SStefano Zampini   /* finalize matrix */
8009566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
8019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
8029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
8039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
804c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
8059566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
806c9225affSStefano Zampini   } else *newmat = B;
8076989cf23SStefano Zampini   PetscFunctionReturn(0);
8086989cf23SStefano Zampini }
8096989cf23SStefano Zampini 
810d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
811d71ae5a4SJacob Faibussowitsch {
8125e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8135e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8145e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8155e3038f0Sstefano_zampini   MPI_Comm               comm;
8165b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8175b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8189e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8195e3038f0Sstefano_zampini 
820ab4d48faSStefano Zampini   PetscFunctionBegin;
8219566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8225e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8235e3038f0Sstefano_zampini   rnest  = NULL;
8245e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8255e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8265e3038f0Sstefano_zampini 
8279566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
82828b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)(*newmat))->type_name);
8299566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8309566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8315e3038f0Sstefano_zampini     if (isnest) {
8329566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8335e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8345e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8355e3038f0Sstefano_zampini     }
8365e3038f0Sstefano_zampini   }
8379566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8399566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8409566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8415e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8425e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8435e3038f0Sstefano_zampini       PetscBool ismatis;
8449e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8455e3038f0Sstefano_zampini 
8465e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8475e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8485e3038f0Sstefano_zampini 
8495e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
850013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8519e7b2b25Sstefano_zampini       if (istrans[ij]) {
8529e7b2b25Sstefano_zampini         Mat T, lT;
8539566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8549566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
85528b400f6SJacob 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);
8569566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8579566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8589e7b2b25Sstefano_zampini       } else {
8599566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
86028b400f6SJacob 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);
8619566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8629e7b2b25Sstefano_zampini       }
8635e3038f0Sstefano_zampini 
8645e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8659566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8669566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8675e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
868aed4548fSBarry 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);
869aed4548fSBarry 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);
8705e3038f0Sstefano_zampini       lr[i] = l1;
8715e3038f0Sstefano_zampini       lc[j] = l2;
8725e3038f0Sstefano_zampini 
8735e3038f0Sstefano_zampini       /* check compatibilty for local matrix reusage */
8745e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8755e3038f0Sstefano_zampini     }
8765e3038f0Sstefano_zampini   }
8775e3038f0Sstefano_zampini 
87876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8795e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8805e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8815e3038f0Sstefano_zampini       rl2g = NULL;
8825e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8835e3038f0Sstefano_zampini         PetscInt n1, n2;
8845e3038f0Sstefano_zampini 
8855e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8869e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8879e7b2b25Sstefano_zampini           Mat T;
8889e7b2b25Sstefano_zampini 
8899566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8909566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8919e7b2b25Sstefano_zampini         } else {
8929566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8939e7b2b25Sstefano_zampini         }
8949566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8955e3038f0Sstefano_zampini         if (!n1) continue;
8965e3038f0Sstefano_zampini         if (!rl2g) {
8975e3038f0Sstefano_zampini           rl2g = cl2g;
8985e3038f0Sstefano_zampini         } else {
8995e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9005e3038f0Sstefano_zampini           PetscBool       same;
9015e3038f0Sstefano_zampini 
9029566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
90308401ef6SPierre 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);
9049566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9059566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9069566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9079566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9089566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
90928b400f6SJacob 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);
9105e3038f0Sstefano_zampini         }
9115e3038f0Sstefano_zampini       }
9125e3038f0Sstefano_zampini     }
9135e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9145e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9155e3038f0Sstefano_zampini       rl2g = NULL;
9165e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9175e3038f0Sstefano_zampini         PetscInt n1, n2;
9185e3038f0Sstefano_zampini 
9195e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9209e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9219e7b2b25Sstefano_zampini           Mat T;
9229e7b2b25Sstefano_zampini 
9239566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9249566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9259e7b2b25Sstefano_zampini         } else {
9269566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9279e7b2b25Sstefano_zampini         }
9289566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9295e3038f0Sstefano_zampini         if (!n1) continue;
9305e3038f0Sstefano_zampini         if (!rl2g) {
9315e3038f0Sstefano_zampini           rl2g = cl2g;
9325e3038f0Sstefano_zampini         } else {
9335e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9345e3038f0Sstefano_zampini           PetscBool       same;
9355e3038f0Sstefano_zampini 
9369566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
93708401ef6SPierre 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);
9389566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9399566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9409566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9419566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9429566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
94328b400f6SJacob 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);
9445e3038f0Sstefano_zampini         }
9455e3038f0Sstefano_zampini       }
9465e3038f0Sstefano_zampini     }
94776bd3646SJed Brown   }
9485e3038f0Sstefano_zampini 
9495e3038f0Sstefano_zampini   B = NULL;
9505e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9515b003df0Sstefano_zampini     PetscInt stl;
9525b003df0Sstefano_zampini 
9535e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9545e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9565b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9575e3038f0Sstefano_zampini       Mat             usedmat;
9585e3038f0Sstefano_zampini       Mat_IS         *matis;
9595e3038f0Sstefano_zampini       const PetscInt *idxs;
9605e3038f0Sstefano_zampini 
9615e3038f0Sstefano_zampini       /* local IS for local NEST */
9629566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9635e3038f0Sstefano_zampini 
9645e3038f0Sstefano_zampini       /* l2gmap */
9655e3038f0Sstefano_zampini       j       = 0;
9665e3038f0Sstefano_zampini       usedmat = nest[i][j];
9679e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
96828b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9699e7b2b25Sstefano_zampini 
9709e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9719e7b2b25Sstefano_zampini         Mat T;
9729566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9739e7b2b25Sstefano_zampini         usedmat = T;
9749e7b2b25Sstefano_zampini       }
9755e3038f0Sstefano_zampini       matis = (Mat_IS *)(usedmat->data);
9769566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9779e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9789566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9799566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9809e7b2b25Sstefano_zampini       } else {
9819566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9829566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9839e7b2b25Sstefano_zampini       }
9849566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9855e3038f0Sstefano_zampini       stl += lr[i];
9865e3038f0Sstefano_zampini     }
9879566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9885e3038f0Sstefano_zampini 
9895e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9905e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9919566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9925b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9935e3038f0Sstefano_zampini       Mat             usedmat;
9945e3038f0Sstefano_zampini       Mat_IS         *matis;
9955e3038f0Sstefano_zampini       const PetscInt *idxs;
9965e3038f0Sstefano_zampini 
9975e3038f0Sstefano_zampini       /* local IS for local NEST */
9989566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
9995e3038f0Sstefano_zampini 
10005e3038f0Sstefano_zampini       /* l2gmap */
10015e3038f0Sstefano_zampini       j       = 0;
10025e3038f0Sstefano_zampini       usedmat = nest[j][i];
10039e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100428b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10059e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10069e7b2b25Sstefano_zampini         Mat T;
10079566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10089e7b2b25Sstefano_zampini         usedmat = T;
10099e7b2b25Sstefano_zampini       }
10105e3038f0Sstefano_zampini       matis = (Mat_IS *)(usedmat->data);
10119566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10129e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10139566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10149566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10159e7b2b25Sstefano_zampini       } else {
10169566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10179566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10189e7b2b25Sstefano_zampini       }
10199566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10205e3038f0Sstefano_zampini       stl += lc[i];
10215e3038f0Sstefano_zampini     }
10229566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10235e3038f0Sstefano_zampini 
10245e3038f0Sstefano_zampini     /* Create MATIS */
10259566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10269566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10279566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10289566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10299566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10309566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10318546b261SStefano Zampini     { /* hack : avoid setup of scatters */
10328546b261SStefano Zampini       Mat_IS *matis     = (Mat_IS *)(B->data);
10338546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10348546b261SStefano Zampini     }
10359566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10389566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10399566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10409e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
104148a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10429e7b2b25Sstefano_zampini     }
10439566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10449566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10458546b261SStefano Zampini     { /* hack : setup of scatters done here */
10468546b261SStefano Zampini       Mat_IS *matis = (Mat_IS *)(B->data);
10478546b261SStefano Zampini 
10488546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10499566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10508546b261SStefano Zampini     }
10519566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10529566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10535e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10549566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10555e3038f0Sstefano_zampini     } else {
10565e3038f0Sstefano_zampini       *newmat = B;
10575e3038f0Sstefano_zampini     }
10585e3038f0Sstefano_zampini   } else {
10595e3038f0Sstefano_zampini     if (lreuse) {
10609566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10615e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10625e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10635e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10649566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
106548a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10665e3038f0Sstefano_zampini           }
10675e3038f0Sstefano_zampini         }
10685e3038f0Sstefano_zampini       }
10695e3038f0Sstefano_zampini     } else {
10705b003df0Sstefano_zampini       PetscInt stl;
10715b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10729566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10735b003df0Sstefano_zampini         stl += lr[i];
10745e3038f0Sstefano_zampini       }
10755b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10769566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10775b003df0Sstefano_zampini         stl += lc[i];
10785e3038f0Sstefano_zampini       }
10799566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1080ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
108148a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1082ab4d48faSStefano Zampini       }
10839566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10849566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10855e3038f0Sstefano_zampini     }
10869566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10879566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10885e3038f0Sstefano_zampini   }
10895e3038f0Sstefano_zampini 
10905b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10915b003df0Sstefano_zampini   convert = PETSC_FALSE;
10929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-matis_convert_local_nest", &convert, NULL));
10935b003df0Sstefano_zampini   if (convert) {
10945b003df0Sstefano_zampini     Mat              M;
10955b003df0Sstefano_zampini     MatISLocalFields lf;
10965b003df0Sstefano_zampini     PetscContainer   c;
10975b003df0Sstefano_zampini 
10989566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
10999566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
11009566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
11019566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
11025b003df0Sstefano_zampini 
11035b003df0Sstefano_zampini     /* attach local fields to the matrix */
11049566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11065b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11075b003df0Sstefano_zampini       PetscInt n, st;
11085b003df0Sstefano_zampini 
11099566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11109566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11119566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11125b003df0Sstefano_zampini     }
11135b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11145b003df0Sstefano_zampini       PetscInt n, st;
11155b003df0Sstefano_zampini 
11169566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11179566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11189566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11195b003df0Sstefano_zampini     }
11205b003df0Sstefano_zampini     lf->nr = nr;
11215b003df0Sstefano_zampini     lf->nc = nc;
11229566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)), &c));
11239566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, lf));
11249566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyFields_Private));
11259566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)(*newmat), "_convert_nest_lfields", (PetscObject)c));
11269566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
11275b003df0Sstefano_zampini   }
11285b003df0Sstefano_zampini 
11295e3038f0Sstefano_zampini   /* Free workspace */
113048a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
113148a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11329566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11345e3038f0Sstefano_zampini   PetscFunctionReturn(0);
11355e3038f0Sstefano_zampini }
11365e3038f0Sstefano_zampini 
1137d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1138d71ae5a4SJacob Faibussowitsch {
1139ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1140ad219c80Sstefano_zampini   Vec                ll, rr;
1141ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1142ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1143ad219c80Sstefano_zampini 
1144ad219c80Sstefano_zampini   PetscFunctionBegin;
1145ad219c80Sstefano_zampini   if (l) {
1146ad219c80Sstefano_zampini     ll = matis->y;
11479566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11489566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11499566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1150ad219c80Sstefano_zampini   } else {
1151ad219c80Sstefano_zampini     ll = NULL;
1152ad219c80Sstefano_zampini   }
1153ad219c80Sstefano_zampini   if (r) {
1154ad219c80Sstefano_zampini     rr = matis->x;
11559566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11569566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11579566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1158ad219c80Sstefano_zampini   } else {
1159ad219c80Sstefano_zampini     rr = NULL;
1160ad219c80Sstefano_zampini   }
1161ad219c80Sstefano_zampini   if (ll) {
11629566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11639566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11649566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1165ad219c80Sstefano_zampini   }
1166ad219c80Sstefano_zampini   if (rr) {
11679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11699566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1170ad219c80Sstefano_zampini   }
11719566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
1172ad219c80Sstefano_zampini   PetscFunctionReturn(0);
1173ad219c80Sstefano_zampini }
1174ad219c80Sstefano_zampini 
1175d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1176d71ae5a4SJacob Faibussowitsch {
11777fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11787fa8f2d3SStefano Zampini   MatInfo        info;
11793966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11807fa8f2d3SStefano Zampini   PetscInt       bs;
11817fa8f2d3SStefano Zampini 
11827fa8f2d3SStefano Zampini   PetscFunctionBegin;
11839566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1184a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11859566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11867fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11877fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11887fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11897fa8f2d3SStefano Zampini     isend[3] = info.memory;
11907fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1191a2ccb5f9Sstefano_zampini   } else {
1192a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1193a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1194a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1195a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1196a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1197a2ccb5f9Sstefano_zampini   }
1198314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
11997fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
12007fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
12017fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
12027fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
12037fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
12047fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1205314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
12067fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
12071c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12087fa8f2d3SStefano Zampini 
12097fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12107fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12117fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12127fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12137fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1214314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12157fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
12161c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12177fa8f2d3SStefano Zampini 
12187fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12197fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12207fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12217fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12227fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12237fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12247fa8f2d3SStefano Zampini   }
12257fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12267fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12277fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12287fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12295e3038f0Sstefano_zampini   PetscFunctionReturn(0);
12305e3038f0Sstefano_zampini }
12315e3038f0Sstefano_zampini 
1232d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1233d71ae5a4SJacob Faibussowitsch {
1234d7f69cd0SStefano Zampini   Mat C, lC, lA;
1235d7f69cd0SStefano Zampini 
1236d7f69cd0SStefano Zampini   PetscFunctionBegin;
12377fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1238cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1239cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12409566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12419566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
12429566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
12439566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12449566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12459566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1246e432b41dSStefano Zampini   } else C = *B;
1247d7f69cd0SStefano Zampini 
1248d7f69cd0SStefano Zampini   /* perform local transposition */
12499566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12509566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12519566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12529566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12539566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1254d7f69cd0SStefano Zampini 
1255cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1256d7f69cd0SStefano Zampini     *B = C;
1257d7f69cd0SStefano Zampini   } else {
12589566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1259d7f69cd0SStefano Zampini   }
12609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1262d7f69cd0SStefano Zampini   PetscFunctionReturn(0);
1263d7f69cd0SStefano Zampini }
1264d7f69cd0SStefano Zampini 
1265d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1266d71ae5a4SJacob Faibussowitsch {
12673fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12683fd1c9e7SStefano Zampini 
12693fd1c9e7SStefano Zampini   PetscFunctionBegin;
12704b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12719566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12729566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12733fd1c9e7SStefano Zampini   }
12749566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12759566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12763fd1c9e7SStefano Zampini   PetscFunctionReturn(0);
12773fd1c9e7SStefano Zampini }
12783fd1c9e7SStefano Zampini 
1279d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1280d71ae5a4SJacob Faibussowitsch {
12814b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12823fd1c9e7SStefano Zampini 
12833fd1c9e7SStefano Zampini   PetscFunctionBegin;
12849566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12859566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12863fd1c9e7SStefano Zampini   PetscFunctionReturn(0);
12873fd1c9e7SStefano Zampini }
12883fd1c9e7SStefano Zampini 
1289d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1290d71ae5a4SJacob Faibussowitsch {
1291f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1292f26d0771SStefano Zampini 
1293f26d0771SStefano Zampini   PetscFunctionBegin;
1294aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
12959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
12969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
12979566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1298f26d0771SStefano Zampini   PetscFunctionReturn(0);
1299f26d0771SStefano Zampini }
1300f26d0771SStefano Zampini 
1301d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1302d71ae5a4SJacob Faibussowitsch {
1303f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1304f26d0771SStefano Zampini 
1305f26d0771SStefano Zampini   PetscFunctionBegin;
1306aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column block indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
13079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13099566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1310f26d0771SStefano Zampini   PetscFunctionReturn(0);
1311f26d0771SStefano Zampini }
1312f26d0771SStefano Zampini 
1313d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1314d71ae5a4SJacob Faibussowitsch {
1315a8116848SStefano Zampini   Mat             locmat, newlocmat;
1316a8116848SStefano Zampini   Mat_IS         *newmatis;
1317a8116848SStefano Zampini   const PetscInt *idxs;
1318a8116848SStefano Zampini   PetscInt        i, m, n;
1319a8116848SStefano Zampini 
1320a8116848SStefano Zampini   PetscFunctionBegin;
1321a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1322a8116848SStefano Zampini     PetscBool ismatis;
1323a8116848SStefano Zampini 
13249566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
132528b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1326a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
132728b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
132828b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1329a8116848SStefano Zampini   }
1330a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
133176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
133276bd3646SJed Brown     Vec                rtest, ltest;
133376bd3646SJed Brown     const PetscScalar *array;
133476bd3646SJed Brown 
13359566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13369566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13379566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
133848a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13399566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13409566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13419566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13429566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13439566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1344aed4548fSBarry 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]));
13459566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13489566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
134948a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13519566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13529566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13539566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13549566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1355aed4548fSBarry 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]));
13569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13579566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13589566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13599566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
136076bd3646SJed Brown   }
1361a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1362a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1363a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1364a8116848SStefano Zampini     IS                     is;
1365a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1366306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
136794342113SStefano Zampini     PetscBool              cong;
1368a8116848SStefano Zampini     MPI_Comm               comm;
1369a8116848SStefano Zampini 
13709566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13719566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13729566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13739566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1374306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1375306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13769566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13779566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13789566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13799566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13809566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13819566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1382a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13839566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13849566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13869566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1387a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13889566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
13899566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
13909566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13919566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13929371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
13939371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
13949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
13959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
13963d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1397a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1398a8116848SStefano Zampini         lidxs[newloc]      = i;
1399a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1400a8116848SStefano Zampini       }
14019566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14039566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1405a8116848SStefano Zampini     /* local is to extract local submatrix */
1406a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14079566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14089566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
140994342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14109566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14119566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1412a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1413a8116848SStefano Zampini     } else {
1414a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1415a8116848SStefano Zampini 
1416a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14179566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14189566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14199566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14209566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1421a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14229566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14239566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14269371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14279371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14289566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14299566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14303d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1431a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1432a8116848SStefano Zampini           lidxs[newloc]      = i;
1433a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1434a8116848SStefano Zampini         }
14359566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14369566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14379566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14389566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1439a8116848SStefano Zampini       /* local is to extract local submatrix */
14409566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14419566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14429566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1443a8116848SStefano Zampini     }
14449566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1445a8116848SStefano Zampini   } else {
14469566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1447a8116848SStefano Zampini   }
14489566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1449a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14509566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1451a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14529566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14539566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1454a8116848SStefano Zampini   }
14559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14569566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1457a8116848SStefano Zampini   PetscFunctionReturn(0);
1458a8116848SStefano Zampini }
1459a8116848SStefano Zampini 
1460d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1461d71ae5a4SJacob Faibussowitsch {
14622b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14632b404112SStefano Zampini   PetscBool ismatis;
14642b404112SStefano Zampini 
14652b404112SStefano Zampini   PetscFunctionBegin;
14669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
146728b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14682b404112SStefano Zampini   b = (Mat_IS *)B->data;
14699566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14709566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14712b404112SStefano Zampini   PetscFunctionReturn(0);
14722b404112SStefano Zampini }
14732b404112SStefano Zampini 
1474d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1475d71ae5a4SJacob Faibussowitsch {
1476527b2640SStefano Zampini   Vec                v;
1477527b2640SStefano Zampini   const PetscScalar *array;
1478527b2640SStefano Zampini   PetscInt           i, n;
14796bd84002SStefano Zampini 
14806bd84002SStefano Zampini   PetscFunctionBegin;
1481527b2640SStefano Zampini   *missing = PETSC_FALSE;
14829566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14839566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14849566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14859566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14869371c9d4SSatish Balay   for (i = 0; i < n; i++)
14879371c9d4SSatish Balay     if (array[i] == 0.) break;
14889566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
14899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1490527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1491527b2640SStefano Zampini   if (d) {
1492527b2640SStefano Zampini     *d = -1;
1493527b2640SStefano Zampini     if (*missing) {
1494527b2640SStefano Zampini       PetscInt rstart;
14959566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1496527b2640SStefano Zampini       *d = i + rstart;
1497527b2640SStefano Zampini     }
1498527b2640SStefano Zampini   }
14996bd84002SStefano Zampini   PetscFunctionReturn(0);
15006bd84002SStefano Zampini }
15016bd84002SStefano Zampini 
1502d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1503d71ae5a4SJacob Faibussowitsch {
150428f4e0baSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(B->data);
150528f4e0baSStefano Zampini   const PetscInt *gidxs;
15064f2d7cafSStefano Zampini   PetscInt        nleaves;
150728f4e0baSStefano Zampini 
150828f4e0baSStefano Zampini   PetscFunctionBegin;
15094f2d7cafSStefano Zampini   if (matis->sf) PetscFunctionReturn(0);
15109566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15139566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1516e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15189566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15209566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15219566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1523a8116848SStefano Zampini   } else {
1524a8116848SStefano Zampini     matis->csf          = matis->sf;
1525a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1526a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1527a8116848SStefano Zampini   }
152828f4e0baSStefano Zampini   PetscFunctionReturn(0);
152928f4e0baSStefano Zampini }
15302e1947a5SStefano Zampini 
1531eb82efa4SStefano Zampini /*@
153211a5261eSBarry Smith    MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing MatPtAP.
153375d48cdbSStefano Zampini 
1534d083f849SBarry Smith    Collective
153575d48cdbSStefano Zampini 
153675d48cdbSStefano Zampini    Input Parameters:
153775d48cdbSStefano Zampini +  A - the matrix
153875d48cdbSStefano Zampini -  store - the boolean flag
153975d48cdbSStefano Zampini 
154075d48cdbSStefano Zampini    Level: advanced
154175d48cdbSStefano Zampini 
1542db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
154375d48cdbSStefano Zampini @*/
1544d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1545d71ae5a4SJacob Faibussowitsch {
154675d48cdbSStefano Zampini   PetscFunctionBegin;
154775d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
154875d48cdbSStefano Zampini   PetscValidType(A, 1);
154975d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1550cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
155175d48cdbSStefano Zampini   PetscFunctionReturn(0);
155275d48cdbSStefano Zampini }
155375d48cdbSStefano Zampini 
1554d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1555d71ae5a4SJacob Faibussowitsch {
155675d48cdbSStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
155775d48cdbSStefano Zampini 
155875d48cdbSStefano Zampini   PetscFunctionBegin;
155975d48cdbSStefano Zampini   matis->storel2l = store;
156048a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
156175d48cdbSStefano Zampini   PetscFunctionReturn(0);
156275d48cdbSStefano Zampini }
156375d48cdbSStefano Zampini 
156475d48cdbSStefano Zampini /*@
1565f03112d0SStefano Zampini    MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1566f03112d0SStefano Zampini 
1567d083f849SBarry Smith    Collective
1568f03112d0SStefano Zampini 
1569f03112d0SStefano Zampini    Input Parameters:
1570f03112d0SStefano Zampini +  A - the matrix
1571f03112d0SStefano Zampini -  fix - the boolean flag
1572f03112d0SStefano Zampini 
1573f03112d0SStefano Zampini    Level: advanced
1574f03112d0SStefano Zampini 
157511a5261eSBarry Smith    Note:
157611a5261eSBarry Smith    When fix is true, new local matrices and l2g maps are generated during the final assembly process.
1577f03112d0SStefano Zampini 
157811a5261eSBarry Smith .seealso: `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1579f03112d0SStefano Zampini @*/
1580d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1581d71ae5a4SJacob Faibussowitsch {
1582f03112d0SStefano Zampini   PetscFunctionBegin;
1583f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1584f03112d0SStefano Zampini   PetscValidType(A, 1);
1585f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1586cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
1587f03112d0SStefano Zampini   PetscFunctionReturn(0);
1588f03112d0SStefano Zampini }
1589f03112d0SStefano Zampini 
1590d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1591d71ae5a4SJacob Faibussowitsch {
1592f03112d0SStefano Zampini   Mat_IS *matis = (Mat_IS *)(A->data);
1593f03112d0SStefano Zampini 
1594f03112d0SStefano Zampini   PetscFunctionBegin;
1595f03112d0SStefano Zampini   matis->locempty = fix;
1596f03112d0SStefano Zampini   PetscFunctionReturn(0);
1597f03112d0SStefano Zampini }
1598f03112d0SStefano Zampini 
1599f03112d0SStefano Zampini /*@
160011a5261eSBarry Smith    MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1601a88811baSStefano Zampini 
1602d083f849SBarry Smith    Collective
1603a88811baSStefano Zampini 
1604a88811baSStefano Zampini    Input Parameters:
1605a88811baSStefano Zampini +  B - the matrix
1606a88811baSStefano Zampini .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1607a88811baSStefano Zampini            (same value is used for all local rows)
1608a88811baSStefano Zampini .  d_nnz - array containing the number of nonzeros in the various rows of the
1609a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
1610a88811baSStefano Zampini            or NULL, if d_nz is used to specify the nonzero structure.
1611a88811baSStefano Zampini            The size of this array is equal to the number of local rows, i.e 'm'.
1612a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1613a88811baSStefano Zampini            the diagonal entry even if it is zero.
1614a88811baSStefano Zampini .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1615a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1616a88811baSStefano Zampini -  o_nnz - array containing the number of nonzeros in the various rows of the
1617a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
1618a88811baSStefano Zampini            each row) or NULL, if o_nz is used to specify the nonzero
1619a88811baSStefano Zampini            structure. The size of this array is equal to the number
1620a88811baSStefano Zampini            of local rows, i.e 'm'.
1621a88811baSStefano Zampini 
1622a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1623a88811baSStefano Zampini 
1624a88811baSStefano Zampini    Level: intermediate
1625a88811baSStefano Zampini 
162611a5261eSBarry Smith    Note:
162711a5261eSBarry Smith    This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
162811a5261eSBarry Smith    from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1629a88811baSStefano Zampini    matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1630a88811baSStefano Zampini 
1631db781477SPatrick Sanan .seealso: `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1632a88811baSStefano Zampini @*/
1633d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1634d71ae5a4SJacob Faibussowitsch {
16352e1947a5SStefano Zampini   PetscFunctionBegin;
16362e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
16372e1947a5SStefano Zampini   PetscValidType(B, 1);
1638cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
16392e1947a5SStefano Zampini   PetscFunctionReturn(0);
16402e1947a5SStefano Zampini }
16412e1947a5SStefano Zampini 
1642844bd0d7SStefano Zampini /* this is used by DMDA */
1643d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1644d71ae5a4SJacob Faibussowitsch {
16452e1947a5SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(B->data);
164628f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
16472e1947a5SStefano Zampini 
16482e1947a5SStefano Zampini   PetscFunctionBegin;
16499566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
16509371c9d4SSatish Balay   if (!d_nnz)
16519371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
16529371c9d4SSatish Balay   else
16539371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
16544f2d7cafSStefano Zampini 
16559371c9d4SSatish Balay   if (!o_nnz)
16569371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
16579371c9d4SSatish Balay   else
16589371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
16594f2d7cafSStefano Zampini 
16609566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16619566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
16629566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
16639566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16644f2d7cafSStefano Zampini 
16654f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
16669566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
16670f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
16689566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
16690f2f62c7SStefano Zampini #endif
16704f2d7cafSStefano Zampini 
1671fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1672fc989267SStefano Zampini     PetscInt b;
1673fc989267SStefano Zampini 
1674fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1675ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1676fc989267SStefano Zampini   }
16779566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16784f2d7cafSStefano Zampini 
167900a59248SStefano Zampini   nlocalcols /= bs;
168000a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
16819566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16820f2f62c7SStefano Zampini 
16830f2f62c7SStefano Zampini   /* for other matrix types */
16849566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
16852e1947a5SStefano Zampini   PetscFunctionReturn(0);
16862e1947a5SStefano Zampini }
1687b4319ba4SBarry Smith 
1688d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1689d71ae5a4SJacob Faibussowitsch {
16903927de2eSStefano Zampini   Mat_IS         *matis = (Mat_IS *)(A->data);
16913927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1692ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
16933927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
16943927de2eSStefano Zampini   PetscInt        lrows, lcols;
16953927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1696f03112d0SStefano Zampini   PetscMPIInt     size;
16973927de2eSStefano Zampini   PetscBool       isdense, issbaij;
16983927de2eSStefano Zampini 
16993927de2eSStefano Zampini   PetscFunctionBegin;
17009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
17019566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
17029566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
17039566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
17049566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
17059566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
17069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1707e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
17089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
17090dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1710ecf5a873SStefano Zampini 
17119566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
17123927de2eSStefano Zampini   /*
1713ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
17143927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
17153927de2eSStefano Zampini   */
17169566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1717d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
17183927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
17199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
17209566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1721f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
17225f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
17233927de2eSStefano Zampini   }
17249566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
17253927de2eSStefano Zampini 
17263927de2eSStefano Zampini   /*
17273927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
17283927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
17293927de2eSStefano Zampini   */
17309566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
17313927de2eSStefano Zampini   /* preallocation as a MATAIJ */
17323927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
17333927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
173412dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
173512dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1736ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
17373927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17383927de2eSStefano Zampini           my_dnz[i] += 1;
17393927de2eSStefano Zampini         } else { /* offdiag block */
17403927de2eSStefano Zampini           my_onz[i] += 1;
17413927de2eSStefano Zampini         }
17423927de2eSStefano Zampini       }
17433927de2eSStefano Zampini     }
1744bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1745bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1746bb1015c3SStefano Zampini     PetscBool       done;
17479566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17485f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1749bb1015c3SStefano Zampini     jptr = jj;
1750bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1751bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1752bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1753bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1754bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1755bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1756bb1015c3SStefano Zampini           my_dnz[i] += 1;
1757bb1015c3SStefano Zampini         } else { /* offdiag block */
1758bb1015c3SStefano Zampini           my_onz[i] += 1;
1759bb1015c3SStefano Zampini         }
1760bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1761bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1762bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1763bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1764bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1765bb1015c3SStefano Zampini           } else {
1766bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1767bb1015c3SStefano Zampini           }
1768bb1015c3SStefano Zampini         }
1769bb1015c3SStefano Zampini       }
1770bb1015c3SStefano Zampini     }
17719566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
17725f80ce2aSJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)(matis->A)), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1773bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
17743927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
17753927de2eSStefano Zampini       const PetscInt *cols;
1776ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
17779566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
17783927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
17793927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1780ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
17813927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17823927de2eSStefano Zampini           my_dnz[i] += 1;
17833927de2eSStefano Zampini         } else { /* offdiag block */
17843927de2eSStefano Zampini           my_onz[i] += 1;
17853927de2eSStefano Zampini         }
17863927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1787d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
17883927de2eSStefano Zampini           owner = row_ownership[index_col];
17893927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1790d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
17913927de2eSStefano Zampini           } else {
1792d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
17933927de2eSStefano Zampini           }
17943927de2eSStefano Zampini         }
17953927de2eSStefano Zampini       }
17969566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
17973927de2eSStefano Zampini     }
17983927de2eSStefano Zampini   }
179948a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
18009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
18019566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1802ecf5a873SStefano Zampini 
1803ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
18043927de2eSStefano Zampini   if (maxreduce) {
18059566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
18069566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
18079566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
18089566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
18093927de2eSStefano Zampini   } else {
18109566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
18119566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
18129566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
18139566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
18143927de2eSStefano Zampini   }
18159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
18163927de2eSStefano Zampini 
18173927de2eSStefano Zampini   /* Resize preallocation if overestimated */
18183927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
18193927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
18203927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
18213927de2eSStefano Zampini   }
18221670daf9Sstefano_zampini 
18231670daf9Sstefano_zampini   /* Set preallocation */
18249566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
18259566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
18269566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
182753b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
182853b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
182953b44cf5SStefano Zampini 
183053b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
183153b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
183253b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
183353b44cf5SStefano Zampini     }
183453b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
183553b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
18363927de2eSStefano Zampini   }
18379566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
18389566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
18399566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1840d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
18419566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
18429566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
18433927de2eSStefano Zampini   PetscFunctionReturn(0);
18443927de2eSStefano Zampini }
18453927de2eSStefano Zampini 
1846d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1847d71ae5a4SJacob Faibussowitsch {
1848b7ce53b6SStefano Zampini   Mat_IS            *matis = (Mat_IS *)(mat->data);
1849487b449aSStefano Zampini   Mat                local_mat, MT;
185053b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1851b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1852b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1853f03112d0SStefano Zampini   PetscMPIInt        size;
18541683a169SBarry Smith   const PetscScalar *array;
1855b7ce53b6SStefano Zampini 
1856b7ce53b6SStefano Zampini   PetscFunctionBegin;
18579566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1858f03112d0SStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
18591670daf9Sstefano_zampini     Mat      B;
186053b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1861487b449aSStefano Zampini     PetscInt rbs, cbs;
18621670daf9Sstefano_zampini 
18639566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18649566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
186553b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
186653b44cf5SStefano Zampini       IS              rows, cols;
186753b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
186853b44cf5SStefano Zampini       PetscInt        i, nw, *work;
186953b44cf5SStefano Zampini 
18709566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18719566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
187253b44cf5SStefano Zampini       nw = nw / rbs;
18739566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nw, &work));
187453b44cf5SStefano Zampini       for (i = 0; i < nw; i++) work[ridxs[i]] += 1;
18759371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18769371c9d4SSatish Balay         if (!work[i] || work[i] > 1) break;
187753b44cf5SStefano Zampini       if (i == nw) {
18789566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18799566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18809566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18819566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
188253b44cf5SStefano Zampini       }
18839566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18849566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
1885e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18869566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18879566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
188853b44cf5SStefano Zampini         nw = nw / cbs;
18899566063dSJacob Faibussowitsch         PetscCall(PetscCalloc1(nw, &work));
189053b44cf5SStefano Zampini         for (i = 0; i < nw; i++) work[cidxs[i]] += 1;
18919371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18929371c9d4SSatish Balay           if (!work[i] || work[i] > 1) break;
189353b44cf5SStefano Zampini         if (i == nw) {
18949566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18959566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18969566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18979566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
189853b44cf5SStefano Zampini         }
18999566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
19009566063dSJacob Faibussowitsch         PetscCall(PetscFree(work));
190153b44cf5SStefano Zampini       } else if (irows) {
19029566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
190353b44cf5SStefano Zampini         icols = irows;
190453b44cf5SStefano Zampini       }
190553b44cf5SStefano Zampini     } else {
19069566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
19079566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
19089566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
19099566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
191053b44cf5SStefano Zampini     }
191153b44cf5SStefano Zampini     if (!irows || !icols) {
19129566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
19139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
191453b44cf5SStefano Zampini       goto general_assembly;
191553b44cf5SStefano Zampini     }
19169566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1917487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
19189566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
19199566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
19209566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)(*M), "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1921487b449aSStefano Zampini     } else {
1922487b449aSStefano Zampini       Mat C;
1923487b449aSStefano Zampini 
19249566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
19259566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1926487b449aSStefano Zampini     }
19279566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
19289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
19299566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
19307c03b4e8SStefano Zampini     PetscFunctionReturn(0);
19317c03b4e8SStefano Zampini   }
193253b44cf5SStefano Zampini general_assembly:
19339566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19369566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19379566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19389566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19399566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19409566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19419566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1942aed4548fSBarry Smith   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(matis->A))->type_name);
194376bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
194476bd3646SJed Brown     PetscBool lb[4], bb[4];
194576bd3646SJed Brown 
1946b9ed4604SStefano Zampini     lb[0] = isseqdense;
1947b9ed4604SStefano Zampini     lb[1] = isseqaij;
1948b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1949b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
19501c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1951aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
195276bd3646SJed Brown   }
1953b7ce53b6SStefano Zampini 
1954487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
19559566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19569566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19579566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19589566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
19599566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
1960b7ce53b6SStefano Zampini   } else {
196153b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1962487b449aSStefano Zampini 
1963b7ce53b6SStefano Zampini     /* some checks */
1964487b449aSStefano Zampini     MT = *M;
19659566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19669566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19679566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
196808401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
196908401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
197008401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
197108401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
197208401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
197308401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
19749566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
1975b7ce53b6SStefano Zampini   }
1976d9a9e74cSStefano Zampini 
19778546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
19789566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
19798546b261SStefano Zampini     isseqaij = PETSC_TRUE;
1980d9a9e74cSStefano Zampini   } else {
19819566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
1982d9a9e74cSStefano Zampini     local_mat = matis->A;
1983d9a9e74cSStefano Zampini   }
1984686e3a49SStefano Zampini 
1985b7ce53b6SStefano Zampini   /* Set values */
19869566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1987b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
198865066ba5SStefano Zampini     PetscInt i, *dummy;
1989ecf5a873SStefano Zampini 
19909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
199165066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
19929566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
19939566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
19949566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
19959566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
19969566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
1997686e3a49SStefano Zampini   } else if (isseqaij) {
19986afe12f5SStefano Zampini     const PetscInt *blocks;
19996afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
2000686e3a49SStefano Zampini     PetscBool       done;
20011683a169SBarry Smith     PetscScalar    *sarray;
2002686e3a49SStefano Zampini 
20039566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
200428b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
20059566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
20069566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
20076afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
20086afe12f5SStefano Zampini       PetscInt sum;
20096afe12f5SStefano Zampini 
20106afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
20116afe12f5SStefano Zampini       if (sum == nvtxs) {
20126afe12f5SStefano Zampini         PetscInt r;
20136afe12f5SStefano Zampini 
20146afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
20156bdcaf15SBarry Smith           PetscAssert(blocks[i] == xadj[r + 1] - xadj[r], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid block sizes prescribed for block %" PetscInt_FMT ": expected %" PetscInt_FMT ", got %" PetscInt_FMT, i, blocks[i], xadj[r + 1] - xadj[r]);
20169566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
20176afe12f5SStefano Zampini           r += blocks[i];
20186afe12f5SStefano Zampini         }
20196afe12f5SStefano Zampini       } else {
202048a46eb9SPierre Jolivet         for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], adjncy + xadj[i], sarray + xadj[i], ADD_VALUES));
20216afe12f5SStefano Zampini       }
20226afe12f5SStefano Zampini     } else {
202348a46eb9SPierre Jolivet       for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], adjncy + xadj[i], sarray + xadj[i], ADD_VALUES));
20246afe12f5SStefano Zampini     }
20259566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
202628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
20279566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2028686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
2029ecf5a873SStefano Zampini     PetscInt i;
2030c0962df8SStefano Zampini 
2031686e3a49SStefano Zampini     for (i = 0; i < local_rows; i++) {
2032686e3a49SStefano Zampini       PetscInt        j;
2033ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2034686e3a49SStefano Zampini 
20359566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
20369566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
20379566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2038686e3a49SStefano Zampini     }
2039b7ce53b6SStefano Zampini   }
20409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20419566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
20431baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2044487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20459566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2046487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2047487b449aSStefano Zampini     *M = MT;
2048b7ce53b6SStefano Zampini   }
2049b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2050b7ce53b6SStefano Zampini }
2051b7ce53b6SStefano Zampini 
2052b7ce53b6SStefano Zampini /*@
205311a5261eSBarry Smith     MatISGetMPIXAIJ - Converts `MATIS` matrix into a parallel `MATAIJ` format
2054b7ce53b6SStefano Zampini 
2055d8d19677SJose E. Roman   Input Parameters:
205611a5261eSBarry Smith +  mat - the matrix (should be of type `MATIS`)
205711a5261eSBarry Smith -  reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
2058b7ce53b6SStefano Zampini 
2059b7ce53b6SStefano Zampini   Output Parameter:
206011a5261eSBarry Smith .  newmat - the matrix in `MATAIJ` format
2061b7ce53b6SStefano Zampini 
2062b7ce53b6SStefano Zampini   Level: developer
2063b7ce53b6SStefano Zampini 
206411a5261eSBarry Smith   Note:
206511a5261eSBarry Smith     This function has been deprecated and it will be removed in future releases. Update your code to use the `MatConvert()` interface.
2066b7ce53b6SStefano Zampini 
2067db781477SPatrick Sanan .seealso: `MATIS`, `MatConvert()`
2068b7ce53b6SStefano Zampini @*/
2069d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
2070d71ae5a4SJacob Faibussowitsch {
2071b7ce53b6SStefano Zampini   PetscFunctionBegin;
2072b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2073b7ce53b6SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, reuse, 2);
2074b7ce53b6SStefano Zampini   PetscValidPointer(newmat, 3);
2075487b449aSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
2076b7ce53b6SStefano Zampini     PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 3);
2077b7ce53b6SStefano Zampini     PetscCheckSameComm(mat, 1, *newmat, 3);
207808401ef6SPierre Jolivet     PetscCheck(mat != *newmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse the same matrix");
2079b7ce53b6SStefano Zampini   }
2080cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetMPIXAIJ_C", (Mat, MatType, MatReuse, Mat *), (mat, MATAIJ, reuse, newmat));
2081b7ce53b6SStefano Zampini   PetscFunctionReturn(0);
2082b7ce53b6SStefano Zampini }
2083b7ce53b6SStefano Zampini 
2084d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2085d71ae5a4SJacob Faibussowitsch {
2086ad6194a2SStefano Zampini   Mat_IS  *matis = (Mat_IS *)(mat->data);
2087c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2088ad6194a2SStefano Zampini   Mat      B, localmat;
2089ad6194a2SStefano Zampini 
2090ad6194a2SStefano Zampini   PetscFunctionBegin;
20919566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20939566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20949566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20959566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20969566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20979566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20989566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20999566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
21009566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
21019566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
21029566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
21039566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
21049566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
21059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
21069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2107ad6194a2SStefano Zampini   *newmat = B;
2108ad6194a2SStefano Zampini   PetscFunctionReturn(0);
2109ad6194a2SStefano Zampini }
2110ad6194a2SStefano Zampini 
2111d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2112d71ae5a4SJacob Faibussowitsch {
211369796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
211469796d55SStefano Zampini   PetscBool local_sym;
211569796d55SStefano Zampini 
211669796d55SStefano Zampini   PetscFunctionBegin;
21179566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
21181c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
211969796d55SStefano Zampini   PetscFunctionReturn(0);
212069796d55SStefano Zampini }
212169796d55SStefano Zampini 
2122d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2123d71ae5a4SJacob Faibussowitsch {
212469796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
212569796d55SStefano Zampini   PetscBool local_sym;
212669796d55SStefano Zampini 
212769796d55SStefano Zampini   PetscFunctionBegin;
2128e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2129e432b41dSStefano Zampini     *flg = PETSC_FALSE;
2130e432b41dSStefano Zampini     PetscFunctionReturn(0);
2131e432b41dSStefano Zampini   }
21329566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
21331c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
213469796d55SStefano Zampini   PetscFunctionReturn(0);
213569796d55SStefano Zampini }
213669796d55SStefano Zampini 
2137d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2138d71ae5a4SJacob Faibussowitsch {
213945471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
214045471136SStefano Zampini   PetscBool local_sym;
214145471136SStefano Zampini 
214245471136SStefano Zampini   PetscFunctionBegin;
2143e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
214445471136SStefano Zampini     *flg = PETSC_FALSE;
214545471136SStefano Zampini     PetscFunctionReturn(0);
214645471136SStefano Zampini   }
21479566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
21481c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
214945471136SStefano Zampini   PetscFunctionReturn(0);
215045471136SStefano Zampini }
215145471136SStefano Zampini 
2152d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2153d71ae5a4SJacob Faibussowitsch {
2154b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2155b4319ba4SBarry Smith 
2156b4319ba4SBarry Smith   PetscFunctionBegin;
21579566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21589566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21599566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21609566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21619566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21639566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21659566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21669566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2167a8116848SStefano Zampini   if (b->sf != b->csf) {
21689566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21699566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2170f03112d0SStefano Zampini   } else b->csf = NULL;
21719566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21739566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2175d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2176d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21779566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21789566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21822e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", NULL));
21849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
2198b4319ba4SBarry Smith   PetscFunctionReturn(0);
2199b4319ba4SBarry Smith }
2200b4319ba4SBarry Smith 
2201d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2202d71ae5a4SJacob Faibussowitsch {
2203b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2204b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2205b4319ba4SBarry Smith 
2206b4319ba4SBarry Smith   PetscFunctionBegin;
2207b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
22089566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
22099566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2210b4319ba4SBarry Smith 
2211b4319ba4SBarry Smith   /* multiply the local matrix */
22129566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2213b4319ba4SBarry Smith 
2214b4319ba4SBarry Smith   /* scatter product back into global memory */
22159566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
22169566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
22179566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2218b4319ba4SBarry Smith   PetscFunctionReturn(0);
2219b4319ba4SBarry Smith }
2220b4319ba4SBarry Smith 
2221d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2222d71ae5a4SJacob Faibussowitsch {
2223650997f4SStefano Zampini   Vec temp_vec;
22242e74eeadSLisandro Dalcin 
22252e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2226650997f4SStefano Zampini   if (v3 != v2) {
22279566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
22289566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2229650997f4SStefano Zampini   } else {
22309566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22319566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
22329566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22339566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2235650997f4SStefano Zampini   }
22362e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22372e74eeadSLisandro Dalcin }
22382e74eeadSLisandro Dalcin 
2239d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2240d71ae5a4SJacob Faibussowitsch {
22412e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
22422e74eeadSLisandro Dalcin 
2243e176bc59SStefano Zampini   PetscFunctionBegin;
22442e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
22459566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22469566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22472e74eeadSLisandro Dalcin 
22482e74eeadSLisandro Dalcin   /* multiply the local matrix */
22499566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
22502e74eeadSLisandro Dalcin 
22512e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22529566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22539566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22549566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22552e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22562e74eeadSLisandro Dalcin }
22572e74eeadSLisandro Dalcin 
2258d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2259d71ae5a4SJacob Faibussowitsch {
2260650997f4SStefano Zampini   Vec temp_vec;
22612e74eeadSLisandro Dalcin 
22622e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2263650997f4SStefano Zampini   if (v3 != v2) {
22649566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22659566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2266650997f4SStefano Zampini   } else {
22679566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22689566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22699566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22709566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2272650997f4SStefano Zampini   }
22732e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
22742e74eeadSLisandro Dalcin }
22752e74eeadSLisandro Dalcin 
2276d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2277d71ae5a4SJacob Faibussowitsch {
2278b4319ba4SBarry Smith   Mat_IS     *a = (Mat_IS *)A->data;
2279b4319ba4SBarry Smith   PetscViewer sviewer;
2280ee2491ecSStefano Zampini   PetscBool   isascii, view = PETSC_TRUE;
2281b4319ba4SBarry Smith 
2282b4319ba4SBarry Smith   PetscFunctionBegin;
22839566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2284ee2491ecSStefano Zampini   if (isascii) {
2285ee2491ecSStefano Zampini     PetscViewerFormat format;
2286ee2491ecSStefano Zampini 
22879566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2288ee2491ecSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2289ee2491ecSStefano Zampini   }
2290ee2491ecSStefano Zampini   if (!view) PetscFunctionReturn(0);
22919566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22929566063dSJacob Faibussowitsch   PetscCall(MatView(a->A, sviewer));
22939566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22949566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
2295b4319ba4SBarry Smith   PetscFunctionReturn(0);
2296b4319ba4SBarry Smith }
2297b4319ba4SBarry Smith 
2298d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2299d71ae5a4SJacob Faibussowitsch {
2300b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2301b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2302b89f26deSStefano Zampini   const PetscScalar *lv;
2303b89f26deSStefano Zampini   PetscInt           bs;
2304b89f26deSStefano Zampini 
2305b89f26deSStefano Zampini   PetscFunctionBegin;
23069566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
23079566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
23089566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
230948a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
23109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(bs, MPIU_SCALAR, &nodeType));
23119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
23129566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
23139566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
23149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2315b89f26deSStefano Zampini   if (values) *values = is->bdiag;
2316b89f26deSStefano Zampini   PetscFunctionReturn(0);
2317b89f26deSStefano Zampini }
2318b89f26deSStefano Zampini 
2319d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2320d71ae5a4SJacob Faibussowitsch {
2321e176bc59SStefano Zampini   Vec             cglobal, rglobal;
23228546b261SStefano Zampini   IS              from;
23238546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2324b89f26deSStefano Zampini   PetscScalar     sum;
23258546b261SStefano Zampini   const PetscInt *garray;
23268546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2327e432b41dSStefano Zampini   VecType         rtype;
2328b4319ba4SBarry Smith 
2329b4319ba4SBarry Smith   PetscFunctionBegin;
23309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
23319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
23329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
23339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
23349566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
23359566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
23369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
23379566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
23389566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
23399566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
23409566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
23419566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
23429566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
23439566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
23449566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
23459566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
23469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
23479566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
23489566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
23499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
23509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2351e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
23529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
23539566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
23549566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
23559566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
23569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
23578546b261SStefano Zampini   } else {
23589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
23598546b261SStefano Zampini     is->cctx = is->rctx;
23608546b261SStefano Zampini   }
23619566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2362b89f26deSStefano Zampini 
23638546b261SStefano Zampini   /* interface counter vector (local) */
23649566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
23659566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
23669566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
23679566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23689566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23699566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23709566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23719566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
23729566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2373b89f26deSStefano Zampini 
2374b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
23759566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2376b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2377e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
23789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2379b0cc1f67SStefano Zampini 
2380b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
23819566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
23828546b261SStefano Zampini   PetscFunctionReturn(0);
23838546b261SStefano Zampini }
23848546b261SStefano Zampini 
2385d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2386d71ae5a4SJacob Faibussowitsch {
2387e432b41dSStefano Zampini   IS                         is;
2388e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2389e432b41dSStefano Zampini   const PetscInt            *idxs;
2390e432b41dSStefano Zampini   PetscHSetI                 ht;
2391e432b41dSStefano Zampini   PetscInt                  *nidxs;
2392e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2393e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2394e432b41dSStefano Zampini 
2395e432b41dSStefano Zampini   PetscFunctionBegin;
23969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
23979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
23989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
23999566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
24009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2401e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
2402e432b41dSStefano Zampini     PetscBool missing;
24039371c9d4SSatish Balay     if (idxs[i] < 0) {
24049371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
24059371c9d4SSatish Balay       continue;
24069371c9d4SSatish Balay     }
24079566063dSJacob Faibussowitsch     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2408e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2409e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2410e432b41dSStefano Zampini   }
24119566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
24121c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2413e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2414e432b41dSStefano Zampini     *nmap = NULL;
2415e432b41dSStefano Zampini     *lmap = NULL;
24169566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
24179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2418e432b41dSStefano Zampini     PetscFunctionReturn(0);
2419e432b41dSStefano Zampini   }
2420e432b41dSStefano Zampini 
2421e432b41dSStefano Zampini   /* New l2g map without negative or repeated indices */
24229566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
24239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
24249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
24259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
24269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2427e432b41dSStefano Zampini 
2428e432b41dSStefano Zampini   /* New local l2g map for repeated indices */
24299566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
24309566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
24319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
24329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2433e432b41dSStefano Zampini 
24349566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
24359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2436e432b41dSStefano Zampini   PetscFunctionReturn(0);
2437e432b41dSStefano Zampini }
2438e432b41dSStefano Zampini 
2439d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2440d71ae5a4SJacob Faibussowitsch {
24418546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2442e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2443e432b41dSStefano Zampini   PetscBool              cong, freem[]                       = {PETSC_FALSE, PETSC_FALSE};
2444e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
24458546b261SStefano Zampini 
24468546b261SStefano Zampini   PetscFunctionBegin;
2447fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2448fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2449e432b41dSStefano Zampini 
24509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
24519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
24539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
24549566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2455e432b41dSStefano Zampini 
2456fc989267SStefano Zampini   /* If NULL, local space matches global space */
2457fc989267SStefano Zampini   if (!rmapping) {
2458fc989267SStefano Zampini     IS is;
2459fc989267SStefano Zampini 
24609566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
24619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
24629566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
24639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2464e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2465e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2466e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
24679566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2468e432b41dSStefano Zampini     if (rmapping == cmapping) {
24699566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2470e432b41dSStefano Zampini       is->cmapping = is->rmapping;
24719566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2472e432b41dSStefano Zampini       localcmapping = localrmapping;
2473fc989267SStefano Zampini     }
2474fc989267SStefano Zampini   }
2475fc989267SStefano Zampini   if (!cmapping) {
2476fc989267SStefano Zampini     IS is;
2477fc989267SStefano Zampini 
24789566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
24799566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
24809566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
24819566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2482e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2483e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
24849566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2485e432b41dSStefano Zampini   }
2486e432b41dSStefano Zampini   if (!is->rmapping) {
24879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2488e432b41dSStefano Zampini     is->rmapping = rmapping;
2489e432b41dSStefano Zampini   }
2490e432b41dSStefano Zampini   if (!is->cmapping) {
24919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2492e432b41dSStefano Zampini     is->cmapping = cmapping;
2493fc989267SStefano Zampini   }
2494fc989267SStefano Zampini 
2495fc989267SStefano Zampini   /* Clean up */
24969566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2497872cf891SStefano Zampini   if (is->csf != is->sf) {
24989566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
24999566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2500f03112d0SStefano Zampini   } else is->csf = NULL;
25019566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
25029566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
25039566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
25043bbff08aSStefano Zampini 
2505fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2506fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
25079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
25089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
25099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
25109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2511e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2512e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
25136625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
25146625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
25156625354bSStefano Zampini 
25169566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
25179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
25189566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
25199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
25209566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
25216625354bSStefano Zampini     }
25221c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2523e432b41dSStefano Zampini     if (same) {
25249566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
25259566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2526e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2527e432b41dSStefano Zampini     }
25286625354bSStefano Zampini   }
25299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
25309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2531e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
25329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
25339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
25349566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
25359566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
25366625354bSStefano Zampini 
25376625354bSStefano Zampini   /* Create the local matrix A */
25389566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
25399566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
25409566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
25419566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
25429566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
25439566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
25449566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
25459566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
25469566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
25479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
25489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2549b4319ba4SBarry Smith 
2550fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
25519566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2552fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
2553fc989267SStefano Zampini   PetscFunctionReturn(0);
2554fc989267SStefano Zampini }
2555fc989267SStefano Zampini 
2556d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2557d71ae5a4SJacob Faibussowitsch {
2558fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2559fc989267SStefano Zampini 
2560fc989267SStefano Zampini   PetscFunctionBegin;
25619566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
256248a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
2563b4319ba4SBarry Smith   PetscFunctionReturn(0);
2564b4319ba4SBarry Smith }
2565b4319ba4SBarry Smith 
2566d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2567d71ae5a4SJacob Faibussowitsch {
25682e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2569f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
25702e74eeadSLisandro Dalcin 
25712e74eeadSLisandro Dalcin   PetscFunctionBegin;
25729566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2573e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25749566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25759566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2576e432b41dSStefano Zampini   } else {
25779566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2578e432b41dSStefano Zampini   }
25792e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
25802e74eeadSLisandro Dalcin }
25812e74eeadSLisandro Dalcin 
2582d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2583d71ae5a4SJacob Faibussowitsch {
258497563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2585f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
258697563a80SStefano Zampini 
258797563a80SStefano Zampini   PetscFunctionBegin;
25889566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2589e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25909566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25919566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2592e432b41dSStefano Zampini   } else {
25939566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, rows_l, values, addv));
2594e432b41dSStefano Zampini   }
259597563a80SStefano Zampini   PetscFunctionReturn(0);
259697563a80SStefano Zampini }
259797563a80SStefano Zampini 
2598d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2599d71ae5a4SJacob Faibussowitsch {
2600b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2601b4319ba4SBarry Smith 
2602b4319ba4SBarry Smith   PetscFunctionBegin;
2603e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
26049566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2605872cf891SStefano Zampini   } else {
26069566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2607872cf891SStefano Zampini   }
2608b4319ba4SBarry Smith   PetscFunctionReturn(0);
2609b4319ba4SBarry Smith }
2610b4319ba4SBarry Smith 
2611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2612d71ae5a4SJacob Faibussowitsch {
2613f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2614f0006bf2SLisandro Dalcin 
2615f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2616e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
26179566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2618b4f971dfSStefano Zampini   } else {
26199566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2620b4f971dfSStefano Zampini   }
2621f0006bf2SLisandro Dalcin   PetscFunctionReturn(0);
2622f0006bf2SLisandro Dalcin }
2623f0006bf2SLisandro Dalcin 
2624d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2625d71ae5a4SJacob Faibussowitsch {
2626f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2627f0ae7da4SStefano Zampini 
2628f0ae7da4SStefano Zampini   PetscFunctionBegin;
2629f0ae7da4SStefano Zampini   if (!n) {
2630f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2631f0ae7da4SStefano Zampini   } else {
2632f0ae7da4SStefano Zampini     PetscInt i;
2633f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2634f0ae7da4SStefano Zampini 
2635f0ae7da4SStefano Zampini     if (columns) {
26369566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2637f0ae7da4SStefano Zampini     } else {
26389566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2639f0ae7da4SStefano Zampini     }
2640f0ae7da4SStefano Zampini     if (diag != 0.) {
2641f0ae7da4SStefano Zampini       const PetscScalar *array;
26429566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
264348a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
26449566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2645f0ae7da4SStefano Zampini     }
26469566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
26479566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2648f0ae7da4SStefano Zampini   }
2649f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2650f0ae7da4SStefano Zampini }
2651f0ae7da4SStefano Zampini 
2652d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2653d71ae5a4SJacob Faibussowitsch {
26546e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
26556e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
26566e520ac8SStefano Zampini   PetscInt *lrows;
26572e74eeadSLisandro Dalcin 
26582e74eeadSLisandro Dalcin   PetscFunctionBegin;
2659cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2660f0ae7da4SStefano Zampini     PetscBool cong;
266126b0207aSStefano Zampini 
26629566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
266326b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
266408401ef6SPierre 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");
2665aed4548fSBarry 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");
2666aed4548fSBarry 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");
2667f0ae7da4SStefano Zampini   }
26686e520ac8SStefano Zampini   /* get locally owned rows */
26699566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
26706e520ac8SStefano Zampini   /* fix right hand side if needed */
26716e520ac8SStefano Zampini   if (x && b) {
26726e520ac8SStefano Zampini     const PetscScalar *xx;
26736e520ac8SStefano Zampini     PetscScalar       *bb;
26746e520ac8SStefano Zampini 
26759566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
26769566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
26776e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
26789566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
26799566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
26802e74eeadSLisandro Dalcin   }
26816e520ac8SStefano Zampini   /* get rows associated to the local matrices */
26829566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
26839566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
26849566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
26856e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
26869566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
26879566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26889566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
26909371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
26919371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
26929566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
26939566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2694d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2695d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
26962e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
26972e74eeadSLisandro Dalcin }
26982e74eeadSLisandro Dalcin 
2699d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2700d71ae5a4SJacob Faibussowitsch {
2701b4319ba4SBarry Smith   PetscFunctionBegin;
27029566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
2703f0ae7da4SStefano Zampini   PetscFunctionReturn(0);
2704f0ae7da4SStefano Zampini }
27052205254eSKarl Rupp 
2706d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2707d71ae5a4SJacob Faibussowitsch {
2708f0ae7da4SStefano Zampini   PetscFunctionBegin;
27099566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
2710b4319ba4SBarry Smith   PetscFunctionReturn(0);
2711b4319ba4SBarry Smith }
2712b4319ba4SBarry Smith 
2713d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2714d71ae5a4SJacob Faibussowitsch {
2715b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2716b4319ba4SBarry Smith 
2717b4319ba4SBarry Smith   PetscFunctionBegin;
27189566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
2719b4319ba4SBarry Smith   PetscFunctionReturn(0);
2720b4319ba4SBarry Smith }
2721b4319ba4SBarry Smith 
2722d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2723d71ae5a4SJacob Faibussowitsch {
2724b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2725d0dbe9f7SStefano Zampini   PetscBool lnnz;
2726b4319ba4SBarry Smith 
2727b4319ba4SBarry Smith   PetscFunctionBegin;
27289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2729872cf891SStefano Zampini   /* fix for local empty rows/cols */
2730872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2731872cf891SStefano Zampini     Mat                    newlA;
2732f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2733f03112d0SStefano Zampini     IS                     nzr, nzc;
2734f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2735f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2736872cf891SStefano Zampini 
27379566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
27389566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
273948a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
27409566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
274148a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
27429566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
27439566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2744e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2745f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
27469566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2747f03112d0SStefano Zampini 
2748872cf891SStefano Zampini       /* extract valid submatrix */
27499566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2750f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2751f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
27529566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
27539566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2754f03112d0SStefano Zampini       newlA = is->A;
2755f03112d0SStefano Zampini     }
2756e432b41dSStefano Zampini 
2757f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2758f03112d0SStefano Zampini     if (newl2g) {
2759e432b41dSStefano Zampini       IS              zr, zc;
2760e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2761e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2762f03112d0SStefano Zampini 
27639566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
27649566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
27659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
27669566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
27679566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
27689566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
27699566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
27709566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
27719566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2772e432b41dSStefano Zampini 
27739566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2774e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
27759566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
27769566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2777e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
27789566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2779e432b41dSStefano Zampini 
27809566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
27819566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
27829566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
27839566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
27849566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
27859566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
27869566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
27879566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
27889566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
27899566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
27909566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27919566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2792f03112d0SStefano Zampini     }
27939566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
27949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
27959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
27969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2797872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2798f03112d0SStefano Zampini   }
2799d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2800d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
2801d0dbe9f7SStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2802d0dbe9f7SStefano Zampini   if (lnnz) A->nonzerostate++;
2803b4319ba4SBarry Smith   PetscFunctionReturn(0);
2804b4319ba4SBarry Smith }
2805b4319ba4SBarry Smith 
2806d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
2807d71ae5a4SJacob Faibussowitsch {
2808b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2809b4319ba4SBarry Smith 
2810b4319ba4SBarry Smith   PetscFunctionBegin;
2811b4319ba4SBarry Smith   *local = is->A;
2812b4319ba4SBarry Smith   PetscFunctionReturn(0);
2813b4319ba4SBarry Smith }
2814b4319ba4SBarry Smith 
2815d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
2816d71ae5a4SJacob Faibussowitsch {
28173b3b1effSJed Brown   PetscFunctionBegin;
28183b3b1effSJed Brown   *local = NULL;
28193b3b1effSJed Brown   PetscFunctionReturn(0);
28203b3b1effSJed Brown }
28213b3b1effSJed Brown 
2822b4319ba4SBarry Smith /*@
282311a5261eSBarry Smith     MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2824b4319ba4SBarry Smith 
2825b4319ba4SBarry Smith   Input Parameter:
2826b4319ba4SBarry Smith .  mat - the matrix
2827b4319ba4SBarry Smith 
2828b4319ba4SBarry Smith   Output Parameter:
2829eb82efa4SStefano Zampini .  local - the local matrix
2830b4319ba4SBarry Smith 
2831b4319ba4SBarry Smith   Level: advanced
2832b4319ba4SBarry Smith 
2833b4319ba4SBarry Smith   Notes:
2834b4319ba4SBarry Smith     This can be called if you have precomputed the nonzero structure of the
2835b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
283611a5261eSBarry Smith   of the `MatSetValues()` operation.
2837b4319ba4SBarry Smith 
283811a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
283996a6f129SJed Brown 
284011a5261eSBarry Smith .seealso: `MATIS`, `MatISRestoreLocalMat()`
2841b4319ba4SBarry Smith @*/
2842d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
2843d71ae5a4SJacob Faibussowitsch {
2844b4319ba4SBarry Smith   PetscFunctionBegin;
28450700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2846b4319ba4SBarry Smith   PetscValidPointer(local, 2);
2847cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
2848b4319ba4SBarry Smith   PetscFunctionReturn(0);
2849b4319ba4SBarry Smith }
2850b4319ba4SBarry Smith 
28513b3b1effSJed Brown /*@
285211a5261eSBarry Smith     MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
28533b3b1effSJed Brown 
28543b3b1effSJed Brown   Input Parameter:
28553b3b1effSJed Brown .  mat - the matrix
28563b3b1effSJed Brown 
28573b3b1effSJed Brown   Output Parameter:
28583b3b1effSJed Brown .  local - the local matrix
28593b3b1effSJed Brown 
28603b3b1effSJed Brown   Level: advanced
28613b3b1effSJed Brown 
286211a5261eSBarry Smith .seealso: `MATIS`, `MatISGetLocalMat()`
28633b3b1effSJed Brown @*/
2864d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
2865d71ae5a4SJacob Faibussowitsch {
28663b3b1effSJed Brown   PetscFunctionBegin;
28673b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
28683b3b1effSJed Brown   PetscValidPointer(local, 2);
2869cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
28703b3b1effSJed Brown   PetscFunctionReturn(0);
28713b3b1effSJed Brown }
28723b3b1effSJed Brown 
2873d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
2874d71ae5a4SJacob Faibussowitsch {
28758546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
28768546b261SStefano Zampini 
28778546b261SStefano Zampini   PetscFunctionBegin;
28781baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
28799566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
28809566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
28818546b261SStefano Zampini   PetscFunctionReturn(0);
28828546b261SStefano Zampini }
28838546b261SStefano Zampini 
28848546b261SStefano Zampini /*@
288511a5261eSBarry Smith     MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
28868546b261SStefano Zampini 
2887d8d19677SJose E. Roman   Input Parameters:
2888a2b725a8SWilliam Gropp +  mat - the matrix
2889a2b725a8SWilliam Gropp -  mtype - the local matrix type
28908546b261SStefano Zampini 
28918546b261SStefano Zampini   Level: advanced
28928546b261SStefano Zampini 
2893db781477SPatrick Sanan .seealso: `MATIS`, `MatSetType()`, `MatType`
28948546b261SStefano Zampini @*/
2895d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
2896d71ae5a4SJacob Faibussowitsch {
28978546b261SStefano Zampini   PetscFunctionBegin;
28988546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2899cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
29008546b261SStefano Zampini   PetscFunctionReturn(0);
29018546b261SStefano Zampini }
29028546b261SStefano Zampini 
2903d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
2904d71ae5a4SJacob Faibussowitsch {
29053b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
29063b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
29078546b261SStefano Zampini   MatType   mtype, otype;
29088546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
29093b03a366Sstefano_zampini 
29103b03a366Sstefano_zampini   PetscFunctionBegin;
2911e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
29129566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
29139566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
2914aed4548fSBarry Smith     PetscCheck(orows == nrows && ocols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (you passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)", orows, ocols, nrows, ncols);
29159566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
29169566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
29179566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
29184e4c7dbeSStefano Zampini   }
29199566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
29209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
29213b03a366Sstefano_zampini   is->A = local;
29229566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
29239566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
292448a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
29253b03a366Sstefano_zampini   PetscFunctionReturn(0);
29263b03a366Sstefano_zampini }
29273b03a366Sstefano_zampini 
29283b03a366Sstefano_zampini /*@
292911a5261eSBarry Smith     MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
29303b03a366Sstefano_zampini 
2931*c3339decSBarry Smith   Collective
29328546b261SStefano Zampini 
2933d8d19677SJose E. Roman   Input Parameters:
2934a2b725a8SWilliam Gropp +  mat - the matrix
2935a2b725a8SWilliam Gropp -  local - the local matrix
29363b03a366Sstefano_zampini 
29373b03a366Sstefano_zampini   Level: advanced
29383b03a366Sstefano_zampini 
29393b03a366Sstefano_zampini   Notes:
294011a5261eSBarry Smith   Any previous matrix within the `MATIS` has its reference count decreased by one.
29413b03a366Sstefano_zampini 
294211a5261eSBarry Smith   This can be called if you have precomputed the local matrix and
294311a5261eSBarry Smith   want to provide it to the matrix object `MATIS`.
294411a5261eSBarry Smith 
294511a5261eSBarry Smith .seealso: `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
29463b03a366Sstefano_zampini @*/
2947d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
2948d71ae5a4SJacob Faibussowitsch {
29493b03a366Sstefano_zampini   PetscFunctionBegin;
29503b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2951b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
2952cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
29533b03a366Sstefano_zampini   PetscFunctionReturn(0);
29543b03a366Sstefano_zampini }
29553b03a366Sstefano_zampini 
2956d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
2957d71ae5a4SJacob Faibussowitsch {
29586726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29596726f965SBarry Smith 
29606726f965SBarry Smith   PetscFunctionBegin;
29619566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
29626726f965SBarry Smith   PetscFunctionReturn(0);
29636726f965SBarry Smith }
29646726f965SBarry Smith 
2965d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
2966d71ae5a4SJacob Faibussowitsch {
29672e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29682e74eeadSLisandro Dalcin 
29692e74eeadSLisandro Dalcin   PetscFunctionBegin;
29709566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
29712e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29722e74eeadSLisandro Dalcin }
29732e74eeadSLisandro Dalcin 
2974d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
2975d71ae5a4SJacob Faibussowitsch {
29762e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29772e74eeadSLisandro Dalcin 
29782e74eeadSLisandro Dalcin   PetscFunctionBegin;
29792e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
29809566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
29812e74eeadSLisandro Dalcin 
29822e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
29839566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
29849566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29859566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29862e74eeadSLisandro Dalcin   PetscFunctionReturn(0);
29872e74eeadSLisandro Dalcin }
29882e74eeadSLisandro Dalcin 
2989d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
2990d71ae5a4SJacob Faibussowitsch {
29916726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29926726f965SBarry Smith 
29936726f965SBarry Smith   PetscFunctionBegin;
29949566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
29956726f965SBarry Smith   PetscFunctionReturn(0);
29966726f965SBarry Smith }
29976726f965SBarry Smith 
2998d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
2999d71ae5a4SJacob Faibussowitsch {
3000f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3001f26d0771SStefano Zampini   Mat_IS *x;
3002f26d0771SStefano Zampini 
3003f26d0771SStefano Zampini   PetscFunctionBegin;
300476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
300576bd3646SJed Brown     PetscBool ismatis;
30069566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
300728b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
300876bd3646SJed Brown   }
3009f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
30109566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
3011f26d0771SStefano Zampini   PetscFunctionReturn(0);
3012f26d0771SStefano Zampini }
3013f26d0771SStefano Zampini 
3014d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3015d71ae5a4SJacob Faibussowitsch {
3016f26d0771SStefano Zampini   Mat                    lA;
3017e432b41dSStefano Zampini   Mat_IS                *matis = (Mat_IS *)(A->data);
3018f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3019f26d0771SStefano Zampini   IS                     is;
3020f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3021f26d0771SStefano Zampini   PetscInt               nrg;
3022f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3023f26d0771SStefano Zampini 
3024f26d0771SStefano Zampini   PetscFunctionBegin;
30259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
30269566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
30279566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
30289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
302976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
303008401ef6SPierre Jolivet     for (i = 0; i < nrl; i++) PetscCheck(rl[i] < nrg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, rl[i], nrg);
303176bd3646SJed Brown   }
30329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3033f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3034f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3035f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
30369566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
30379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
30389566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
30399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
30409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3041f26d0771SStefano Zampini   /* compute new l2g map for columns */
3042e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3043f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3044f26d0771SStefano Zampini     PetscInt        ncg;
3045f26d0771SStefano Zampini     PetscInt        ncl;
3046f26d0771SStefano Zampini 
30479566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
30489566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
30499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
30509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
305176bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
305208401ef6SPierre Jolivet       for (i = 0; i < ncl; i++) PetscCheck(cl[i] < ncg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local column index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, cl[i], ncg);
305376bd3646SJed Brown     }
30549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3055f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3056f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3057f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
30589566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
30599566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
30609566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
30619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
30629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3063f26d0771SStefano Zampini   } else {
30649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3065f26d0771SStefano Zampini     cl2g = rl2g;
3066f26d0771SStefano Zampini   }
3067f26d0771SStefano Zampini   /* create the MATIS submatrix */
30689566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
30699566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
30709566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
30719566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3072b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3073f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
30749566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
30759566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
30769566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
30779566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
30789566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
30799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
30809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30819566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3082e432b41dSStefano Zampini 
3083f26d0771SStefano Zampini   /* remove unsupported ops */
30849566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3085f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3086f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3087f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3088f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3089f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3090f26d0771SStefano Zampini   PetscFunctionReturn(0);
3091f26d0771SStefano Zampini }
3092f26d0771SStefano Zampini 
3093d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject)
3094d71ae5a4SJacob Faibussowitsch {
3095872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
30968546b261SStefano Zampini   char      type[256];
30978546b261SStefano Zampini   PetscBool flg;
3098872cf891SStefano Zampini 
3099872cf891SStefano Zampini   PetscFunctionBegin;
3100d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3101d0dbe9f7SStefano Zampini   PetscCall(PetscOptionsBool("-matis_keepassembled", "Store an assembled version if needed", "MatISKeepAssembled", a->keepassembled, &a->keepassembled, NULL));
31029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
31039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
31049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-matis_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
31051baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
31061baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3107d0609cedSBarry Smith   PetscOptionsHeadEnd();
3108872cf891SStefano Zampini   PetscFunctionReturn(0);
3109872cf891SStefano Zampini }
3110872cf891SStefano Zampini 
3111284134d9SBarry Smith /*@
311211a5261eSBarry Smith     MatCreateIS - Creates a "process" unassembled matrix, `MATIS`, assembled on each
3113284134d9SBarry Smith        process but not across processes.
3114284134d9SBarry Smith 
3115284134d9SBarry Smith    Input Parameters:
3116284134d9SBarry Smith +     comm    - MPI communicator that will share the matrix
3117e176bc59SStefano Zampini .     bs      - block size of the matrix
3118df3898eeSBarry Smith .     m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3119e176bc59SStefano Zampini .     rmap    - local to global map for rows
3120e176bc59SStefano Zampini -     cmap    - local to global map for cols
3121284134d9SBarry Smith 
3122284134d9SBarry Smith    Output Parameter:
3123284134d9SBarry Smith .    A - the resulting matrix
3124284134d9SBarry Smith 
31258e6c10adSSatish Balay    Level: advanced
31268e6c10adSSatish Balay 
312795452b02SPatrick Sanan    Notes:
3128fc989267SStefano Zampini     m and n are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
312911a5261eSBarry Smith     used in `MatMult()` operations. The sizes of rmap and cmap define the size of the local matrices.
313011a5261eSBarry Smith 
3131fc989267SStefano Zampini     If rmap (cmap) is NULL, then the local row (column) spaces matches the global space.
3132284134d9SBarry Smith 
3133db781477SPatrick Sanan .seealso: `MATIS`, `MatSetLocalToGlobalMapping()`
3134284134d9SBarry Smith @*/
3135d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3136d71ae5a4SJacob Faibussowitsch {
3137284134d9SBarry Smith   PetscFunctionBegin;
31389566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
31399566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
314048a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
31419566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
31429566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
3143284134d9SBarry Smith   PetscFunctionReturn(0);
3144284134d9SBarry Smith }
3145284134d9SBarry Smith 
3146d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3147d71ae5a4SJacob Faibussowitsch {
31488b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3149e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
31508b9382cfSStefano Zampini 
31518b9382cfSStefano Zampini   PetscFunctionBegin;
31528b9382cfSStefano Zampini   *has = PETSC_FALSE;
3153e26763e4SStefano Zampini   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(0);
3154d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
31559371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
31569371c9d4SSatish Balay     if (op == tobefiltered[i]) PetscFunctionReturn(0);
31579566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
31588b9382cfSStefano Zampini   PetscFunctionReturn(0);
31598b9382cfSStefano Zampini }
31608b9382cfSStefano Zampini 
3161d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3162d71ae5a4SJacob Faibussowitsch {
3163e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3164e432b41dSStefano Zampini 
3165e432b41dSStefano Zampini   PetscFunctionBegin;
31669566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
31679566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
31689566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3169e432b41dSStefano Zampini   PetscFunctionReturn(0);
3170e432b41dSStefano Zampini }
3171e432b41dSStefano Zampini 
3172d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3173d71ae5a4SJacob Faibussowitsch {
3174e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3175e432b41dSStefano Zampini 
3176e432b41dSStefano Zampini   PetscFunctionBegin;
3177e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3178e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
31799566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3180e432b41dSStefano Zampini   } else {
31819566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3182e432b41dSStefano Zampini   }
31839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3184e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3185e432b41dSStefano Zampini   PetscFunctionReturn(0);
3186e432b41dSStefano Zampini }
3187e432b41dSStefano Zampini 
3188d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3189d71ae5a4SJacob Faibussowitsch {
3190e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3191e432b41dSStefano Zampini 
3192e432b41dSStefano Zampini   PetscFunctionBegin;
3193e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3194e432b41dSStefano Zampini   PetscCheck(ncoo <= PETSC_MAX_INT, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support", ncoo);
3195e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo, coo_i, NULL, coo_i));
3196e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo, coo_j, NULL, coo_j));
3197e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
31989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3199e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
3200e432b41dSStefano Zampini   PetscFunctionReturn(0);
3201e432b41dSStefano Zampini }
3202e432b41dSStefano Zampini 
3203d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3204d71ae5a4SJacob Faibussowitsch {
3205d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3206d0dbe9f7SStefano Zampini   PetscObjectState Astate, aAstate       = PETSC_MIN_INT;
3207d0dbe9f7SStefano Zampini   PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT;
3208d0dbe9f7SStefano Zampini 
3209d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3210d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3211d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3212d0dbe9f7SStefano Zampini   if (a->assembledA) {
3213d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3214d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3215d0dbe9f7SStefano Zampini   }
3216d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3217d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3218d0dbe9f7SStefano Zampini     MatType     aAtype;
3219d0dbe9f7SStefano Zampini     PetscMPIInt size;
3220d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3221d0dbe9f7SStefano Zampini 
3222d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3223d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3224d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3225d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3226d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3227d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3228d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3229d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3230d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3231d0dbe9f7SStefano Zampini 
3232d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3233d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3234d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3235d0dbe9f7SStefano Zampini   }
3236d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3237d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3238d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
3239d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3240d0dbe9f7SStefano Zampini }
3241d0dbe9f7SStefano Zampini 
3242d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3243d71ae5a4SJacob Faibussowitsch {
3244d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3245d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3246d0dbe9f7SStefano Zampini   *tA = NULL;
3247d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3248d0dbe9f7SStefano Zampini }
3249d0dbe9f7SStefano Zampini 
3250d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3251d71ae5a4SJacob Faibussowitsch {
3252d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3253d0dbe9f7SStefano Zampini   PetscObjectState Astate, dAstate = PETSC_MIN_INT;
3254d0dbe9f7SStefano Zampini 
3255d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3256d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3257d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3258d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3259d0dbe9f7SStefano Zampini     Mat     tA;
3260d0dbe9f7SStefano Zampini     MatType ltype;
3261d0dbe9f7SStefano Zampini 
3262d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3263d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3264d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3265d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3266d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3267d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3268d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3269d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3270d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3271d0dbe9f7SStefano Zampini   }
3272d0dbe9f7SStefano Zampini   *dA = a->dA;
3273d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3274d0dbe9f7SStefano Zampini }
3275d0dbe9f7SStefano Zampini 
3276d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3277d71ae5a4SJacob Faibussowitsch {
3278d0dbe9f7SStefano Zampini   Mat tA;
3279d0dbe9f7SStefano Zampini 
3280d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3281d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3282d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3283d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3284d0dbe9f7SStefano Zampini #if 0
3285d0dbe9f7SStefano Zampini   {
3286d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3287d0dbe9f7SStefano Zampini     MatType   ltype;
3288d0dbe9f7SStefano Zampini     VecType   vtype;
3289d0dbe9f7SStefano Zampini     char      *flg;
3290d0dbe9f7SStefano Zampini 
3291d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3292d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3293d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3294d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3295d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3296d0dbe9f7SStefano Zampini     if (flg) {
3297d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3298d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3299d0dbe9f7SStefano Zampini 
3300d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3301d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3302d0dbe9f7SStefano Zampini       }
3303d0dbe9f7SStefano Zampini     }
3304d0dbe9f7SStefano Zampini   }
3305d0dbe9f7SStefano Zampini #endif
3306d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3307d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3308d0dbe9f7SStefano Zampini }
3309d0dbe9f7SStefano Zampini 
3310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3311d71ae5a4SJacob Faibussowitsch {
3312d0dbe9f7SStefano Zampini   Mat tA;
3313d0dbe9f7SStefano Zampini 
3314d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3315d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3316d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3317d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3318d0dbe9f7SStefano Zampini   PetscFunctionReturn(0);
3319d0dbe9f7SStefano Zampini }
3320d0dbe9f7SStefano Zampini 
3321e432b41dSStefano Zampini /*@
332211a5261eSBarry Smith    MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3323e432b41dSStefano Zampini 
3324e432b41dSStefano Zampini    Not Collective
3325e432b41dSStefano Zampini 
3326e432b41dSStefano Zampini    Input Parameter:
3327e432b41dSStefano Zampini .  A - the matrix
3328e432b41dSStefano Zampini 
3329e432b41dSStefano Zampini    Output Parameters:
3330e432b41dSStefano Zampini +  rmapping - row mapping
3331e432b41dSStefano Zampini -  cmapping - column mapping
3332e432b41dSStefano Zampini 
333311a5261eSBarry Smith    Note:
333411a5261eSBarry 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.
3335e432b41dSStefano Zampini 
3336e432b41dSStefano Zampini    Level: advanced
3337e432b41dSStefano Zampini 
333811a5261eSBarry Smith .seealso: `MatIS`, `MatSetLocalToGlobalMapping()`
3339e432b41dSStefano Zampini @*/
3340d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3341d71ae5a4SJacob Faibussowitsch {
3342e432b41dSStefano Zampini   PetscFunctionBegin;
3343e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3344e432b41dSStefano Zampini   PetscValidType(A, 1);
3345e432b41dSStefano Zampini   if (rmapping) PetscValidPointer(rmapping, 2);
3346e432b41dSStefano Zampini   if (cmapping) PetscValidPointer(cmapping, 3);
3347cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
3348e432b41dSStefano Zampini   PetscFunctionReturn(0);
3349e432b41dSStefano Zampini }
3350e432b41dSStefano Zampini 
3351d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3352d71ae5a4SJacob Faibussowitsch {
3353e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3354e432b41dSStefano Zampini 
3355e432b41dSStefano Zampini   PetscFunctionBegin;
3356e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3357e432b41dSStefano Zampini   if (c) *c = a->cmapping;
3358e432b41dSStefano Zampini   PetscFunctionReturn(0);
3359e432b41dSStefano Zampini }
3360e432b41dSStefano Zampini 
3361b4319ba4SBarry Smith /*MC
336211a5261eSBarry Smith    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
3363b89f26deSStefano Zampini    This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3364b4319ba4SBarry Smith    product is handled "implicitly".
3365b4319ba4SBarry Smith 
3366b4319ba4SBarry Smith    Options Database Keys:
336775d48cdbSStefano Zampini + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
336875d48cdbSStefano Zampini . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
336975d48cdbSStefano Zampini - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3370b4319ba4SBarry Smith 
337195452b02SPatrick Sanan    Notes:
337295452b02SPatrick Sanan    Options prefix for the inner matrix are given by -is_mat_xxx
3373b4319ba4SBarry Smith 
337411a5261eSBarry Smith    You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3375b4319ba4SBarry Smith 
3376b4319ba4SBarry Smith    You can do matrix preallocation on the local matrix after you obtain it with
337711a5261eSBarry Smith    `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()`
3378b4319ba4SBarry Smith 
3379b4319ba4SBarry Smith   Level: advanced
3380b4319ba4SBarry Smith 
338111a5261eSBarry Smith .seealso: `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3382b4319ba4SBarry Smith M*/
3383d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3384d71ae5a4SJacob Faibussowitsch {
3385e432b41dSStefano Zampini   Mat_IS *a;
3386b4319ba4SBarry Smith 
3387b4319ba4SBarry Smith   PetscFunctionBegin;
33884dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
33899566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3390e432b41dSStefano Zampini   A->data = (void *)a;
3391b4319ba4SBarry Smith 
3392e176bc59SStefano Zampini   /* matrix ops */
33939566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3394b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
33952e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
33962e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
33972e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3398b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3399b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
34002e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
340198921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3402b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3403f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
34042e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3405f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3406b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3407b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3408b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
34096726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
34102e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
34112e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
34126726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
341369796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
341469796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
341545471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3416ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
34176bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
34182b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3419659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
34207dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3421f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
34223fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
34233fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3424d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
34257fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3426ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3427872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3428fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
34298b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3430d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3431d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3432d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3433b4319ba4SBarry Smith 
3434b7ce53b6SStefano Zampini   /* special MATIS functions */
34359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
34369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
34379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
34389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
34399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", MatConvert_IS_XAIJ));
34409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
34419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
34429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
34439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
34449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
34459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
34469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
34479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
34489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
34499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
34509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
34519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
34529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
34539566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
3454b4319ba4SBarry Smith   PetscFunctionReturn(0);
3455b4319ba4SBarry Smith }
3456