xref: /petsc/src/mat/impls/is/matis.c (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
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));
313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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);
904f572ea9SToby Isaac   PetscAssertPointer(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));
1533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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;
2403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24175d48cdbSStefano Zampini }
24275d48cdbSStefano Zampini 
243d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
244d71ae5a4SJacob Faibussowitsch {
2454222ddf1SHong Zhang   Mat_Product *product = C->product;
2464222ddf1SHong Zhang   Mat          A = product->A, P = product->B;
2474222ddf1SHong Zhang   PetscReal    fill = product->fill;
24875d48cdbSStefano Zampini 
24975d48cdbSStefano Zampini   PetscFunctionBegin;
2509566063dSJacob Faibussowitsch   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
2514222ddf1SHong Zhang   C->ops->productnumeric = MatProductNumeric_PtAP;
2523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25375d48cdbSStefano Zampini }
25475d48cdbSStefano Zampini 
255d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
256d71ae5a4SJacob Faibussowitsch {
2574222ddf1SHong Zhang   PetscFunctionBegin;
2584222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
2593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2604222ddf1SHong Zhang }
2614222ddf1SHong Zhang 
262d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
263d71ae5a4SJacob Faibussowitsch {
2644222ddf1SHong Zhang   Mat_Product *product = C->product;
2654222ddf1SHong Zhang 
2664222ddf1SHong Zhang   PetscFunctionBegin;
26748a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
2683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2694222ddf1SHong Zhang }
2704222ddf1SHong Zhang 
271d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
272d71ae5a4SJacob Faibussowitsch {
2735b003df0Sstefano_zampini   MatISLocalFields lf = (MatISLocalFields)ptr;
2745b003df0Sstefano_zampini   PetscInt         i;
2755b003df0Sstefano_zampini 
276ab4d48faSStefano Zampini   PetscFunctionBegin;
27748a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
27848a46eb9SPierre Jolivet   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
2799566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lf->rf, lf->cf));
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree(lf));
2813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2825b003df0Sstefano_zampini }
283a72627d2SStefano Zampini 
284d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
285d71ae5a4SJacob Faibussowitsch {
286c9225affSStefano Zampini   Mat B, lB;
287c9225affSStefano Zampini 
288c9225affSStefano Zampini   PetscFunctionBegin;
289c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
290c9225affSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
291c9225affSStefano Zampini     PetscInt               bs;
292c9225affSStefano Zampini     IS                     is;
293c9225affSStefano Zampini 
2949566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
2959566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
296c9225affSStefano Zampini     if (bs > 1) {
297c9225affSStefano Zampini       IS       is2;
298c9225affSStefano Zampini       PetscInt i, *aux;
299c9225affSStefano Zampini 
3009566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3019566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3029566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3039566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3049566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
305c9225affSStefano Zampini       is = is2;
306c9225affSStefano Zampini     }
3079566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3099566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3109566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
311c9225affSStefano Zampini     if (bs > 1) {
312c9225affSStefano Zampini       IS       is2;
313c9225affSStefano Zampini       PetscInt i, *aux;
314c9225affSStefano Zampini 
3159566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3169566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3179566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3189566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3199566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
320c9225affSStefano Zampini       is = is2;
321c9225affSStefano Zampini     }
3229566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3239566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3259566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
3269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3289566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
329c9225affSStefano Zampini     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
330c9225affSStefano Zampini   } else {
331c9225affSStefano Zampini     B = *newmat;
3329566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
333c9225affSStefano Zampini     lB = A;
334c9225affSStefano Zampini   }
3359566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lB));
3369566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lB));
3379566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
33948a46eb9SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
3403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
341c9225affSStefano Zampini }
342c9225affSStefano Zampini 
343d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
344d71ae5a4SJacob Faibussowitsch {
345*f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
346c9225affSStefano Zampini   PetscScalar    *aa;
347c9225affSStefano Zampini   const PetscInt *ii, *jj;
348c9225affSStefano Zampini   PetscInt        i, n, m;
349fabe8965SStefano Zampini   PetscInt       *ecount, **eneighs;
350c9225affSStefano Zampini   PetscBool       flg;
351c9225affSStefano Zampini 
352c9225affSStefano Zampini   PetscFunctionBegin;
3539566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
35408401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
3559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
35608401ef6SPierre Jolivet   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
3579566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
358c9225affSStefano Zampini   for (i = 0; i < n; i++) {
359fabe8965SStefano Zampini     if (ecount[i] > 1) {
360c9225affSStefano Zampini       PetscInt j;
361c9225affSStefano Zampini 
362c9225affSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
363c9225affSStefano Zampini         PetscInt  i2   = jj[j], p, p2;
364fabe8965SStefano Zampini         PetscReal scal = 0.0;
365c9225affSStefano Zampini 
366c9225affSStefano Zampini         for (p = 0; p < ecount[i]; p++) {
367c9225affSStefano Zampini           for (p2 = 0; p2 < ecount[i2]; p2++) {
3689371c9d4SSatish Balay             if (eneighs[i][p] == eneighs[i2][p2]) {
3699371c9d4SSatish Balay               scal += 1.0;
3709371c9d4SSatish Balay               break;
3719371c9d4SSatish Balay             }
372c9225affSStefano Zampini           }
373c9225affSStefano Zampini         }
374fabe8965SStefano Zampini         if (scal) aa[j] /= scal;
375c9225affSStefano Zampini       }
376c9225affSStefano Zampini     }
377c9225affSStefano Zampini   }
3789566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
3799566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
3809566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
38108401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
3823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
383c9225affSStefano Zampini }
384c9225affSStefano Zampini 
3859371c9d4SSatish Balay typedef enum {
3869371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_NATURAL,
3879371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_MAT,
3889371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_ND
3899371c9d4SSatish Balay } MatISDisassemblel2gType;
390fabe8965SStefano Zampini 
391d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
392d71ae5a4SJacob Faibussowitsch {
393fabe8965SStefano Zampini   Mat                     Ad, Ao;
394fabe8965SStefano Zampini   IS                      is, ndmap, ndsub;
395c9225affSStefano Zampini   MPI_Comm                comm;
396fabe8965SStefano Zampini   const PetscInt         *garray, *ndmapi;
397fabe8965SStefano Zampini   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
398fabe8965SStefano Zampini   PetscBool               ismpiaij, ismpibaij;
399f4259b30SLisandro Dalcin   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
400fabe8965SStefano Zampini   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
401fabe8965SStefano Zampini   MatPartitioning         part;
402fabe8965SStefano Zampini   PetscSF                 sf;
40391d376acSStefano Zampini   PetscObject             dm;
404c9225affSStefano Zampini 
405c9225affSStefano Zampini   PetscFunctionBegin;
406d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
4079566063dSJacob 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));
408d0609cedSBarry Smith   PetscOptionsEnd();
409fabe8965SStefano Zampini   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
4109566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
4113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
412c9225affSStefano Zampini   }
4139566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4149566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
4159566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
4169566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
417fabe8965SStefano Zampini   switch (mode) {
418fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_ND:
4199566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(comm, &part));
4209566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(part, A));
4219566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
4229566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(part));
4239566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApplyND(part, &ndmap));
4249566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&part));
4259566063dSJacob Faibussowitsch     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
4269566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
4279566063dSJacob Faibussowitsch     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
4289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
429fabe8965SStefano Zampini 
430fabe8965SStefano Zampini     /* it may happen that a separator node is not properly shared */
4319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
4329566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &sf));
4339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
4349566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
4359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
4369566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
4379566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4389566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4399566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
4409566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ndmap, &ndmapi));
441fabe8965SStefano Zampini     for (i = 0, cnt = 0; i < A->rmap->n; i++)
4429371c9d4SSatish Balay       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
443fabe8965SStefano Zampini 
4441c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
445fabe8965SStefano Zampini     if (i) { /* we detected isolated separator nodes */
446fabe8965SStefano Zampini       Mat                    A2, A3;
447fabe8965SStefano Zampini       IS                    *workis, is2;
448fabe8965SStefano Zampini       PetscScalar           *vals;
449fabe8965SStefano Zampini       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
450fabe8965SStefano Zampini       ISLocalToGlobalMapping ll2g;
451fabe8965SStefano Zampini       PetscBool              flg;
452fabe8965SStefano Zampini       const PetscInt        *ii, *jj;
453fabe8965SStefano Zampini 
454fabe8965SStefano Zampini       /* communicate global id of separators */
455d0609cedSBarry Smith       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
4569371c9d4SSatish Balay       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
457fabe8965SStefano Zampini 
4589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl, &lndmapi));
4599566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
460fabe8965SStefano Zampini 
461fabe8965SStefano Zampini       /* compute adjacency of isolated separators node */
4629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(gcnt, &workis));
463fabe8965SStefano Zampini       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
46448a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
465fabe8965SStefano Zampini       }
46648a46eb9SPierre Jolivet       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
467fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4689566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
4699566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
470fabe8965SStefano Zampini       }
471fabe8965SStefano Zampini 
472fabe8965SStefano Zampini       /* no communications since all the ISes correspond to locally owned rows */
4739566063dSJacob Faibussowitsch       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
474fabe8965SStefano Zampini 
475fabe8965SStefano Zampini       /* end communicate global id of separators */
4769566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
477fabe8965SStefano Zampini 
478fabe8965SStefano Zampini       /* communicate new layers : create a matrix and transpose it */
4799566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(dnz, A->rmap->n));
4809566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(onz, A->rmap->n));
481fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) {
482fabe8965SStefano Zampini         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
483fabe8965SStefano Zampini           const PetscInt *idxs;
484fabe8965SStefano Zampini           PetscInt        s;
485fabe8965SStefano Zampini 
4869566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(workis[j], &s));
4879566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
4889566063dSJacob Faibussowitsch           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
489fabe8965SStefano Zampini           j++;
490fabe8965SStefano Zampini         }
491fabe8965SStefano Zampini       }
49208401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
493fabe8965SStefano Zampini 
494fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4959566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
4969566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
497fabe8965SStefano Zampini       }
498fabe8965SStefano Zampini 
499fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
5009566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(j, &vals));
501fabe8965SStefano Zampini       for (i = 0; i < j; i++) vals[i] = 1.0;
502fabe8965SStefano Zampini 
5039566063dSJacob Faibussowitsch       PetscCall(MatCreate(comm, &A2));
5049566063dSJacob Faibussowitsch       PetscCall(MatSetType(A2, MATMPIAIJ));
5059566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
5069566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
5079566063dSJacob Faibussowitsch       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
508fabe8965SStefano Zampini       for (i = 0, j = 0; i < A2->rmap->n; i++) {
509fabe8965SStefano Zampini         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
510fabe8965SStefano Zampini         const PetscInt *idxs;
511fabe8965SStefano Zampini 
512fabe8965SStefano Zampini         if (s) {
5139566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5149566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
5159566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(workis[j], &idxs));
516fabe8965SStefano Zampini           j++;
517fabe8965SStefano Zampini         }
518fabe8965SStefano Zampini       }
51908401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
5209566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
5219566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
5229566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
5239566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
524fabe8965SStefano Zampini 
525fabe8965SStefano Zampini       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
526fabe8965SStefano Zampini       for (i = 0, j = 0; i < nl; i++)
527fabe8965SStefano Zampini         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
5289566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
5299566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
5309566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5319566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A2));
532fabe8965SStefano Zampini 
533fabe8965SStefano Zampini       /* extend local to global map to include connected isolated separators */
5349566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
53528b400f6SJacob Faibussowitsch       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
5369566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
5379566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
53828b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5399566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
5409566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
54128b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5429566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
5439566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5449566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
545fabe8965SStefano Zampini 
546fabe8965SStefano Zampini       /* add new nodes to the local-to-global map */
5479566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
5489566063dSJacob Faibussowitsch       PetscCall(ISExpand(ndsub, is2, &is));
5499566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is2));
5509566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5519566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
552fabe8965SStefano Zampini 
5539566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A3));
5549566063dSJacob Faibussowitsch       PetscCall(PetscFree(lndmapi));
555d0609cedSBarry Smith       MatPreallocateEnd(dnz, onz);
55648a46eb9SPierre Jolivet       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
5579566063dSJacob Faibussowitsch       PetscCall(PetscFree(workis));
558fabe8965SStefano Zampini     }
5599566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
5609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
5619566063dSJacob Faibussowitsch     PetscCall(PetscFree(ndmapc));
5629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndmap));
5639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndsub));
5649566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
5659566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-matis_nd_l2g_view"));
566fabe8965SStefano Zampini     break;
567fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
56891d376acSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)&dm));
56991d376acSStefano Zampini     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
57091d376acSStefano Zampini       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
57191d376acSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*l2g));
5723ba16761SJacob Faibussowitsch       if (*l2g) PetscFunctionReturn(PETSC_SUCCESS);
57391d376acSStefano Zampini     }
574fabe8965SStefano Zampini     if (ismpiaij) {
5759566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
576fabe8965SStefano Zampini     } else if (ismpibaij) {
5779566063dSJacob Faibussowitsch       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
57898921bdaSJacob Faibussowitsch     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
579c9225affSStefano Zampini     if (A->rmap->n) {
580fabe8965SStefano Zampini       PetscInt dc, oc, stc, *aux;
581c9225affSStefano Zampini 
582ebf8cefbSJunchao Zhang       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
5839566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
584d0dbe9f7SStefano Zampini       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
5859566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
5869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
587c9225affSStefano Zampini       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
588ebf8cefbSJunchao Zhang       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
5899566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
590c9225affSStefano Zampini     } else {
5919566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
592c9225affSStefano Zampini     }
5939566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
595fabe8965SStefano Zampini     break;
596d71ae5a4SJacob Faibussowitsch   default:
597d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
598c9225affSStefano Zampini   }
5993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
600c9225affSStefano Zampini }
601c9225affSStefano Zampini 
602d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
603d71ae5a4SJacob Faibussowitsch {
604c9225affSStefano Zampini   Mat                    lA, Ad, Ao, B = NULL;
6056989cf23SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
6066989cf23SStefano Zampini   IS                     is;
6076989cf23SStefano Zampini   MPI_Comm               comm;
6086989cf23SStefano Zampini   void                  *ptrs[2];
6096989cf23SStefano Zampini   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
610c9225affSStefano Zampini   const PetscInt        *garray;
6116989cf23SStefano Zampini   PetscScalar           *dd, *od, *aa, *data;
612c9225affSStefano Zampini   const PetscInt        *di, *dj, *oi, *oj;
613c9225affSStefano Zampini   const PetscInt        *odi, *odj, *ooi, *ooj;
6146989cf23SStefano Zampini   PetscInt              *aux, *ii, *jj;
615c9225affSStefano Zampini   PetscInt               bs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
616c9225affSStefano Zampini   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE;
617c9225affSStefano Zampini   PetscMPIInt            size;
6186989cf23SStefano Zampini 
619ab4d48faSStefano Zampini   PetscFunctionBegin;
6209566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
6219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
622c9225affSStefano Zampini   if (size == 1) {
6239566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
6243ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
625c9225affSStefano Zampini   }
626c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
6279566063dSJacob Faibussowitsch     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
6289566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
6299566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
6309566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
6319566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
6329566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6339566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSize(B, bs));
6349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
635c9225affSStefano Zampini     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
636c9225affSStefano Zampini     reuse = MAT_REUSE_MATRIX;
637c9225affSStefano Zampini   }
638c9225affSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
639c9225affSStefano Zampini     Mat            *newlA, lA;
640c9225affSStefano Zampini     IS              rows, cols;
641c9225affSStefano Zampini     const PetscInt *ridx, *cidx;
642c9225affSStefano Zampini     PetscInt        rbs, cbs, nr, nc;
643c9225affSStefano Zampini 
644c9225affSStefano Zampini     if (!B) B = *newmat;
6459566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
6469566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
6479566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
6489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
6499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
6509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
6519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
6529566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
653c9225affSStefano Zampini     if (rl2g != cl2g) {
6549566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
655c9225affSStefano Zampini     } else {
6569566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)rows));
657c9225affSStefano Zampini       cols = rows;
658c9225affSStefano Zampini     }
6599566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(B, &lA));
6609566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
6619566063dSJacob Faibussowitsch     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
6629566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
6639566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
6649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rows));
6659566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cols));
666c9225affSStefano Zampini     if (!lA->preallocated) { /* first time */
6679566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
6689566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(B, lA));
6699566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)lA));
670c9225affSStefano Zampini     }
6719566063dSJacob Faibussowitsch     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
6729566063dSJacob Faibussowitsch     PetscCall(MatDestroySubMatrices(1, &newlA));
6739566063dSJacob Faibussowitsch     PetscCall(MatISScaleDisassembling_Private(B));
6749566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
6759566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
6769566063dSJacob Faibussowitsch     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
677c9225affSStefano Zampini     else *newmat = B;
6783ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
679c9225affSStefano Zampini   }
680c9225affSStefano Zampini   /* rectangular case, just compress out the column space */
6819566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
6829566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
683c9225affSStefano Zampini   if (ismpiaij) {
684c9225affSStefano Zampini     bs = 1;
6859566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
686c9225affSStefano Zampini   } else if (ismpibaij) {
6879566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
6889566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
6899566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
6909566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
69198921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
6929566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ad, &dd));
6939566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ao, &od));
69428b400f6SJacob Faibussowitsch   PetscCheck(garray, comm, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
6956989cf23SStefano Zampini 
6966989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
6979566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
6989566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
6999566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &dr, &dc));
7009566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
7019566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
70228b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
7039566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
70428b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
705c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
706c9225affSStefano Zampini   /* store original pointers to be restored later */
7079371c9d4SSatish Balay   odi = di;
7089371c9d4SSatish Balay   odj = dj;
7099371c9d4SSatish Balay   ooi = oi;
7109371c9d4SSatish Balay   ooj = oj;
7116989cf23SStefano Zampini 
7126989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
7139566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(comm, dr / bs, str / bs, 1, &is));
714c9225affSStefano Zampini   if (bs > 1) {
715c9225affSStefano Zampini     IS is2;
716c9225affSStefano Zampini 
7179566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7189566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
7199566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, i, aux, PETSC_COPY_VALUES, &is2));
7209566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
722c9225affSStefano Zampini     is = is2;
723c9225affSStefano Zampini   }
7249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
726e363d98aSStefano Zampini   if (dr) {
7279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
728c9225affSStefano Zampini     for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
729c9225affSStefano Zampini     for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = garray[i];
7309566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
731e363d98aSStefano Zampini     lc = dc + oc;
732e363d98aSStefano Zampini   } else {
7339566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, 0, NULL, PETSC_OWN_POINTER, &is));
734e363d98aSStefano Zampini     lc = 0;
735e363d98aSStefano Zampini   }
7369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7379566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7386989cf23SStefano Zampini 
7396989cf23SStefano Zampini   /* create MATIS object */
7409566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7429566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
7439566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, bs));
7449566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7476989cf23SStefano Zampini 
7486989cf23SStefano Zampini   /* merge local matrices */
7499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7516989cf23SStefano Zampini   ii  = aux;
7526989cf23SStefano Zampini   jj  = aux + dr + 1;
7536989cf23SStefano Zampini   aa  = data;
7546989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7559371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7569371c9d4SSatish Balay     for (; jd < *di; jd++) {
7579371c9d4SSatish Balay       *jj++ = *dj++;
7589371c9d4SSatish Balay       *aa++ = *dd++;
7599371c9d4SSatish Balay     }
7609371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7619371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7629371c9d4SSatish Balay       *aa++ = *od++;
7639371c9d4SSatish Balay     }
7646989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7656989cf23SStefano Zampini   }
7666989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
767c9225affSStefano Zampini 
7689566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
76928b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7709566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
77128b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7729566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7739566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
774c9225affSStefano Zampini 
7756989cf23SStefano Zampini   ii = aux;
7766989cf23SStefano Zampini   jj = aux + dr + 1;
7776989cf23SStefano Zampini   aa = data;
7789566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
7796989cf23SStefano Zampini 
7806989cf23SStefano Zampini   /* create containers to destroy the data */
7816989cf23SStefano Zampini   ptrs[0] = aux;
7826989cf23SStefano Zampini   ptrs[1] = data;
7836989cf23SStefano Zampini   for (i = 0; i < 2; i++) {
7846989cf23SStefano Zampini     PetscContainer c;
7856989cf23SStefano Zampini 
7869566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
7879566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, ptrs[i]));
7889566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
7899566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)lA, names[i], (PetscObject)c));
7909566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
7916989cf23SStefano Zampini   }
792c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7939566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
795c9225affSStefano Zampini   }
7966989cf23SStefano Zampini 
7976989cf23SStefano Zampini   /* finalize matrix */
7989566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
7999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
8009566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
8019566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
802c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
8039566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
804c9225affSStefano Zampini   } else *newmat = B;
8053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8066989cf23SStefano Zampini }
8076989cf23SStefano Zampini 
808d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
809d71ae5a4SJacob Faibussowitsch {
8105e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8115e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8125e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8135e3038f0Sstefano_zampini   MPI_Comm               comm;
8145b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8155b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8169e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8175e3038f0Sstefano_zampini 
818ab4d48faSStefano Zampini   PetscFunctionBegin;
8199566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8205e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8215e3038f0Sstefano_zampini   rnest  = NULL;
8225e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8235e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8245e3038f0Sstefano_zampini 
8259566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
826*f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8279566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8289566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8295e3038f0Sstefano_zampini     if (isnest) {
8309566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8315e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8325e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8335e3038f0Sstefano_zampini     }
8345e3038f0Sstefano_zampini   }
8359566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8369566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8379566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8389566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8395e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8405e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8415e3038f0Sstefano_zampini       PetscBool ismatis;
8429e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8435e3038f0Sstefano_zampini 
8445e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8455e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8465e3038f0Sstefano_zampini 
8475e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
848013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8499e7b2b25Sstefano_zampini       if (istrans[ij]) {
8509e7b2b25Sstefano_zampini         Mat T, lT;
8519566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8529566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
85328b400f6SJacob 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);
8549566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8559566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8569e7b2b25Sstefano_zampini       } else {
8579566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
85828b400f6SJacob 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);
8599566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8609e7b2b25Sstefano_zampini       }
8615e3038f0Sstefano_zampini 
8625e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8639566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8649566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8655e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
866aed4548fSBarry 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);
867aed4548fSBarry 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);
8685e3038f0Sstefano_zampini       lr[i] = l1;
8695e3038f0Sstefano_zampini       lc[j] = l2;
8705e3038f0Sstefano_zampini 
871da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8725e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8735e3038f0Sstefano_zampini     }
8745e3038f0Sstefano_zampini   }
8755e3038f0Sstefano_zampini 
87676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8775e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8785e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8795e3038f0Sstefano_zampini       rl2g = NULL;
8805e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8815e3038f0Sstefano_zampini         PetscInt n1, n2;
8825e3038f0Sstefano_zampini 
8835e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8849e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8859e7b2b25Sstefano_zampini           Mat T;
8869e7b2b25Sstefano_zampini 
8879566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8889566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8899e7b2b25Sstefano_zampini         } else {
8909566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8919e7b2b25Sstefano_zampini         }
8929566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8935e3038f0Sstefano_zampini         if (!n1) continue;
8945e3038f0Sstefano_zampini         if (!rl2g) {
8955e3038f0Sstefano_zampini           rl2g = cl2g;
8965e3038f0Sstefano_zampini         } else {
8975e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
8985e3038f0Sstefano_zampini           PetscBool       same;
8995e3038f0Sstefano_zampini 
9009566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
90108401ef6SPierre 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);
9029566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9039566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9049566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9059566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9069566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
90728b400f6SJacob 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);
9085e3038f0Sstefano_zampini         }
9095e3038f0Sstefano_zampini       }
9105e3038f0Sstefano_zampini     }
9115e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9125e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9135e3038f0Sstefano_zampini       rl2g = NULL;
9145e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9155e3038f0Sstefano_zampini         PetscInt n1, n2;
9165e3038f0Sstefano_zampini 
9175e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9189e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9199e7b2b25Sstefano_zampini           Mat T;
9209e7b2b25Sstefano_zampini 
9219566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9229566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9239e7b2b25Sstefano_zampini         } else {
9249566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9259e7b2b25Sstefano_zampini         }
9269566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9275e3038f0Sstefano_zampini         if (!n1) continue;
9285e3038f0Sstefano_zampini         if (!rl2g) {
9295e3038f0Sstefano_zampini           rl2g = cl2g;
9305e3038f0Sstefano_zampini         } else {
9315e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9325e3038f0Sstefano_zampini           PetscBool       same;
9335e3038f0Sstefano_zampini 
9349566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
93508401ef6SPierre 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);
9369566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9379566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9389566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9399566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9409566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
94128b400f6SJacob 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);
9425e3038f0Sstefano_zampini         }
9435e3038f0Sstefano_zampini       }
9445e3038f0Sstefano_zampini     }
94576bd3646SJed Brown   }
9465e3038f0Sstefano_zampini 
9475e3038f0Sstefano_zampini   B = NULL;
9485e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9495b003df0Sstefano_zampini     PetscInt stl;
9505b003df0Sstefano_zampini 
9515e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9525e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9545b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9555e3038f0Sstefano_zampini       Mat             usedmat;
9565e3038f0Sstefano_zampini       Mat_IS         *matis;
9575e3038f0Sstefano_zampini       const PetscInt *idxs;
9585e3038f0Sstefano_zampini 
9595e3038f0Sstefano_zampini       /* local IS for local NEST */
9609566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9615e3038f0Sstefano_zampini 
9625e3038f0Sstefano_zampini       /* l2gmap */
9635e3038f0Sstefano_zampini       j       = 0;
9645e3038f0Sstefano_zampini       usedmat = nest[i][j];
9659e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
96628b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9679e7b2b25Sstefano_zampini 
9689e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9699e7b2b25Sstefano_zampini         Mat T;
9709566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9719e7b2b25Sstefano_zampini         usedmat = T;
9729e7b2b25Sstefano_zampini       }
973*f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9749566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9759e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9769566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9779566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9789e7b2b25Sstefano_zampini       } else {
9799566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9809566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9819e7b2b25Sstefano_zampini       }
9829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9835e3038f0Sstefano_zampini       stl += lr[i];
9845e3038f0Sstefano_zampini     }
9859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9865e3038f0Sstefano_zampini 
9875e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9885e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9905b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9915e3038f0Sstefano_zampini       Mat             usedmat;
9925e3038f0Sstefano_zampini       Mat_IS         *matis;
9935e3038f0Sstefano_zampini       const PetscInt *idxs;
9945e3038f0Sstefano_zampini 
9955e3038f0Sstefano_zampini       /* local IS for local NEST */
9969566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
9975e3038f0Sstefano_zampini 
9985e3038f0Sstefano_zampini       /* l2gmap */
9995e3038f0Sstefano_zampini       j       = 0;
10005e3038f0Sstefano_zampini       usedmat = nest[j][i];
10019e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100228b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10039e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10049e7b2b25Sstefano_zampini         Mat T;
10059566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10069e7b2b25Sstefano_zampini         usedmat = T;
10079e7b2b25Sstefano_zampini       }
1008*f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10099566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10109e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10119566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10129566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10139e7b2b25Sstefano_zampini       } else {
10149566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10159566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10169e7b2b25Sstefano_zampini       }
10179566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10185e3038f0Sstefano_zampini       stl += lc[i];
10195e3038f0Sstefano_zampini     }
10209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10215e3038f0Sstefano_zampini 
10225e3038f0Sstefano_zampini     /* Create MATIS */
10239566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10249566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10259566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10269566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10279566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10289566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10298546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1030*f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
10318546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10328546b261SStefano Zampini     }
10339566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10369566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10379566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10389e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
103948a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10409e7b2b25Sstefano_zampini     }
10419566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10438546b261SStefano Zampini     { /* hack : setup of scatters done here */
1044*f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10458546b261SStefano Zampini 
10468546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10479566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10488546b261SStefano Zampini     }
10499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10509566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10515e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10529566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10535e3038f0Sstefano_zampini     } else {
10545e3038f0Sstefano_zampini       *newmat = B;
10555e3038f0Sstefano_zampini     }
10565e3038f0Sstefano_zampini   } else {
10575e3038f0Sstefano_zampini     if (lreuse) {
10589566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10595e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10605e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10615e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10629566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
106348a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10645e3038f0Sstefano_zampini           }
10655e3038f0Sstefano_zampini         }
10665e3038f0Sstefano_zampini       }
10675e3038f0Sstefano_zampini     } else {
10685b003df0Sstefano_zampini       PetscInt stl;
10695b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10709566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10715b003df0Sstefano_zampini         stl += lr[i];
10725e3038f0Sstefano_zampini       }
10735b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10749566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10755b003df0Sstefano_zampini         stl += lc[i];
10765e3038f0Sstefano_zampini       }
10779566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1078ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
107948a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1080ab4d48faSStefano Zampini       }
10819566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10829566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10835e3038f0Sstefano_zampini     }
10849566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10859566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10865e3038f0Sstefano_zampini   }
10875e3038f0Sstefano_zampini 
10885b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10895b003df0Sstefano_zampini   convert = PETSC_FALSE;
10909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-matis_convert_local_nest", &convert, NULL));
10915b003df0Sstefano_zampini   if (convert) {
10925b003df0Sstefano_zampini     Mat              M;
10935b003df0Sstefano_zampini     MatISLocalFields lf;
10945b003df0Sstefano_zampini     PetscContainer   c;
10955b003df0Sstefano_zampini 
10969566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
10979566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
10989566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
10999566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
11005b003df0Sstefano_zampini 
11015b003df0Sstefano_zampini     /* attach local fields to the matrix */
11029566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11045b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11055b003df0Sstefano_zampini       PetscInt n, st;
11065b003df0Sstefano_zampini 
11079566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11089566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11099566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11105b003df0Sstefano_zampini     }
11115b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11125b003df0Sstefano_zampini       PetscInt n, st;
11135b003df0Sstefano_zampini 
11149566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11159566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11169566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11175b003df0Sstefano_zampini     }
11185b003df0Sstefano_zampini     lf->nr = nr;
11195b003df0Sstefano_zampini     lf->nc = nc;
1120*f4f49eeaSPierre Jolivet     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)*newmat), &c));
11219566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, lf));
11229566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyFields_Private));
1123*f4f49eeaSPierre Jolivet     PetscCall(PetscObjectCompose((PetscObject)*newmat, "_convert_nest_lfields", (PetscObject)c));
11249566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
11255b003df0Sstefano_zampini   }
11265b003df0Sstefano_zampini 
11275e3038f0Sstefano_zampini   /* Free workspace */
112848a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
112948a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11309566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11319566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11335e3038f0Sstefano_zampini }
11345e3038f0Sstefano_zampini 
1135d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1136d71ae5a4SJacob Faibussowitsch {
1137ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1138ad219c80Sstefano_zampini   Vec                ll, rr;
1139ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1140ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1141ad219c80Sstefano_zampini 
1142ad219c80Sstefano_zampini   PetscFunctionBegin;
1143ad219c80Sstefano_zampini   if (l) {
1144ad219c80Sstefano_zampini     ll = matis->y;
11459566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11469566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11479566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1148ad219c80Sstefano_zampini   } else {
1149ad219c80Sstefano_zampini     ll = NULL;
1150ad219c80Sstefano_zampini   }
1151ad219c80Sstefano_zampini   if (r) {
1152ad219c80Sstefano_zampini     rr = matis->x;
11539566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11549566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11559566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1156ad219c80Sstefano_zampini   } else {
1157ad219c80Sstefano_zampini     rr = NULL;
1158ad219c80Sstefano_zampini   }
1159ad219c80Sstefano_zampini   if (ll) {
11609566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11629566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1163ad219c80Sstefano_zampini   }
1164ad219c80Sstefano_zampini   if (rr) {
11659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11669566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11679566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1168ad219c80Sstefano_zampini   }
11699566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1171ad219c80Sstefano_zampini }
1172ad219c80Sstefano_zampini 
1173d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1174d71ae5a4SJacob Faibussowitsch {
11757fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11767fa8f2d3SStefano Zampini   MatInfo        info;
11773966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11787fa8f2d3SStefano Zampini   PetscInt       bs;
11797fa8f2d3SStefano Zampini 
11807fa8f2d3SStefano Zampini   PetscFunctionBegin;
11819566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1182a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11839566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11847fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11857fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11867fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11877fa8f2d3SStefano Zampini     isend[3] = info.memory;
11887fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1189a2ccb5f9Sstefano_zampini   } else {
1190a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1191a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1192a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1193a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1194a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1195a2ccb5f9Sstefano_zampini   }
1196314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
11977fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
11987fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
11997fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
12007fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
12017fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
12027fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1203314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
12047fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
12051c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12067fa8f2d3SStefano Zampini 
12077fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12087fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12097fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12107fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12117fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1212314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12137fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
12141c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12157fa8f2d3SStefano Zampini 
12167fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12177fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12187fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12197fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12207fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12217fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12227fa8f2d3SStefano Zampini   }
12237fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12247fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12257fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12267fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12285e3038f0Sstefano_zampini }
12295e3038f0Sstefano_zampini 
1230d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1231d71ae5a4SJacob Faibussowitsch {
1232d7f69cd0SStefano Zampini   Mat C, lC, lA;
1233d7f69cd0SStefano Zampini 
1234d7f69cd0SStefano Zampini   PetscFunctionBegin;
12357fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1236cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1237cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12389566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12399566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
12409566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
12419566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12429566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12439566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1244e432b41dSStefano Zampini   } else C = *B;
1245d7f69cd0SStefano Zampini 
1246d7f69cd0SStefano Zampini   /* perform local transposition */
12479566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12489566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12499566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12509566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12519566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1252d7f69cd0SStefano Zampini 
1253cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1254d7f69cd0SStefano Zampini     *B = C;
1255d7f69cd0SStefano Zampini   } else {
12569566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1257d7f69cd0SStefano Zampini   }
12589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12599566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1261d7f69cd0SStefano Zampini }
1262d7f69cd0SStefano Zampini 
1263d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1264d71ae5a4SJacob Faibussowitsch {
12653fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12663fd1c9e7SStefano Zampini 
12673fd1c9e7SStefano Zampini   PetscFunctionBegin;
12684b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12699566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12709566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12713fd1c9e7SStefano Zampini   }
12729566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12739566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12753fd1c9e7SStefano Zampini }
12763fd1c9e7SStefano Zampini 
1277d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1278d71ae5a4SJacob Faibussowitsch {
12794b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12803fd1c9e7SStefano Zampini 
12813fd1c9e7SStefano Zampini   PetscFunctionBegin;
12829566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12839566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12853fd1c9e7SStefano Zampini }
12863fd1c9e7SStefano Zampini 
1287d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1288d71ae5a4SJacob Faibussowitsch {
1289f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1290f26d0771SStefano Zampini 
1291f26d0771SStefano Zampini   PetscFunctionBegin;
1292aed4548fSBarry 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);
12939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
12949566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
12959566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
12963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1297f26d0771SStefano Zampini }
1298f26d0771SStefano Zampini 
1299d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1300d71ae5a4SJacob Faibussowitsch {
1301f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1302f26d0771SStefano Zampini 
1303f26d0771SStefano Zampini   PetscFunctionBegin;
1304aed4548fSBarry 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);
13059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13079566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1309f26d0771SStefano Zampini }
1310f26d0771SStefano Zampini 
1311d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1312d71ae5a4SJacob Faibussowitsch {
1313a8116848SStefano Zampini   Mat             locmat, newlocmat;
1314a8116848SStefano Zampini   Mat_IS         *newmatis;
1315a8116848SStefano Zampini   const PetscInt *idxs;
1316a8116848SStefano Zampini   PetscInt        i, m, n;
1317a8116848SStefano Zampini 
1318a8116848SStefano Zampini   PetscFunctionBegin;
1319a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1320a8116848SStefano Zampini     PetscBool ismatis;
1321a8116848SStefano Zampini 
13229566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
132328b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1324a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
132528b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
132628b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1327a8116848SStefano Zampini   }
1328a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
132976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
133076bd3646SJed Brown     Vec                rtest, ltest;
133176bd3646SJed Brown     const PetscScalar *array;
133276bd3646SJed Brown 
13339566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13349566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13359566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
133648a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13389566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13399566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13409566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13419566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1342aed4548fSBarry 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]));
13439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13449566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13459566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13469566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
134748a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13489566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13509566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13519566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13529566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1353aed4548fSBarry 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]));
13549566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13559566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13579566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
135876bd3646SJed Brown   }
1359a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1360a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1361a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1362a8116848SStefano Zampini     IS                     is;
1363a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1364306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
136594342113SStefano Zampini     PetscBool              cong;
1366a8116848SStefano Zampini     MPI_Comm               comm;
1367a8116848SStefano Zampini 
13689566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13699566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13709566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13719566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1372306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1373306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13769566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13779566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13789566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13799566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1380a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13819566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13829566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13839566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13849566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1385a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13869566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
13879566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
13889566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13899566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13909371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
13919371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
13929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
13939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
13943d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1395a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1396a8116848SStefano Zampini         lidxs[newloc]      = i;
1397a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1398a8116848SStefano Zampini       }
13999566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14009566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1403a8116848SStefano Zampini     /* local is to extract local submatrix */
1404a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14059566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14069566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
140794342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14089566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14099566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1410a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1411a8116848SStefano Zampini     } else {
1412a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1413a8116848SStefano Zampini 
1414a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14159566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14169566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14179566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14189566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1419a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14209566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14219566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14229566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14249371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14259371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14269566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14279566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14283d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1429a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1430a8116848SStefano Zampini           lidxs[newloc]      = i;
1431a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1432a8116848SStefano Zampini         }
14339566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14349566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14369566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1437a8116848SStefano Zampini       /* local is to extract local submatrix */
14389566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14399566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14409566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1441a8116848SStefano Zampini     }
14429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1443a8116848SStefano Zampini   } else {
14449566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1445a8116848SStefano Zampini   }
14469566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1447a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14489566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1449a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14509566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1452a8116848SStefano Zampini   }
14539566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1456a8116848SStefano Zampini }
1457a8116848SStefano Zampini 
1458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1459d71ae5a4SJacob Faibussowitsch {
14602b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14612b404112SStefano Zampini   PetscBool ismatis;
14622b404112SStefano Zampini 
14632b404112SStefano Zampini   PetscFunctionBegin;
14649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
146528b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14662b404112SStefano Zampini   b = (Mat_IS *)B->data;
14679566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14689566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14702b404112SStefano Zampini }
14712b404112SStefano Zampini 
1472d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1473d71ae5a4SJacob Faibussowitsch {
1474527b2640SStefano Zampini   Vec                v;
1475527b2640SStefano Zampini   const PetscScalar *array;
1476527b2640SStefano Zampini   PetscInt           i, n;
14776bd84002SStefano Zampini 
14786bd84002SStefano Zampini   PetscFunctionBegin;
1479527b2640SStefano Zampini   *missing = PETSC_FALSE;
14809566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14819566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14829566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14839566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14849371c9d4SSatish Balay   for (i = 0; i < n; i++)
14859371c9d4SSatish Balay     if (array[i] == 0.) break;
14869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
14879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1488527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1489527b2640SStefano Zampini   if (d) {
1490527b2640SStefano Zampini     *d = -1;
1491527b2640SStefano Zampini     if (*missing) {
1492527b2640SStefano Zampini       PetscInt rstart;
14939566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1494527b2640SStefano Zampini       *d = i + rstart;
1495527b2640SStefano Zampini     }
1496527b2640SStefano Zampini   }
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14986bd84002SStefano Zampini }
14996bd84002SStefano Zampini 
1500d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1501d71ae5a4SJacob Faibussowitsch {
1502*f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
150328f4e0baSStefano Zampini   const PetscInt *gidxs;
15044f2d7cafSStefano Zampini   PetscInt        nleaves;
150528f4e0baSStefano Zampini 
150628f4e0baSStefano Zampini   PetscFunctionBegin;
15073ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15089566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15119566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1514e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15159566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15169566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15189566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1521a8116848SStefano Zampini   } else {
1522a8116848SStefano Zampini     matis->csf          = matis->sf;
1523a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1524a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1525a8116848SStefano Zampini   }
15263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152728f4e0baSStefano Zampini }
15282e1947a5SStefano Zampini 
1529eb82efa4SStefano Zampini /*@
15302ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
153175d48cdbSStefano Zampini 
1532d083f849SBarry Smith   Collective
153375d48cdbSStefano Zampini 
153475d48cdbSStefano Zampini   Input Parameters:
153575d48cdbSStefano Zampini + A     - the matrix
153675d48cdbSStefano Zampini - store - the boolean flag
153775d48cdbSStefano Zampini 
153875d48cdbSStefano Zampini   Level: advanced
153975d48cdbSStefano Zampini 
15401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
154175d48cdbSStefano Zampini @*/
1542d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1543d71ae5a4SJacob Faibussowitsch {
154475d48cdbSStefano Zampini   PetscFunctionBegin;
154575d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
154675d48cdbSStefano Zampini   PetscValidType(A, 1);
154775d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1548cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
15493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155075d48cdbSStefano Zampini }
155175d48cdbSStefano Zampini 
1552d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1553d71ae5a4SJacob Faibussowitsch {
1554*f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
155575d48cdbSStefano Zampini 
155675d48cdbSStefano Zampini   PetscFunctionBegin;
155775d48cdbSStefano Zampini   matis->storel2l = store;
155848a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
15593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
156075d48cdbSStefano Zampini }
156175d48cdbSStefano Zampini 
156275d48cdbSStefano Zampini /*@
1563f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1564f03112d0SStefano Zampini 
1565d083f849SBarry Smith   Collective
1566f03112d0SStefano Zampini 
1567f03112d0SStefano Zampini   Input Parameters:
1568f03112d0SStefano Zampini + A   - the matrix
1569f03112d0SStefano Zampini - fix - the boolean flag
1570f03112d0SStefano Zampini 
1571f03112d0SStefano Zampini   Level: advanced
1572f03112d0SStefano Zampini 
157311a5261eSBarry Smith   Note:
15742fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1575f03112d0SStefano Zampini 
15761cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1577f03112d0SStefano Zampini @*/
1578d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1579d71ae5a4SJacob Faibussowitsch {
1580f03112d0SStefano Zampini   PetscFunctionBegin;
1581f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1582f03112d0SStefano Zampini   PetscValidType(A, 1);
1583f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1584cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
15853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1586f03112d0SStefano Zampini }
1587f03112d0SStefano Zampini 
1588d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1589d71ae5a4SJacob Faibussowitsch {
1590*f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1591f03112d0SStefano Zampini 
1592f03112d0SStefano Zampini   PetscFunctionBegin;
1593f03112d0SStefano Zampini   matis->locempty = fix;
15943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1595f03112d0SStefano Zampini }
1596f03112d0SStefano Zampini 
1597f03112d0SStefano Zampini /*@
159811a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1599a88811baSStefano Zampini 
1600d083f849SBarry Smith   Collective
1601a88811baSStefano Zampini 
1602a88811baSStefano Zampini   Input Parameters:
1603a88811baSStefano Zampini + B     - the matrix
1604a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1605a88811baSStefano Zampini            (same value is used for all local rows)
1606a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1607a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
16082ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
16092ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1610a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1611a88811baSStefano Zampini            the diagonal entry even if it is zero.
1612a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1613a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1614a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1615a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
16162ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1617a88811baSStefano Zampini            structure. The size of this array is equal to the number
16182ef1f0ffSBarry Smith            of local rows, i.e `m`.
1619a88811baSStefano Zampini 
1620a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1621a88811baSStefano Zampini 
1622a88811baSStefano Zampini   Level: intermediate
1623a88811baSStefano Zampini 
162411a5261eSBarry Smith   Note:
162511a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
162611a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1627a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1628a88811baSStefano Zampini 
16291cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1630a88811baSStefano Zampini @*/
1631d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1632d71ae5a4SJacob Faibussowitsch {
16332e1947a5SStefano Zampini   PetscFunctionBegin;
16342e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
16352e1947a5SStefano Zampini   PetscValidType(B, 1);
1636cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
16373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16382e1947a5SStefano Zampini }
16392e1947a5SStefano Zampini 
1640844bd0d7SStefano Zampini /* this is used by DMDA */
1641d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1642d71ae5a4SJacob Faibussowitsch {
1643*f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
164428f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
16452e1947a5SStefano Zampini 
16462e1947a5SStefano Zampini   PetscFunctionBegin;
16479566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
16489371c9d4SSatish Balay   if (!d_nnz)
16499371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
16509371c9d4SSatish Balay   else
16519371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
16524f2d7cafSStefano Zampini 
16539371c9d4SSatish Balay   if (!o_nnz)
16549371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
16559371c9d4SSatish Balay   else
16569371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
16574f2d7cafSStefano Zampini 
16589566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16599566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
16609566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
16619566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
16624f2d7cafSStefano Zampini 
16634f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
16649566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
16650f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
16669566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
16670f2f62c7SStefano Zampini #endif
16684f2d7cafSStefano Zampini 
1669fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1670fc989267SStefano Zampini     PetscInt b;
1671fc989267SStefano Zampini 
1672fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1673ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1674fc989267SStefano Zampini   }
16759566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16764f2d7cafSStefano Zampini 
167700a59248SStefano Zampini   nlocalcols /= bs;
167800a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
16799566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
16800f2f62c7SStefano Zampini 
16810f2f62c7SStefano Zampini   /* for other matrix types */
16829566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
16833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16842e1947a5SStefano Zampini }
1685b4319ba4SBarry Smith 
1686d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1687d71ae5a4SJacob Faibussowitsch {
1688*f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
16893927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1690ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
16913927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
16923927de2eSStefano Zampini   PetscInt        lrows, lcols;
16933927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1694f03112d0SStefano Zampini   PetscMPIInt     size;
16953927de2eSStefano Zampini   PetscBool       isdense, issbaij;
16963927de2eSStefano Zampini 
16973927de2eSStefano Zampini   PetscFunctionBegin;
16989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
16999566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
17009566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
17019566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
17029566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
17039566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
17049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1705e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
17069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
17070dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1708ecf5a873SStefano Zampini 
17099566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
17103927de2eSStefano Zampini   /*
1711ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
17123927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
17133927de2eSStefano Zampini   */
17149566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1715d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
17163927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
17179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
17189566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1719f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
17205f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
17213927de2eSStefano Zampini   }
17229566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
17233927de2eSStefano Zampini 
17243927de2eSStefano Zampini   /*
17253927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
17263927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
17273927de2eSStefano Zampini   */
17289566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
17293927de2eSStefano Zampini   /* preallocation as a MATAIJ */
17303927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
17313927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
173212dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
173312dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1734ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
17353927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17363927de2eSStefano Zampini           my_dnz[i] += 1;
17373927de2eSStefano Zampini         } else { /* offdiag block */
17383927de2eSStefano Zampini           my_onz[i] += 1;
17393927de2eSStefano Zampini         }
17403927de2eSStefano Zampini       }
17413927de2eSStefano Zampini     }
1742bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1743bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1744bb1015c3SStefano Zampini     PetscBool       done;
17459566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1746*f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1747bb1015c3SStefano Zampini     jptr = jj;
1748bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1749bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1750bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1751bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1752bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1753bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1754bb1015c3SStefano Zampini           my_dnz[i] += 1;
1755bb1015c3SStefano Zampini         } else { /* offdiag block */
1756bb1015c3SStefano Zampini           my_onz[i] += 1;
1757bb1015c3SStefano Zampini         }
1758bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1759bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1760bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1761bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1762bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1763bb1015c3SStefano Zampini           } else {
1764bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1765bb1015c3SStefano Zampini           }
1766bb1015c3SStefano Zampini         }
1767bb1015c3SStefano Zampini       }
1768bb1015c3SStefano Zampini     }
17699566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1770*f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1771bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
17723927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
17733927de2eSStefano Zampini       const PetscInt *cols;
1774ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
17759566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
17763927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
17773927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1778ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
17793927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
17803927de2eSStefano Zampini           my_dnz[i] += 1;
17813927de2eSStefano Zampini         } else { /* offdiag block */
17823927de2eSStefano Zampini           my_onz[i] += 1;
17833927de2eSStefano Zampini         }
17843927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1785d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
17863927de2eSStefano Zampini           owner = row_ownership[index_col];
17873927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1788d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
17893927de2eSStefano Zampini           } else {
1790d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
17913927de2eSStefano Zampini           }
17923927de2eSStefano Zampini         }
17933927de2eSStefano Zampini       }
17949566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
17953927de2eSStefano Zampini     }
17963927de2eSStefano Zampini   }
179748a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
17989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
17999566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1800ecf5a873SStefano Zampini 
1801ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
18023927de2eSStefano Zampini   if (maxreduce) {
18039566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
18049566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
18059566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
18069566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
18073927de2eSStefano Zampini   } else {
18089566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
18099566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
18109566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
18119566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
18123927de2eSStefano Zampini   }
18139566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
18143927de2eSStefano Zampini 
18153927de2eSStefano Zampini   /* Resize preallocation if overestimated */
18163927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
18173927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
18183927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
18193927de2eSStefano Zampini   }
18201670daf9Sstefano_zampini 
18211670daf9Sstefano_zampini   /* Set preallocation */
18229566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
18239566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
18249566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
182553b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
182653b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
182753b44cf5SStefano Zampini 
182853b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
182953b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
183053b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
183153b44cf5SStefano Zampini     }
183253b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
183353b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
18343927de2eSStefano Zampini   }
18359566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
18369566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
18379566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1838d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
18399566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
18409566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
18413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18423927de2eSStefano Zampini }
18433927de2eSStefano Zampini 
1844d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1845d71ae5a4SJacob Faibussowitsch {
1846*f4f49eeaSPierre Jolivet   Mat_IS            *matis = (Mat_IS *)mat->data;
1847487b449aSStefano Zampini   Mat                local_mat, MT;
184853b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1849b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1850b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1851f03112d0SStefano Zampini   PetscMPIInt        size;
18521683a169SBarry Smith   const PetscScalar *array;
1853b7ce53b6SStefano Zampini 
1854b7ce53b6SStefano Zampini   PetscFunctionBegin;
18559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1856f03112d0SStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
18571670daf9Sstefano_zampini     Mat      B;
185853b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1859487b449aSStefano Zampini     PetscInt rbs, cbs;
18601670daf9Sstefano_zampini 
18619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18629566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
186353b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
186453b44cf5SStefano Zampini       IS              rows, cols;
186553b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
186653b44cf5SStefano Zampini       PetscInt        i, nw, *work;
186753b44cf5SStefano Zampini 
18689566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
187053b44cf5SStefano Zampini       nw = nw / rbs;
18719566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(nw, &work));
187253b44cf5SStefano Zampini       for (i = 0; i < nw; i++) work[ridxs[i]] += 1;
18739371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18749371c9d4SSatish Balay         if (!work[i] || work[i] > 1) break;
187553b44cf5SStefano Zampini       if (i == nw) {
18769566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18779566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18789566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18799566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
188053b44cf5SStefano Zampini       }
18819566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18829566063dSJacob Faibussowitsch       PetscCall(PetscFree(work));
1883e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18849566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18859566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
188653b44cf5SStefano Zampini         nw = nw / cbs;
18879566063dSJacob Faibussowitsch         PetscCall(PetscCalloc1(nw, &work));
188853b44cf5SStefano Zampini         for (i = 0; i < nw; i++) work[cidxs[i]] += 1;
18899371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18909371c9d4SSatish Balay           if (!work[i] || work[i] > 1) break;
189153b44cf5SStefano Zampini         if (i == nw) {
18929566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18939566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18949566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18959566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
189653b44cf5SStefano Zampini         }
18979566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
18989566063dSJacob Faibussowitsch         PetscCall(PetscFree(work));
189953b44cf5SStefano Zampini       } else if (irows) {
19009566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
190153b44cf5SStefano Zampini         icols = irows;
190253b44cf5SStefano Zampini       }
190353b44cf5SStefano Zampini     } else {
1904*f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
1905*f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
19069566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
19079566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
190853b44cf5SStefano Zampini     }
190953b44cf5SStefano Zampini     if (!irows || !icols) {
19109566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
19119566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
191253b44cf5SStefano Zampini       goto general_assembly;
191353b44cf5SStefano Zampini     }
19149566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1915487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
19169566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
1917*f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
1918*f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1919487b449aSStefano Zampini     } else {
1920487b449aSStefano Zampini       Mat C;
1921487b449aSStefano Zampini 
19229566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
19239566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1924487b449aSStefano Zampini     }
19259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
19269566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
19279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
19283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19297c03b4e8SStefano Zampini   }
193053b44cf5SStefano Zampini general_assembly:
19319566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19349566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19359566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19369566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19379566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19389566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19399566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1940*f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
194176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
194276bd3646SJed Brown     PetscBool lb[4], bb[4];
194376bd3646SJed Brown 
1944b9ed4604SStefano Zampini     lb[0] = isseqdense;
1945b9ed4604SStefano Zampini     lb[1] = isseqaij;
1946b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1947b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
19481c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1949aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
195076bd3646SJed Brown   }
1951b7ce53b6SStefano Zampini 
1952487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
19539566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19549566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19559566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19569566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
19579566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
1958b7ce53b6SStefano Zampini   } else {
195953b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1960487b449aSStefano Zampini 
1961b7ce53b6SStefano Zampini     /* some checks */
1962487b449aSStefano Zampini     MT = *M;
19639566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19649566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19659566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
196608401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
196708401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
196808401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
196908401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
197008401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
197108401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
19729566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
1973b7ce53b6SStefano Zampini   }
1974d9a9e74cSStefano Zampini 
19758546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
19769566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
19778546b261SStefano Zampini     isseqaij = PETSC_TRUE;
1978d9a9e74cSStefano Zampini   } else {
19799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
1980d9a9e74cSStefano Zampini     local_mat = matis->A;
1981d9a9e74cSStefano Zampini   }
1982686e3a49SStefano Zampini 
1983b7ce53b6SStefano Zampini   /* Set values */
19849566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1985b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
198665066ba5SStefano Zampini     PetscInt i, *dummy;
1987ecf5a873SStefano Zampini 
19889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
198965066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
19909566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
19919566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
19929566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
19939566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
19949566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
1995686e3a49SStefano Zampini   } else if (isseqaij) {
19966afe12f5SStefano Zampini     const PetscInt *blocks;
19976afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
1998686e3a49SStefano Zampini     PetscBool       done;
19991683a169SBarry Smith     PetscScalar    *sarray;
2000686e3a49SStefano Zampini 
20019566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
200228b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
20039566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
20049566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
20056afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
20066afe12f5SStefano Zampini       PetscInt sum;
20076afe12f5SStefano Zampini 
20086afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
20096afe12f5SStefano Zampini       if (sum == nvtxs) {
20106afe12f5SStefano Zampini         PetscInt r;
20116afe12f5SStefano Zampini 
20126afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
20136bdcaf15SBarry 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]);
20149566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
20156afe12f5SStefano Zampini           r += blocks[i];
20166afe12f5SStefano Zampini         }
20176afe12f5SStefano Zampini       } else {
201848a46eb9SPierre 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));
20196afe12f5SStefano Zampini       }
20206afe12f5SStefano Zampini     } else {
20218e3a54c0SPierre Jolivet       for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], PetscSafePointerPlusOffset(adjncy, xadj[i]), PetscSafePointerPlusOffset(sarray, xadj[i]), ADD_VALUES));
20226afe12f5SStefano Zampini     }
20239566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
202428b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
20259566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2026686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
2027ecf5a873SStefano Zampini     PetscInt i;
2028c0962df8SStefano Zampini 
2029686e3a49SStefano Zampini     for (i = 0; i < local_rows; i++) {
2030686e3a49SStefano Zampini       PetscInt        j;
2031ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2032686e3a49SStefano Zampini 
20339566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
20349566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
20359566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2036686e3a49SStefano Zampini     }
2037b7ce53b6SStefano Zampini   }
20389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
20411baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2042487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20439566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2044487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2045487b449aSStefano Zampini     *M = MT;
2046b7ce53b6SStefano Zampini   }
20473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2048b7ce53b6SStefano Zampini }
2049b7ce53b6SStefano Zampini 
2050b7ce53b6SStefano Zampini /*@
205111a5261eSBarry Smith   MatISGetMPIXAIJ - Converts `MATIS` matrix into a parallel `MATAIJ` format
2052b7ce53b6SStefano Zampini 
2053d8d19677SJose E. Roman   Input Parameters:
205411a5261eSBarry Smith + mat   - the matrix (should be of type `MATIS`)
205511a5261eSBarry Smith - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
2056b7ce53b6SStefano Zampini 
2057b7ce53b6SStefano Zampini   Output Parameter:
205811a5261eSBarry Smith . newmat - the matrix in `MATAIJ` format
2059b7ce53b6SStefano Zampini 
20602ef1f0ffSBarry Smith   Level: deprecated
2061b7ce53b6SStefano Zampini 
206211a5261eSBarry Smith   Note:
206311a5261eSBarry Smith   This function has been deprecated and it will be removed in future releases. Update your code to use the `MatConvert()` interface.
2064b7ce53b6SStefano Zampini 
20651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatConvert()`
2066b7ce53b6SStefano Zampini @*/
2067d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
2068d71ae5a4SJacob Faibussowitsch {
2069b7ce53b6SStefano Zampini   PetscFunctionBegin;
2070b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2071b7ce53b6SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, reuse, 2);
20724f572ea9SToby Isaac   PetscAssertPointer(newmat, 3);
2073487b449aSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
2074b7ce53b6SStefano Zampini     PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 3);
2075b7ce53b6SStefano Zampini     PetscCheckSameComm(mat, 1, *newmat, 3);
207608401ef6SPierre Jolivet     PetscCheck(mat != *newmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse the same matrix");
2077b7ce53b6SStefano Zampini   }
2078cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetMPIXAIJ_C", (Mat, MatType, MatReuse, Mat *), (mat, MATAIJ, reuse, newmat));
20793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2080b7ce53b6SStefano Zampini }
2081b7ce53b6SStefano Zampini 
2082d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2083d71ae5a4SJacob Faibussowitsch {
2084*f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2085c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2086ad6194a2SStefano Zampini   Mat      B, localmat;
2087ad6194a2SStefano Zampini 
2088ad6194a2SStefano Zampini   PetscFunctionBegin;
20899566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20909566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20919566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20929566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20939566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20949566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20959566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20969566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20979566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20989566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20999566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
21009566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
21019566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
21029566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
21039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
21049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2105ad6194a2SStefano Zampini   *newmat = B;
21063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2107ad6194a2SStefano Zampini }
2108ad6194a2SStefano Zampini 
2109d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2110d71ae5a4SJacob Faibussowitsch {
211169796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
211269796d55SStefano Zampini   PetscBool local_sym;
211369796d55SStefano Zampini 
211469796d55SStefano Zampini   PetscFunctionBegin;
21159566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
21161c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
21173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
211869796d55SStefano Zampini }
211969796d55SStefano Zampini 
2120d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2121d71ae5a4SJacob Faibussowitsch {
212269796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
212369796d55SStefano Zampini   PetscBool local_sym;
212469796d55SStefano Zampini 
212569796d55SStefano Zampini   PetscFunctionBegin;
2126e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2127e432b41dSStefano Zampini     *flg = PETSC_FALSE;
21283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2129e432b41dSStefano Zampini   }
21309566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
21311c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
21323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
213369796d55SStefano Zampini }
213469796d55SStefano Zampini 
2135d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2136d71ae5a4SJacob Faibussowitsch {
213745471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
213845471136SStefano Zampini   PetscBool local_sym;
213945471136SStefano Zampini 
214045471136SStefano Zampini   PetscFunctionBegin;
2141e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
214245471136SStefano Zampini     *flg = PETSC_FALSE;
21433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
214445471136SStefano Zampini   }
21459566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
21461c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
21473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
214845471136SStefano Zampini }
214945471136SStefano Zampini 
2150d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2151d71ae5a4SJacob Faibussowitsch {
2152b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2153b4319ba4SBarry Smith 
2154b4319ba4SBarry Smith   PetscFunctionBegin;
21559566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21569566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21589566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21599566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21609566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21619566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21629566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21639566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21649566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2165a8116848SStefano Zampini   if (b->sf != b->csf) {
21669566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21679566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2168f03112d0SStefano Zampini   } else b->csf = NULL;
21699566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21709566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2173d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2174d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21759566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21769566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21802e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", NULL));
21829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
21963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2197b4319ba4SBarry Smith }
2198b4319ba4SBarry Smith 
2199d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2200d71ae5a4SJacob Faibussowitsch {
2201b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2202b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2203b4319ba4SBarry Smith 
2204b4319ba4SBarry Smith   PetscFunctionBegin;
2205b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
22069566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
22079566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2208b4319ba4SBarry Smith 
2209b4319ba4SBarry Smith   /* multiply the local matrix */
22109566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2211b4319ba4SBarry Smith 
2212b4319ba4SBarry Smith   /* scatter product back into global memory */
22139566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
22149566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
22159566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
22163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2217b4319ba4SBarry Smith }
2218b4319ba4SBarry Smith 
2219d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2220d71ae5a4SJacob Faibussowitsch {
2221650997f4SStefano Zampini   Vec temp_vec;
22222e74eeadSLisandro Dalcin 
22232e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2224650997f4SStefano Zampini   if (v3 != v2) {
22259566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
22269566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2227650997f4SStefano Zampini   } else {
22289566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22299566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
22309566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22319566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2233650997f4SStefano Zampini   }
22343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22352e74eeadSLisandro Dalcin }
22362e74eeadSLisandro Dalcin 
2237d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2238d71ae5a4SJacob Faibussowitsch {
22392e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
22402e74eeadSLisandro Dalcin 
2241e176bc59SStefano Zampini   PetscFunctionBegin;
22422e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
22439566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22449566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
22452e74eeadSLisandro Dalcin 
22462e74eeadSLisandro Dalcin   /* multiply the local matrix */
22479566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
22482e74eeadSLisandro Dalcin 
22492e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22509566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22519566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22529566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22542e74eeadSLisandro Dalcin }
22552e74eeadSLisandro Dalcin 
2256d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2257d71ae5a4SJacob Faibussowitsch {
2258650997f4SStefano Zampini   Vec temp_vec;
22592e74eeadSLisandro Dalcin 
22602e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2261650997f4SStefano Zampini   if (v3 != v2) {
22629566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22639566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2264650997f4SStefano Zampini   } else {
22659566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22669566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22689566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2270650997f4SStefano Zampini   }
22713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22722e74eeadSLisandro Dalcin }
22732e74eeadSLisandro Dalcin 
2274d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2275d71ae5a4SJacob Faibussowitsch {
2276b4319ba4SBarry Smith   Mat_IS     *a = (Mat_IS *)A->data;
2277b4319ba4SBarry Smith   PetscViewer sviewer;
2278ee2491ecSStefano Zampini   PetscBool   isascii, view = PETSC_TRUE;
2279b4319ba4SBarry Smith 
2280b4319ba4SBarry Smith   PetscFunctionBegin;
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2282ee2491ecSStefano Zampini   if (isascii) {
2283ee2491ecSStefano Zampini     PetscViewerFormat format;
2284ee2491ecSStefano Zampini 
22859566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2286ee2491ecSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2287ee2491ecSStefano Zampini   }
22883ba16761SJacob Faibussowitsch   if (!view) PetscFunctionReturn(PETSC_SUCCESS);
22899566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22909566063dSJacob Faibussowitsch   PetscCall(MatView(a->A, sviewer));
22919566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2293b4319ba4SBarry Smith }
2294b4319ba4SBarry Smith 
2295d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2296d71ae5a4SJacob Faibussowitsch {
2297b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2298b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2299b89f26deSStefano Zampini   const PetscScalar *lv;
2300b89f26deSStefano Zampini   PetscInt           bs;
2301b89f26deSStefano Zampini 
2302b89f26deSStefano Zampini   PetscFunctionBegin;
23039566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
23049566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
23059566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
230648a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
23079566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(bs, MPIU_SCALAR, &nodeType));
23089566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
23099566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
23109566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
23119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2312b89f26deSStefano Zampini   if (values) *values = is->bdiag;
23133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2314b89f26deSStefano Zampini }
2315b89f26deSStefano Zampini 
2316d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2317d71ae5a4SJacob Faibussowitsch {
2318e176bc59SStefano Zampini   Vec             cglobal, rglobal;
23198546b261SStefano Zampini   IS              from;
23208546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2321b89f26deSStefano Zampini   PetscScalar     sum;
23228546b261SStefano Zampini   const PetscInt *garray;
23238546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2324e432b41dSStefano Zampini   VecType         rtype;
2325b4319ba4SBarry Smith 
2326b4319ba4SBarry Smith   PetscFunctionBegin;
23279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
23289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
23299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
23309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
23319566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
23329566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
23339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
23349566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
23359566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
23369566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
23379566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
23389566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
23399566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
23409566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
23419566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
23429566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
23439566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
23449566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
23459566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
23469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
23479566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2348e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
23499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
23509566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
23519566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
23529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
23539566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
23548546b261SStefano Zampini   } else {
23559566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
23568546b261SStefano Zampini     is->cctx = is->rctx;
23578546b261SStefano Zampini   }
23589566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2359b89f26deSStefano Zampini 
23608546b261SStefano Zampini   /* interface counter vector (local) */
23619566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
23629566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
23639566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
23649566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23659566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
23669566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23679566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
23689566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
23699566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2370b89f26deSStefano Zampini 
2371b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
23729566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2373b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2374e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
23759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2376b0cc1f67SStefano Zampini 
2377b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
23789566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
23793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23808546b261SStefano Zampini }
23818546b261SStefano Zampini 
2382d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2383d71ae5a4SJacob Faibussowitsch {
2384e432b41dSStefano Zampini   IS                         is;
2385e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2386e432b41dSStefano Zampini   const PetscInt            *idxs;
2387e432b41dSStefano Zampini   PetscHSetI                 ht;
2388e432b41dSStefano Zampini   PetscInt                  *nidxs;
2389e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2390e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2391e432b41dSStefano Zampini 
2392e432b41dSStefano Zampini   PetscFunctionBegin;
23939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
23949566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
23959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
23969566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
23979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2398e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
2399e432b41dSStefano Zampini     PetscBool missing;
24009371c9d4SSatish Balay     if (idxs[i] < 0) {
24019371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
24029371c9d4SSatish Balay       continue;
24039371c9d4SSatish Balay     }
24049566063dSJacob Faibussowitsch     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2405e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2406e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2407e432b41dSStefano Zampini   }
24089566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
24091c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2410e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2411e432b41dSStefano Zampini     *nmap = NULL;
2412e432b41dSStefano Zampini     *lmap = NULL;
24139566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
24149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
24153ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2416e432b41dSStefano Zampini   }
2417e432b41dSStefano Zampini 
2418e432b41dSStefano Zampini   /* New l2g map without negative or repeated indices */
24199566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
24209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
24219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
24229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
24239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2424e432b41dSStefano Zampini 
2425e432b41dSStefano Zampini   /* New local l2g map for repeated indices */
24269566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
24279566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
24289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
24299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
2430e432b41dSStefano Zampini 
24319566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
24329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
24333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2434e432b41dSStefano Zampini }
2435e432b41dSStefano Zampini 
2436d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2437d71ae5a4SJacob Faibussowitsch {
24388546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2439e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2440e432b41dSStefano Zampini   PetscBool              cong, freem[]                       = {PETSC_FALSE, PETSC_FALSE};
2441e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
24428546b261SStefano Zampini 
24438546b261SStefano Zampini   PetscFunctionBegin;
2444fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2445fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2446e432b41dSStefano Zampini 
24479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
24489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
24499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
24509566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
24519566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2452e432b41dSStefano Zampini 
2453fc989267SStefano Zampini   /* If NULL, local space matches global space */
2454fc989267SStefano Zampini   if (!rmapping) {
2455fc989267SStefano Zampini     IS is;
2456fc989267SStefano Zampini 
24579566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
24589566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
24599566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
24609566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2461e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2462e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2463e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
24649566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2465e432b41dSStefano Zampini     if (rmapping == cmapping) {
24669566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2467e432b41dSStefano Zampini       is->cmapping = is->rmapping;
24689566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2469e432b41dSStefano Zampini       localcmapping = localrmapping;
2470fc989267SStefano Zampini     }
2471fc989267SStefano Zampini   }
2472fc989267SStefano Zampini   if (!cmapping) {
2473fc989267SStefano Zampini     IS is;
2474fc989267SStefano Zampini 
24759566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
24769566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
24779566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
24789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2479e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2480e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
24819566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2482e432b41dSStefano Zampini   }
2483e432b41dSStefano Zampini   if (!is->rmapping) {
24849566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2485e432b41dSStefano Zampini     is->rmapping = rmapping;
2486e432b41dSStefano Zampini   }
2487e432b41dSStefano Zampini   if (!is->cmapping) {
24889566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2489e432b41dSStefano Zampini     is->cmapping = cmapping;
2490fc989267SStefano Zampini   }
2491fc989267SStefano Zampini 
2492fc989267SStefano Zampini   /* Clean up */
24939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2494872cf891SStefano Zampini   if (is->csf != is->sf) {
24959566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
24969566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2497f03112d0SStefano Zampini   } else is->csf = NULL;
24989566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
24999566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
25009566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
25013bbff08aSStefano Zampini 
2502fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2503fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
25049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
25059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
25069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
25079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2508e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2509e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
25106625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
25116625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
25126625354bSStefano Zampini 
25139566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
25149566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
25159566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
25169566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
25179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
25186625354bSStefano Zampini     }
25191c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2520e432b41dSStefano Zampini     if (same) {
25219566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
25229566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2523e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2524e432b41dSStefano Zampini     }
25256625354bSStefano Zampini   }
25269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
25279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2528e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
25299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
25309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
25319566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
25329566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
25336625354bSStefano Zampini 
25346625354bSStefano Zampini   /* Create the local matrix A */
25359566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
25369566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
25379566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
25389566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
25399566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
25409566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
25419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
25429566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
25439566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
25449566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
25459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2546b4319ba4SBarry Smith 
2547fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
25489566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2549fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
25503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2551fc989267SStefano Zampini }
2552fc989267SStefano Zampini 
2553d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2554d71ae5a4SJacob Faibussowitsch {
2555fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2556fc989267SStefano Zampini 
2557fc989267SStefano Zampini   PetscFunctionBegin;
25589566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
255948a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
25603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2561b4319ba4SBarry Smith }
2562b4319ba4SBarry Smith 
2563d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2564d71ae5a4SJacob Faibussowitsch {
25652e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2566f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
25672e74eeadSLisandro Dalcin 
25682e74eeadSLisandro Dalcin   PetscFunctionBegin;
25699566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2570e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25719566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25729566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2573e432b41dSStefano Zampini   } else {
25749566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2575e432b41dSStefano Zampini   }
25763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25772e74eeadSLisandro Dalcin }
25782e74eeadSLisandro Dalcin 
2579d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2580d71ae5a4SJacob Faibussowitsch {
258197563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2582f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
258397563a80SStefano Zampini 
258497563a80SStefano Zampini   PetscFunctionBegin;
25859566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2586e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
25879566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
25889566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2589e432b41dSStefano Zampini   } else {
25909566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, rows_l, values, addv));
2591e432b41dSStefano Zampini   }
25923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
259397563a80SStefano Zampini }
259497563a80SStefano Zampini 
2595d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2596d71ae5a4SJacob Faibussowitsch {
2597b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2598b4319ba4SBarry Smith 
2599b4319ba4SBarry Smith   PetscFunctionBegin;
2600e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
26019566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2602872cf891SStefano Zampini   } else {
26039566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2604872cf891SStefano Zampini   }
26053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2606b4319ba4SBarry Smith }
2607b4319ba4SBarry Smith 
2608d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2609d71ae5a4SJacob Faibussowitsch {
2610f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2611f0006bf2SLisandro Dalcin 
2612f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2613e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
26149566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2615b4f971dfSStefano Zampini   } else {
26169566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2617b4f971dfSStefano Zampini   }
26183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2619f0006bf2SLisandro Dalcin }
2620f0006bf2SLisandro Dalcin 
2621d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2622d71ae5a4SJacob Faibussowitsch {
2623f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2624f0ae7da4SStefano Zampini 
2625f0ae7da4SStefano Zampini   PetscFunctionBegin;
2626f0ae7da4SStefano Zampini   if (!n) {
2627f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2628f0ae7da4SStefano Zampini   } else {
2629f0ae7da4SStefano Zampini     PetscInt i;
2630f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2631f0ae7da4SStefano Zampini 
2632f0ae7da4SStefano Zampini     if (columns) {
26339566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2634f0ae7da4SStefano Zampini     } else {
26359566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2636f0ae7da4SStefano Zampini     }
2637f0ae7da4SStefano Zampini     if (diag != 0.) {
2638f0ae7da4SStefano Zampini       const PetscScalar *array;
26399566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
264048a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
26419566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2642f0ae7da4SStefano Zampini     }
26439566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
26449566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2645f0ae7da4SStefano Zampini   }
26463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2647f0ae7da4SStefano Zampini }
2648f0ae7da4SStefano Zampini 
2649d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2650d71ae5a4SJacob Faibussowitsch {
26516e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
26526e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
26536e520ac8SStefano Zampini   PetscInt *lrows;
26542e74eeadSLisandro Dalcin 
26552e74eeadSLisandro Dalcin   PetscFunctionBegin;
2656cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2657f0ae7da4SStefano Zampini     PetscBool cong;
265826b0207aSStefano Zampini 
26599566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
266026b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
266108401ef6SPierre 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");
2662aed4548fSBarry 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");
2663aed4548fSBarry 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");
2664f0ae7da4SStefano Zampini   }
26656e520ac8SStefano Zampini   /* get locally owned rows */
26669566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
26676e520ac8SStefano Zampini   /* fix right hand side if needed */
26686e520ac8SStefano Zampini   if (x && b) {
26696e520ac8SStefano Zampini     const PetscScalar *xx;
26706e520ac8SStefano Zampini     PetscScalar       *bb;
26716e520ac8SStefano Zampini 
26729566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
26739566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
26746e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
26759566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
26769566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
26772e74eeadSLisandro Dalcin   }
26786e520ac8SStefano Zampini   /* get rows associated to the local matrices */
26799566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
26809566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
26819566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
26826e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
26839566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
26849566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26859566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
26869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
26879371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
26889371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
26899566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
26909566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2691d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2692d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
26933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26942e74eeadSLisandro Dalcin }
26952e74eeadSLisandro Dalcin 
2696d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2697d71ae5a4SJacob Faibussowitsch {
2698b4319ba4SBarry Smith   PetscFunctionBegin;
26999566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
27003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2701f0ae7da4SStefano Zampini }
27022205254eSKarl Rupp 
2703d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2704d71ae5a4SJacob Faibussowitsch {
2705f0ae7da4SStefano Zampini   PetscFunctionBegin;
27069566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
27073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2708b4319ba4SBarry Smith }
2709b4319ba4SBarry Smith 
2710d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2711d71ae5a4SJacob Faibussowitsch {
2712b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2713b4319ba4SBarry Smith 
2714b4319ba4SBarry Smith   PetscFunctionBegin;
27159566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
27163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2717b4319ba4SBarry Smith }
2718b4319ba4SBarry Smith 
2719d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2720d71ae5a4SJacob Faibussowitsch {
2721b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2722d0dbe9f7SStefano Zampini   PetscBool lnnz;
2723b4319ba4SBarry Smith 
2724b4319ba4SBarry Smith   PetscFunctionBegin;
27259566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2726872cf891SStefano Zampini   /* fix for local empty rows/cols */
2727872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2728872cf891SStefano Zampini     Mat                    newlA;
2729f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2730f03112d0SStefano Zampini     IS                     nzr, nzc;
2731f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2732f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2733872cf891SStefano Zampini 
27349566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
27359566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
273648a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
27379566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
273848a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
27399566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
27409566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2741e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2742f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
2743712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2744f03112d0SStefano Zampini 
2745872cf891SStefano Zampini       /* extract valid submatrix */
27469566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2747f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2748f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
2749712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
27509566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2751f03112d0SStefano Zampini       newlA = is->A;
2752f03112d0SStefano Zampini     }
2753e432b41dSStefano Zampini 
2754f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2755f03112d0SStefano Zampini     if (newl2g) {
2756e432b41dSStefano Zampini       IS              zr, zc;
2757e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2758e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2759f03112d0SStefano Zampini 
27609566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
27619566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
27629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
27639566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
27649566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
27659566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
27669566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
27679566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
27689566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2769e432b41dSStefano Zampini 
27709566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2771e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
27729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
27739566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2774e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
27759566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2776e432b41dSStefano Zampini 
27779566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
27789566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
27799566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
27809566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
27819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
27829566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
27839566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
27849566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
27859566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
27869566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
27879566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
27889566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2789f03112d0SStefano Zampini     }
27909566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
27919566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
27929566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
27939566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2794872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2795f03112d0SStefano Zampini   }
2796d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2797d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
2798d0dbe9f7SStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2799d0dbe9f7SStefano Zampini   if (lnnz) A->nonzerostate++;
28003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2801b4319ba4SBarry Smith }
2802b4319ba4SBarry Smith 
2803d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
2804d71ae5a4SJacob Faibussowitsch {
2805b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2806b4319ba4SBarry Smith 
2807b4319ba4SBarry Smith   PetscFunctionBegin;
2808b4319ba4SBarry Smith   *local = is->A;
28093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2810b4319ba4SBarry Smith }
2811b4319ba4SBarry Smith 
2812d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
2813d71ae5a4SJacob Faibussowitsch {
28143b3b1effSJed Brown   PetscFunctionBegin;
28153b3b1effSJed Brown   *local = NULL;
28163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28173b3b1effSJed Brown }
28183b3b1effSJed Brown 
2819b4319ba4SBarry Smith /*@
282011a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2821b4319ba4SBarry Smith 
2822b4319ba4SBarry Smith   Input Parameter:
2823b4319ba4SBarry Smith . mat - the matrix
2824b4319ba4SBarry Smith 
2825b4319ba4SBarry Smith   Output Parameter:
2826eb82efa4SStefano Zampini . local - the local matrix
2827b4319ba4SBarry Smith 
2828b4319ba4SBarry Smith   Level: advanced
2829b4319ba4SBarry Smith 
2830b4319ba4SBarry Smith   Notes:
2831b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
2832b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
283311a5261eSBarry Smith   of the `MatSetValues()` operation.
2834b4319ba4SBarry Smith 
283511a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
283696a6f129SJed Brown 
28371cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
2838b4319ba4SBarry Smith @*/
2839d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
2840d71ae5a4SJacob Faibussowitsch {
2841b4319ba4SBarry Smith   PetscFunctionBegin;
28420700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
28434f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2844cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
28453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2846b4319ba4SBarry Smith }
2847b4319ba4SBarry Smith 
28483b3b1effSJed Brown /*@
284911a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
28503b3b1effSJed Brown 
28512ef1f0ffSBarry Smith   Input Parameters:
28522ef1f0ffSBarry Smith + mat   - the matrix
28532ef1f0ffSBarry Smith - local - the local matrix
28543b3b1effSJed Brown 
28553b3b1effSJed Brown   Level: advanced
28563b3b1effSJed Brown 
28571cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
28583b3b1effSJed Brown @*/
2859d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
2860d71ae5a4SJacob Faibussowitsch {
28613b3b1effSJed Brown   PetscFunctionBegin;
28623b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
28634f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2864cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
28653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28663b3b1effSJed Brown }
28673b3b1effSJed Brown 
2868d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
2869d71ae5a4SJacob Faibussowitsch {
28708546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
28718546b261SStefano Zampini 
28728546b261SStefano Zampini   PetscFunctionBegin;
28731baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
28749566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
28759566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
28763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28778546b261SStefano Zampini }
28788546b261SStefano Zampini 
2879fe59aa6dSJacob Faibussowitsch /*@C
288011a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
28818546b261SStefano Zampini 
2882d8d19677SJose E. Roman   Input Parameters:
2883a2b725a8SWilliam Gropp + mat   - the matrix
2884a2b725a8SWilliam Gropp - mtype - the local matrix type
28858546b261SStefano Zampini 
28868546b261SStefano Zampini   Level: advanced
28878546b261SStefano Zampini 
28881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
28898546b261SStefano Zampini @*/
2890d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
2891d71ae5a4SJacob Faibussowitsch {
28928546b261SStefano Zampini   PetscFunctionBegin;
28938546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2894cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
28953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28968546b261SStefano Zampini }
28978546b261SStefano Zampini 
2898d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
2899d71ae5a4SJacob Faibussowitsch {
29003b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
29013b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
29028546b261SStefano Zampini   MatType   mtype, otype;
29038546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
29043b03a366Sstefano_zampini 
29053b03a366Sstefano_zampini   PetscFunctionBegin;
2906e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
29079566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
29089566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
2909aed4548fSBarry 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);
29109566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
29119566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
29129566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
29134e4c7dbeSStefano Zampini   }
29149566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
29159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
29163b03a366Sstefano_zampini   is->A = local;
29179566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
29189566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
291948a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
29203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29213b03a366Sstefano_zampini }
29223b03a366Sstefano_zampini 
29233b03a366Sstefano_zampini /*@
292411a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
29253b03a366Sstefano_zampini 
2926c3339decSBarry Smith   Collective
29278546b261SStefano Zampini 
2928d8d19677SJose E. Roman   Input Parameters:
2929a2b725a8SWilliam Gropp + mat   - the matrix
2930a2b725a8SWilliam Gropp - local - the local matrix
29313b03a366Sstefano_zampini 
29323b03a366Sstefano_zampini   Level: advanced
29333b03a366Sstefano_zampini 
29343b03a366Sstefano_zampini   Notes:
293511a5261eSBarry Smith   Any previous matrix within the `MATIS` has its reference count decreased by one.
29363b03a366Sstefano_zampini 
293711a5261eSBarry Smith   This can be called if you have precomputed the local matrix and
293811a5261eSBarry Smith   want to provide it to the matrix object `MATIS`.
293911a5261eSBarry Smith 
29401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
29413b03a366Sstefano_zampini @*/
2942d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
2943d71ae5a4SJacob Faibussowitsch {
29443b03a366Sstefano_zampini   PetscFunctionBegin;
29453b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2946b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
2947cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
29483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29493b03a366Sstefano_zampini }
29503b03a366Sstefano_zampini 
2951d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
2952d71ae5a4SJacob Faibussowitsch {
29536726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29546726f965SBarry Smith 
29556726f965SBarry Smith   PetscFunctionBegin;
29569566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
29573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29586726f965SBarry Smith }
29596726f965SBarry Smith 
2960d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
2961d71ae5a4SJacob Faibussowitsch {
29622e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29632e74eeadSLisandro Dalcin 
29642e74eeadSLisandro Dalcin   PetscFunctionBegin;
29659566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
29663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29672e74eeadSLisandro Dalcin }
29682e74eeadSLisandro Dalcin 
2969d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
2970d71ae5a4SJacob Faibussowitsch {
29712e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
29722e74eeadSLisandro Dalcin 
29732e74eeadSLisandro Dalcin   PetscFunctionBegin;
29742e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
29759566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
29762e74eeadSLisandro Dalcin 
29772e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
29789566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
29799566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29809566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
29813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29822e74eeadSLisandro Dalcin }
29832e74eeadSLisandro Dalcin 
2984d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
2985d71ae5a4SJacob Faibussowitsch {
29866726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
29876726f965SBarry Smith 
29886726f965SBarry Smith   PetscFunctionBegin;
29899566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
29903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29916726f965SBarry Smith }
29926726f965SBarry Smith 
2993d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
2994d71ae5a4SJacob Faibussowitsch {
2995f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
2996f26d0771SStefano Zampini   Mat_IS *x;
2997f26d0771SStefano Zampini 
2998f26d0771SStefano Zampini   PetscFunctionBegin;
299976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
300076bd3646SJed Brown     PetscBool ismatis;
30019566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
300228b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
300376bd3646SJed Brown   }
3004f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
30059566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
30063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3007f26d0771SStefano Zampini }
3008f26d0771SStefano Zampini 
3009d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3010d71ae5a4SJacob Faibussowitsch {
3011f26d0771SStefano Zampini   Mat                    lA;
3012*f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3013f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3014f26d0771SStefano Zampini   IS                     is;
3015f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3016f26d0771SStefano Zampini   PetscInt               nrg;
3017f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3018f26d0771SStefano Zampini 
3019f26d0771SStefano Zampini   PetscFunctionBegin;
30209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
30219566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
30229566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
30239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
302476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
302508401ef6SPierre 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);
302676bd3646SJed Brown   }
30279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3028f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3029f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3030f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
30319566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
30329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
30339566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
30349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
30359566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3036f26d0771SStefano Zampini   /* compute new l2g map for columns */
3037e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3038f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3039f26d0771SStefano Zampini     PetscInt        ncg;
3040f26d0771SStefano Zampini     PetscInt        ncl;
3041f26d0771SStefano Zampini 
30429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
30439566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
30449566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
30459566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
304676bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
304708401ef6SPierre 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);
304876bd3646SJed Brown     }
30499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3050f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3051f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3052f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
30539566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
30549566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
30559566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
30569566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
30579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3058f26d0771SStefano Zampini   } else {
30599566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3060f26d0771SStefano Zampini     cl2g = rl2g;
3061f26d0771SStefano Zampini   }
3062f26d0771SStefano Zampini   /* create the MATIS submatrix */
30639566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
30649566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
30659566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
30669566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3067b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3068f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
30699566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
30709566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
30719566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
30729566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
30739566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
30749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
30759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3077e432b41dSStefano Zampini 
3078f26d0771SStefano Zampini   /* remove unsupported ops */
30799566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3080f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3081f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3082f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3083f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3084f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
30853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3086f26d0771SStefano Zampini }
3087f26d0771SStefano Zampini 
3088d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject)
3089d71ae5a4SJacob Faibussowitsch {
3090872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
30918546b261SStefano Zampini   char      type[256];
30928546b261SStefano Zampini   PetscBool flg;
3093872cf891SStefano Zampini 
3094872cf891SStefano Zampini   PetscFunctionBegin;
3095d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3096d0dbe9f7SStefano Zampini   PetscCall(PetscOptionsBool("-matis_keepassembled", "Store an assembled version if needed", "MatISKeepAssembled", a->keepassembled, &a->keepassembled, NULL));
30979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
30989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-matis_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
30999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-matis_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
31001baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
31011baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3102d0609cedSBarry Smith   PetscOptionsHeadEnd();
31033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3104872cf891SStefano Zampini }
3105872cf891SStefano Zampini 
3106284134d9SBarry Smith /*@
310711a5261eSBarry Smith   MatCreateIS - Creates a "process" unassembled matrix, `MATIS`, assembled on each
3108284134d9SBarry Smith   process but not across processes.
3109284134d9SBarry Smith 
3110284134d9SBarry Smith   Input Parameters:
3111284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3112e176bc59SStefano Zampini . bs   - block size of the matrix
31132920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
31142920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
31152920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
31162920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3117e176bc59SStefano Zampini . rmap - local to global map for rows
3118e176bc59SStefano Zampini - cmap - local to global map for cols
3119284134d9SBarry Smith 
3120284134d9SBarry Smith   Output Parameter:
3121284134d9SBarry Smith . A - the resulting matrix
3122284134d9SBarry Smith 
31238e6c10adSSatish Balay   Level: advanced
31248e6c10adSSatish Balay 
312595452b02SPatrick Sanan   Notes:
31262ef1f0ffSBarry Smith   `m` and `n` are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
312711a5261eSBarry Smith   used in `MatMult()` operations. The sizes of rmap and cmap define the size of the local matrices.
312811a5261eSBarry Smith 
31292ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3130284134d9SBarry Smith 
31311cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3132284134d9SBarry Smith @*/
3133d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3134d71ae5a4SJacob Faibussowitsch {
3135284134d9SBarry Smith   PetscFunctionBegin;
31369566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
31379566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
313848a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
31399566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
31409566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
31413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3142284134d9SBarry Smith }
3143284134d9SBarry Smith 
3144d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3145d71ae5a4SJacob Faibussowitsch {
31468b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3147e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
31488b9382cfSStefano Zampini 
31498b9382cfSStefano Zampini   PetscFunctionBegin;
31508b9382cfSStefano Zampini   *has = PETSC_FALSE;
31513ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3152d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
31539371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
31543ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
31559566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
31563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31578b9382cfSStefano Zampini }
31588b9382cfSStefano Zampini 
3159d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3160d71ae5a4SJacob Faibussowitsch {
3161e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3162e432b41dSStefano Zampini 
3163e432b41dSStefano Zampini   PetscFunctionBegin;
31649566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
31659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
31669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
31673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3168e432b41dSStefano Zampini }
3169e432b41dSStefano Zampini 
3170d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3171d71ae5a4SJacob Faibussowitsch {
3172e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3173e432b41dSStefano Zampini 
3174e432b41dSStefano Zampini   PetscFunctionBegin;
3175e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3176e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
31779566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3178e432b41dSStefano Zampini   } else {
31799566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3180e432b41dSStefano Zampini   }
31819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3182e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
31833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3184e432b41dSStefano Zampini }
3185e432b41dSStefano Zampini 
3186d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3187d71ae5a4SJacob Faibussowitsch {
3188e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3189e432b41dSStefano Zampini 
3190e432b41dSStefano Zampini   PetscFunctionBegin;
3191e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3192e432b41dSStefano 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);
3193e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo, coo_i, NULL, coo_i));
3194e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo, coo_j, NULL, coo_j));
3195e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
31969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3197e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
31983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3199e432b41dSStefano Zampini }
3200e432b41dSStefano Zampini 
3201d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3202d71ae5a4SJacob Faibussowitsch {
3203d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3204d0dbe9f7SStefano Zampini   PetscObjectState Astate, aAstate       = PETSC_MIN_INT;
3205d0dbe9f7SStefano Zampini   PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT;
3206d0dbe9f7SStefano Zampini 
3207d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3208d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3209d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3210d0dbe9f7SStefano Zampini   if (a->assembledA) {
3211d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3212d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3213d0dbe9f7SStefano Zampini   }
3214d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3215d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3216d0dbe9f7SStefano Zampini     MatType     aAtype;
3217d0dbe9f7SStefano Zampini     PetscMPIInt size;
3218d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3219d0dbe9f7SStefano Zampini 
3220d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3221d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3222d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3223d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3224d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3225d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3226d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3227d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3228d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3229d0dbe9f7SStefano Zampini 
3230d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3231d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3232d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3233d0dbe9f7SStefano Zampini   }
3234d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3235d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3236d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
32373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3238d0dbe9f7SStefano Zampini }
3239d0dbe9f7SStefano Zampini 
3240d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3241d71ae5a4SJacob Faibussowitsch {
3242d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3243d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3244d0dbe9f7SStefano Zampini   *tA = NULL;
32453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3246d0dbe9f7SStefano Zampini }
3247d0dbe9f7SStefano Zampini 
3248d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3249d71ae5a4SJacob Faibussowitsch {
3250d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3251d0dbe9f7SStefano Zampini   PetscObjectState Astate, dAstate = PETSC_MIN_INT;
3252d0dbe9f7SStefano Zampini 
3253d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3254d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3255d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3256d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3257d0dbe9f7SStefano Zampini     Mat     tA;
3258d0dbe9f7SStefano Zampini     MatType ltype;
3259d0dbe9f7SStefano Zampini 
3260d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3261d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3262d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3263d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3264d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3265d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3266d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3267d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3268d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3269d0dbe9f7SStefano Zampini   }
3270d0dbe9f7SStefano Zampini   *dA = a->dA;
32713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3272d0dbe9f7SStefano Zampini }
3273d0dbe9f7SStefano Zampini 
3274d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3275d71ae5a4SJacob Faibussowitsch {
3276d0dbe9f7SStefano Zampini   Mat tA;
3277d0dbe9f7SStefano Zampini 
3278d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3279d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3280d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3281d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3282d0dbe9f7SStefano Zampini #if 0
3283d0dbe9f7SStefano Zampini   {
3284d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3285d0dbe9f7SStefano Zampini     MatType   ltype;
3286d0dbe9f7SStefano Zampini     VecType   vtype;
3287d0dbe9f7SStefano Zampini     char      *flg;
3288d0dbe9f7SStefano Zampini 
3289d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3290d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3291d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3292d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3293d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3294d0dbe9f7SStefano Zampini     if (flg) {
3295d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3296d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3297d0dbe9f7SStefano Zampini 
3298d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3299d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3300d0dbe9f7SStefano Zampini       }
3301d0dbe9f7SStefano Zampini     }
3302d0dbe9f7SStefano Zampini   }
3303d0dbe9f7SStefano Zampini #endif
3304d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
33053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3306d0dbe9f7SStefano Zampini }
3307d0dbe9f7SStefano Zampini 
3308d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3309d71ae5a4SJacob Faibussowitsch {
3310d0dbe9f7SStefano Zampini   Mat tA;
3311d0dbe9f7SStefano Zampini 
3312d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3313d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3314d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3315d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
33163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3317d0dbe9f7SStefano Zampini }
3318d0dbe9f7SStefano Zampini 
3319e432b41dSStefano Zampini /*@
332011a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3321e432b41dSStefano Zampini 
3322e432b41dSStefano Zampini   Not Collective
3323e432b41dSStefano Zampini 
3324e432b41dSStefano Zampini   Input Parameter:
3325e432b41dSStefano Zampini . A - the matrix
3326e432b41dSStefano Zampini 
3327e432b41dSStefano Zampini   Output Parameters:
3328e432b41dSStefano Zampini + rmapping - row mapping
3329e432b41dSStefano Zampini - cmapping - column mapping
3330e432b41dSStefano Zampini 
33312ef1f0ffSBarry Smith   Level: advanced
33322ef1f0ffSBarry Smith 
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 
33361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatIS`, `MatSetLocalToGlobalMapping()`
3337e432b41dSStefano Zampini @*/
3338d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3339d71ae5a4SJacob Faibussowitsch {
3340e432b41dSStefano Zampini   PetscFunctionBegin;
3341e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3342e432b41dSStefano Zampini   PetscValidType(A, 1);
33434f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
33444f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3345cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
33463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3347e432b41dSStefano Zampini }
3348e432b41dSStefano Zampini 
3349d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3350d71ae5a4SJacob Faibussowitsch {
3351e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3352e432b41dSStefano Zampini 
3353e432b41dSStefano Zampini   PetscFunctionBegin;
3354e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3355e432b41dSStefano Zampini   if (c) *c = a->cmapping;
33563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3357e432b41dSStefano Zampini }
3358e432b41dSStefano Zampini 
3359b4319ba4SBarry Smith /*MC
336011a5261eSBarry Smith    MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
3361b89f26deSStefano Zampini    This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3362b4319ba4SBarry Smith    product is handled "implicitly".
3363b4319ba4SBarry Smith 
3364b4319ba4SBarry Smith    Options Database Keys:
33652ef1f0ffSBarry Smith + -mat_type is - sets the matrix type to `MATIS`.
336675d48cdbSStefano Zampini . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
33672ef1f0ffSBarry Smith - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
33682ef1f0ffSBarry Smith 
33692ef1f0ffSBarry Smith   Level: advanced
3370b4319ba4SBarry Smith 
337195452b02SPatrick Sanan    Notes:
33722ef1f0ffSBarry Smith    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 
33791cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3380b4319ba4SBarry Smith M*/
3381d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3382d71ae5a4SJacob Faibussowitsch {
3383e432b41dSStefano Zampini   Mat_IS *a;
3384b4319ba4SBarry Smith 
3385b4319ba4SBarry Smith   PetscFunctionBegin;
33864dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
33879566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3388e432b41dSStefano Zampini   A->data = (void *)a;
3389b4319ba4SBarry Smith 
3390e176bc59SStefano Zampini   /* matrix ops */
33919566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3392b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
33932e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
33942e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
33952e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3396b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3397b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
33982e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
339998921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3400b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3401f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
34022e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3403f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3404b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3405b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3406b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
34076726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
34082e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
34092e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
34106726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
341169796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
341269796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
341345471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3414ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
34156bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
34162b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3417659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
34187dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3419f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
34203fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
34213fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3422d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
34237fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3424ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3425872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3426fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
34278b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3428d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3429d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3430d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3431b4319ba4SBarry Smith 
3432b7ce53b6SStefano Zampini   /* special MATIS functions */
34339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
34349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
34359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
34369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
34379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetMPIXAIJ_C", MatConvert_IS_XAIJ));
34389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
34399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
34409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
34419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
34429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
34439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
34449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
34459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
34469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
34479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
34489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
34499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
34509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
34519566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
34523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3453b4319ba4SBarry Smith }
3454