xref: /petsc/src/mat/impls/is/matis.c (revision d72e20dbf88ebab8ccdd7395f3c9d876f628ab64)
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));
2104f58015eSStefano Zampini     PetscCall(ISCreateBlock(comm, ibs, N1 / 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 {
345f4f49eeaSPierre 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));
5654f58015eSStefano Zampini     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-mat_is_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));
6946989cf23SStefano Zampini 
6956989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
6969566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
6979566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
6989566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &dr, &dc));
6999566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
700*d72e20dbSStefano Zampini   PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
701*d72e20dbSStefano Zampini 
7029566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
70328b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
7049566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
70528b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
706c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
707c9225affSStefano Zampini   /* store original pointers to be restored later */
7089371c9d4SSatish Balay   odi = di;
7099371c9d4SSatish Balay   odj = dj;
7109371c9d4SSatish Balay   ooi = oi;
7119371c9d4SSatish Balay   ooj = oj;
7126989cf23SStefano Zampini 
7136989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
7149566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(comm, dr / bs, str / bs, 1, &is));
715c9225affSStefano Zampini   if (bs > 1) {
716c9225affSStefano Zampini     IS is2;
717c9225affSStefano Zampini 
7189566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7199566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
7209566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, i, aux, PETSC_COPY_VALUES, &is2));
7219566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7229566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
723c9225affSStefano Zampini     is = is2;
724c9225affSStefano Zampini   }
7259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
727e363d98aSStefano Zampini   if (dr) {
7289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
729c9225affSStefano Zampini     for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
730c9225affSStefano Zampini     for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = garray[i];
7319566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
732e363d98aSStefano Zampini     lc = dc + oc;
733e363d98aSStefano Zampini   } else {
7349566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, bs, 0, NULL, PETSC_OWN_POINTER, &is));
735e363d98aSStefano Zampini     lc = 0;
736e363d98aSStefano Zampini   }
7379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7396989cf23SStefano Zampini 
7406989cf23SStefano Zampini   /* create MATIS object */
7419566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7429566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7439566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
7449566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, bs));
7459566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7486989cf23SStefano Zampini 
7496989cf23SStefano Zampini   /* merge local matrices */
7509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7526989cf23SStefano Zampini   ii  = aux;
7536989cf23SStefano Zampini   jj  = aux + dr + 1;
7546989cf23SStefano Zampini   aa  = data;
7556989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7569371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7579371c9d4SSatish Balay     for (; jd < *di; jd++) {
7589371c9d4SSatish Balay       *jj++ = *dj++;
7599371c9d4SSatish Balay       *aa++ = *dd++;
7609371c9d4SSatish Balay     }
7619371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7629371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7639371c9d4SSatish Balay       *aa++ = *od++;
7649371c9d4SSatish Balay     }
7656989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7666989cf23SStefano Zampini   }
7676989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
768c9225affSStefano Zampini 
7699566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
77028b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7719566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
77228b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7739566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
775c9225affSStefano Zampini 
7766989cf23SStefano Zampini   ii = aux;
7776989cf23SStefano Zampini   jj = aux + dr + 1;
7786989cf23SStefano Zampini   aa = data;
7799566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
7806989cf23SStefano Zampini 
7816989cf23SStefano Zampini   /* create containers to destroy the data */
7826989cf23SStefano Zampini   ptrs[0] = aux;
7836989cf23SStefano Zampini   ptrs[1] = data;
7846989cf23SStefano Zampini   for (i = 0; i < 2; i++) {
7856989cf23SStefano Zampini     PetscContainer c;
7866989cf23SStefano Zampini 
7879566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
7889566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, ptrs[i]));
7899566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
7909566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)lA, names[i], (PetscObject)c));
7919566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
7926989cf23SStefano Zampini   }
793c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7949566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
796c9225affSStefano Zampini   }
7976989cf23SStefano Zampini 
7986989cf23SStefano Zampini   /* finalize matrix */
7999566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
8009566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
8019566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
8029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
803c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
8049566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
805c9225affSStefano Zampini   } else *newmat = B;
8063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8076989cf23SStefano Zampini }
8086989cf23SStefano Zampini 
809d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
810d71ae5a4SJacob Faibussowitsch {
8115e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8125e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8135e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8145e3038f0Sstefano_zampini   MPI_Comm               comm;
8155b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8165b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8179e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8184f58015eSStefano Zampini   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
8195e3038f0Sstefano_zampini 
820ab4d48faSStefano Zampini   PetscFunctionBegin;
8219566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8225e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8235e3038f0Sstefano_zampini   rnest  = NULL;
8245e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8255e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8265e3038f0Sstefano_zampini 
8279566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
828f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8299566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8309566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8315e3038f0Sstefano_zampini     if (isnest) {
8329566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8335e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8345e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8355e3038f0Sstefano_zampini     }
8365e3038f0Sstefano_zampini   }
8379566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8399566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8409566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8415e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8425e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8434f58015eSStefano Zampini       PetscBool ismatis, sallow;
8449e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8455e3038f0Sstefano_zampini 
8465e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8475e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8485e3038f0Sstefano_zampini 
8495e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
850013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8519e7b2b25Sstefano_zampini       if (istrans[ij]) {
8529e7b2b25Sstefano_zampini         Mat T, lT;
8539566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8549566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
85528b400f6SJacob Faibussowitsch         PetscCheck(ismatis, comm, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") (transposed) is not of type MATIS", i, j);
8564f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(T, &sallow));
8579566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8589566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8599e7b2b25Sstefano_zampini       } else {
8609566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
86128b400f6SJacob 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);
8624f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
8639566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8649e7b2b25Sstefano_zampini       }
8654f58015eSStefano Zampini       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
8664f58015eSStefano Zampini       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
8675e3038f0Sstefano_zampini 
8685e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8699566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8709566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8715e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
872aed4548fSBarry 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);
873aed4548fSBarry 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);
8745e3038f0Sstefano_zampini       lr[i] = l1;
8755e3038f0Sstefano_zampini       lc[j] = l2;
8765e3038f0Sstefano_zampini 
877da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8785e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8795e3038f0Sstefano_zampini     }
8805e3038f0Sstefano_zampini   }
8815e3038f0Sstefano_zampini 
88276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8835e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8845e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8855e3038f0Sstefano_zampini       rl2g = NULL;
8865e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8875e3038f0Sstefano_zampini         PetscInt n1, n2;
8885e3038f0Sstefano_zampini 
8895e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8909e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8919e7b2b25Sstefano_zampini           Mat T;
8929e7b2b25Sstefano_zampini 
8939566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8949566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8959e7b2b25Sstefano_zampini         } else {
8969566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8979e7b2b25Sstefano_zampini         }
8989566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8995e3038f0Sstefano_zampini         if (!n1) continue;
9005e3038f0Sstefano_zampini         if (!rl2g) {
9015e3038f0Sstefano_zampini           rl2g = cl2g;
9025e3038f0Sstefano_zampini         } else {
9035e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9045e3038f0Sstefano_zampini           PetscBool       same;
9055e3038f0Sstefano_zampini 
9069566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
90708401ef6SPierre 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);
9089566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9099566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9109566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9119566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9129566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
91328b400f6SJacob 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);
9145e3038f0Sstefano_zampini         }
9155e3038f0Sstefano_zampini       }
9165e3038f0Sstefano_zampini     }
9175e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9185e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9195e3038f0Sstefano_zampini       rl2g = NULL;
9205e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9215e3038f0Sstefano_zampini         PetscInt n1, n2;
9225e3038f0Sstefano_zampini 
9235e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9249e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9259e7b2b25Sstefano_zampini           Mat T;
9269e7b2b25Sstefano_zampini 
9279566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9289566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9299e7b2b25Sstefano_zampini         } else {
9309566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9319e7b2b25Sstefano_zampini         }
9329566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9335e3038f0Sstefano_zampini         if (!n1) continue;
9345e3038f0Sstefano_zampini         if (!rl2g) {
9355e3038f0Sstefano_zampini           rl2g = cl2g;
9365e3038f0Sstefano_zampini         } else {
9375e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9385e3038f0Sstefano_zampini           PetscBool       same;
9395e3038f0Sstefano_zampini 
9409566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
94108401ef6SPierre 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);
9429566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9439566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9449566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9459566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9469566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
94728b400f6SJacob 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);
9485e3038f0Sstefano_zampini         }
9495e3038f0Sstefano_zampini       }
9505e3038f0Sstefano_zampini     }
95176bd3646SJed Brown   }
9525e3038f0Sstefano_zampini 
9535e3038f0Sstefano_zampini   B = NULL;
9545e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9555b003df0Sstefano_zampini     PetscInt stl;
9565b003df0Sstefano_zampini 
9575e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9585e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9605b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9615e3038f0Sstefano_zampini       Mat             usedmat;
9625e3038f0Sstefano_zampini       Mat_IS         *matis;
9635e3038f0Sstefano_zampini       const PetscInt *idxs;
9645e3038f0Sstefano_zampini 
9655e3038f0Sstefano_zampini       /* local IS for local NEST */
9669566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9675e3038f0Sstefano_zampini 
9685e3038f0Sstefano_zampini       /* l2gmap */
9695e3038f0Sstefano_zampini       j       = 0;
9705e3038f0Sstefano_zampini       usedmat = nest[i][j];
9719e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
97228b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9739e7b2b25Sstefano_zampini 
9749e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9759e7b2b25Sstefano_zampini         Mat T;
9769566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9779e7b2b25Sstefano_zampini         usedmat = T;
9789e7b2b25Sstefano_zampini       }
979f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9809566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9819e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9829566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9839566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9849e7b2b25Sstefano_zampini       } else {
9859566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9869566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9879e7b2b25Sstefano_zampini       }
9889566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9895e3038f0Sstefano_zampini       stl += lr[i];
9905e3038f0Sstefano_zampini     }
9919566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9925e3038f0Sstefano_zampini 
9935e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9945e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9965b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9975e3038f0Sstefano_zampini       Mat             usedmat;
9985e3038f0Sstefano_zampini       Mat_IS         *matis;
9995e3038f0Sstefano_zampini       const PetscInt *idxs;
10005e3038f0Sstefano_zampini 
10015e3038f0Sstefano_zampini       /* local IS for local NEST */
10029566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10035e3038f0Sstefano_zampini 
10045e3038f0Sstefano_zampini       /* l2gmap */
10055e3038f0Sstefano_zampini       j       = 0;
10065e3038f0Sstefano_zampini       usedmat = nest[j][i];
10079e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100828b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10099e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10109e7b2b25Sstefano_zampini         Mat T;
10119566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10129e7b2b25Sstefano_zampini         usedmat = T;
10139e7b2b25Sstefano_zampini       }
1014f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10159566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10169e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10179566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10189566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10199e7b2b25Sstefano_zampini       } else {
10209566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10219566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10229e7b2b25Sstefano_zampini       }
10239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10245e3038f0Sstefano_zampini       stl += lc[i];
10255e3038f0Sstefano_zampini     }
10269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10275e3038f0Sstefano_zampini 
10285e3038f0Sstefano_zampini     /* Create MATIS */
10299566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10309566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10319566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10329566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10339566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10349566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10354f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
10368546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1037f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
10388546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10398546b261SStefano Zampini     }
10409566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10419566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10439566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10449566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10459e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
104648a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10479e7b2b25Sstefano_zampini     }
10489566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10499566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10508546b261SStefano Zampini     { /* hack : setup of scatters done here */
1051f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10528546b261SStefano Zampini 
10538546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10549566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10558546b261SStefano Zampini     }
10569566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10579566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10585e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10599566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10605e3038f0Sstefano_zampini     } else {
10615e3038f0Sstefano_zampini       *newmat = B;
10625e3038f0Sstefano_zampini     }
10635e3038f0Sstefano_zampini   } else {
10645e3038f0Sstefano_zampini     if (lreuse) {
10659566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10665e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10675e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10685e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10699566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
107048a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10715e3038f0Sstefano_zampini           }
10725e3038f0Sstefano_zampini         }
10735e3038f0Sstefano_zampini       }
10745e3038f0Sstefano_zampini     } else {
10755b003df0Sstefano_zampini       PetscInt stl;
10765b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10779566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10785b003df0Sstefano_zampini         stl += lr[i];
10795e3038f0Sstefano_zampini       }
10805b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10819566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10825b003df0Sstefano_zampini         stl += lc[i];
10835e3038f0Sstefano_zampini       }
10849566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1085ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
108648a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1087ab4d48faSStefano Zampini       }
10889566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10899566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10905e3038f0Sstefano_zampini     }
10919566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10929566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10935e3038f0Sstefano_zampini   }
10945e3038f0Sstefano_zampini 
10955b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10965b003df0Sstefano_zampini   convert = PETSC_FALSE;
10974f58015eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
10985b003df0Sstefano_zampini   if (convert) {
10995b003df0Sstefano_zampini     Mat              M;
11005b003df0Sstefano_zampini     MatISLocalFields lf;
11015b003df0Sstefano_zampini     PetscContainer   c;
11025b003df0Sstefano_zampini 
11039566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
11049566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
11059566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
11069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
11075b003df0Sstefano_zampini 
11085b003df0Sstefano_zampini     /* attach local fields to the matrix */
11099566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11115b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11125b003df0Sstefano_zampini       PetscInt n, st;
11135b003df0Sstefano_zampini 
11149566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11159566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11169566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11175b003df0Sstefano_zampini     }
11185b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11195b003df0Sstefano_zampini       PetscInt n, st;
11205b003df0Sstefano_zampini 
11219566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11229566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11239566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11245b003df0Sstefano_zampini     }
11255b003df0Sstefano_zampini     lf->nr = nr;
11265b003df0Sstefano_zampini     lf->nc = nc;
1127f4f49eeaSPierre Jolivet     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)*newmat), &c));
11289566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, lf));
11299566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyFields_Private));
1130f4f49eeaSPierre Jolivet     PetscCall(PetscObjectCompose((PetscObject)*newmat, "_convert_nest_lfields", (PetscObject)c));
11319566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
11325b003df0Sstefano_zampini   }
11335b003df0Sstefano_zampini 
11345e3038f0Sstefano_zampini   /* Free workspace */
113548a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
113648a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11379566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11389566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11405e3038f0Sstefano_zampini }
11415e3038f0Sstefano_zampini 
1142d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1143d71ae5a4SJacob Faibussowitsch {
1144ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1145ad219c80Sstefano_zampini   Vec                ll, rr;
1146ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1147ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1148ad219c80Sstefano_zampini 
1149ad219c80Sstefano_zampini   PetscFunctionBegin;
1150ad219c80Sstefano_zampini   if (l) {
1151ad219c80Sstefano_zampini     ll = matis->y;
11529566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11539566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11549566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1155ad219c80Sstefano_zampini   } else {
1156ad219c80Sstefano_zampini     ll = NULL;
1157ad219c80Sstefano_zampini   }
1158ad219c80Sstefano_zampini   if (r) {
1159ad219c80Sstefano_zampini     rr = matis->x;
11609566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11619566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11629566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1163ad219c80Sstefano_zampini   } else {
1164ad219c80Sstefano_zampini     rr = NULL;
1165ad219c80Sstefano_zampini   }
1166ad219c80Sstefano_zampini   if (ll) {
11679566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11699566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1170ad219c80Sstefano_zampini   }
1171ad219c80Sstefano_zampini   if (rr) {
11729566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11739566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11749566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1175ad219c80Sstefano_zampini   }
11769566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1178ad219c80Sstefano_zampini }
1179ad219c80Sstefano_zampini 
1180d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1181d71ae5a4SJacob Faibussowitsch {
11827fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11837fa8f2d3SStefano Zampini   MatInfo        info;
11843966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11857fa8f2d3SStefano Zampini   PetscInt       bs;
11867fa8f2d3SStefano Zampini 
11877fa8f2d3SStefano Zampini   PetscFunctionBegin;
11889566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1189a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11909566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11917fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11927fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11937fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11947fa8f2d3SStefano Zampini     isend[3] = info.memory;
11957fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1196a2ccb5f9Sstefano_zampini   } else {
1197a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1198a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1199a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1200a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1201a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1202a2ccb5f9Sstefano_zampini   }
1203314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
12047fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
12057fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
12067fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
12077fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
12087fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
12097fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1210314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
12117fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
12121c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12137fa8f2d3SStefano Zampini 
12147fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12157fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12167fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12177fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12187fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1219314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12207fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
12211c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12227fa8f2d3SStefano Zampini 
12237fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12247fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12257fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12267fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12277fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12287fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12297fa8f2d3SStefano Zampini   }
12307fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12317fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12327fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12337fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12355e3038f0Sstefano_zampini }
12365e3038f0Sstefano_zampini 
1237d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1238d71ae5a4SJacob Faibussowitsch {
1239d7f69cd0SStefano Zampini   Mat C, lC, lA;
1240d7f69cd0SStefano Zampini 
1241d7f69cd0SStefano Zampini   PetscFunctionBegin;
12427fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1243cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1244cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12454f58015eSStefano Zampini     PetscBool              allow_repeated;
12464f58015eSStefano Zampini 
12479566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12489566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
12499566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
12509566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12514f58015eSStefano Zampini     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
12524f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
12539566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12549566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1255e432b41dSStefano Zampini   } else C = *B;
1256d7f69cd0SStefano Zampini 
1257d7f69cd0SStefano Zampini   /* perform local transposition */
12589566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12599566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12609566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12619566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12629566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1263d7f69cd0SStefano Zampini 
1264cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1265d7f69cd0SStefano Zampini     *B = C;
1266d7f69cd0SStefano Zampini   } else {
12679566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1268d7f69cd0SStefano Zampini   }
12699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1272d7f69cd0SStefano Zampini }
1273d7f69cd0SStefano Zampini 
1274d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1275d71ae5a4SJacob Faibussowitsch {
12763fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12773fd1c9e7SStefano Zampini 
12783fd1c9e7SStefano Zampini   PetscFunctionBegin;
12794f58015eSStefano Zampini   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
12804b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12819566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12829566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12833fd1c9e7SStefano Zampini   }
12849566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12859566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12873fd1c9e7SStefano Zampini }
12883fd1c9e7SStefano Zampini 
1289d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1290d71ae5a4SJacob Faibussowitsch {
12914b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12923fd1c9e7SStefano Zampini 
12933fd1c9e7SStefano Zampini   PetscFunctionBegin;
12949566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12959566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12973fd1c9e7SStefano Zampini }
12983fd1c9e7SStefano Zampini 
1299d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_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 indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
13059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
13069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
13079566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1309f26d0771SStefano Zampini }
1310f26d0771SStefano Zampini 
1311d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1312d71ae5a4SJacob Faibussowitsch {
1313f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1314f26d0771SStefano Zampini 
1315f26d0771SStefano Zampini   PetscFunctionBegin;
1316aed4548fSBarry 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);
13179566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13199566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1321f26d0771SStefano Zampini }
1322f26d0771SStefano Zampini 
1323d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1324d71ae5a4SJacob Faibussowitsch {
1325a8116848SStefano Zampini   Mat             locmat, newlocmat;
1326a8116848SStefano Zampini   Mat_IS         *newmatis;
1327a8116848SStefano Zampini   const PetscInt *idxs;
1328a8116848SStefano Zampini   PetscInt        i, m, n;
1329a8116848SStefano Zampini 
1330a8116848SStefano Zampini   PetscFunctionBegin;
1331a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1332a8116848SStefano Zampini     PetscBool ismatis;
1333a8116848SStefano Zampini 
13349566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
133528b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1336a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
133728b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
133828b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1339a8116848SStefano Zampini   }
1340a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
134176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
134276bd3646SJed Brown     Vec                rtest, ltest;
134376bd3646SJed Brown     const PetscScalar *array;
134476bd3646SJed Brown 
13459566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13469566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13479566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
134848a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13519566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13529566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13539566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1354aed4548fSBarry 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]));
13559566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13569566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13579566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13589566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
135948a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13609566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13619566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13629566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13639566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13649566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1365aed4548fSBarry 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]));
13669566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13679566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13689566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
137076bd3646SJed Brown   }
1371a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1372a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1373a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1374a8116848SStefano Zampini     IS                     is;
1375a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1376306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
137794342113SStefano Zampini     PetscBool              cong;
1378a8116848SStefano Zampini     MPI_Comm               comm;
1379a8116848SStefano Zampini 
13809566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13819566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13829566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13839566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1384306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1385306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13869566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13889566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13899566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13904f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
13919566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13929566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1393a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13949566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13959566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13969566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13979566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1398a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13999566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
14009566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
14019566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14029566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14039371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
14049371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
14059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
14069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
14073d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1408a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1409a8116848SStefano Zampini         lidxs[newloc]      = i;
1410a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1411a8116848SStefano Zampini       }
14129566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1416a8116848SStefano Zampini     /* local is to extract local submatrix */
1417a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14189566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14199566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
142094342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14219566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14229566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1423a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1424a8116848SStefano Zampini     } else {
1425a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1426a8116848SStefano Zampini 
1427a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14289566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14299566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14309566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14319566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1432a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14339566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14349566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14359566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14369566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14379371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14389371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14409566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14413d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1442a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1443a8116848SStefano Zampini           lidxs[newloc]      = i;
1444a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1445a8116848SStefano Zampini         }
14469566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14479566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14499566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1450a8116848SStefano Zampini       /* local is to extract local submatrix */
14519566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14529566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14539566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1454a8116848SStefano Zampini     }
14559566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1456a8116848SStefano Zampini   } else {
14579566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1458a8116848SStefano Zampini   }
14599566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1460a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14619566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1462a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14639566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1465a8116848SStefano Zampini   }
14669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14679566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1469a8116848SStefano Zampini }
1470a8116848SStefano Zampini 
1471d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1472d71ae5a4SJacob Faibussowitsch {
14732b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14742b404112SStefano Zampini   PetscBool ismatis;
14752b404112SStefano Zampini 
14762b404112SStefano Zampini   PetscFunctionBegin;
14779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
147828b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14792b404112SStefano Zampini   b = (Mat_IS *)B->data;
14809566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14819566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14832b404112SStefano Zampini }
14842b404112SStefano Zampini 
1485d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1486d71ae5a4SJacob Faibussowitsch {
1487527b2640SStefano Zampini   Vec                v;
1488527b2640SStefano Zampini   const PetscScalar *array;
1489527b2640SStefano Zampini   PetscInt           i, n;
14906bd84002SStefano Zampini 
14916bd84002SStefano Zampini   PetscFunctionBegin;
1492527b2640SStefano Zampini   *missing = PETSC_FALSE;
14939566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14949566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14959566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14969566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14979371c9d4SSatish Balay   for (i = 0; i < n; i++)
14989371c9d4SSatish Balay     if (array[i] == 0.) break;
14999566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
15009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1501527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1502527b2640SStefano Zampini   if (d) {
1503527b2640SStefano Zampini     *d = -1;
1504527b2640SStefano Zampini     if (*missing) {
1505527b2640SStefano Zampini       PetscInt rstart;
15069566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1507527b2640SStefano Zampini       *d = i + rstart;
1508527b2640SStefano Zampini     }
1509527b2640SStefano Zampini   }
15103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15116bd84002SStefano Zampini }
15126bd84002SStefano Zampini 
1513d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1514d71ae5a4SJacob Faibussowitsch {
1515f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
151628f4e0baSStefano Zampini   const PetscInt *gidxs;
15174f2d7cafSStefano Zampini   PetscInt        nleaves;
151828f4e0baSStefano Zampini 
151928f4e0baSStefano Zampini   PetscFunctionBegin;
15203ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15219566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15249566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1527e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15299566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15309566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15319566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1534a8116848SStefano Zampini   } else {
1535a8116848SStefano Zampini     matis->csf          = matis->sf;
1536a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1537a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1538a8116848SStefano Zampini   }
15393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154028f4e0baSStefano Zampini }
15412e1947a5SStefano Zampini 
1542eb82efa4SStefano Zampini /*@
15434f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15444f58015eSStefano Zampini 
15454f58015eSStefano Zampini   Not Collective
15464f58015eSStefano Zampini 
15474f58015eSStefano Zampini   Input Parameter:
15484f58015eSStefano Zampini . A - the matrix
15494f58015eSStefano Zampini 
15504f58015eSStefano Zampini   Output Parameter:
15514f58015eSStefano Zampini . flg - the boolean flag
15524f58015eSStefano Zampini 
15534f58015eSStefano Zampini   Level: intermediate
15544f58015eSStefano Zampini 
15554f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
15564f58015eSStefano Zampini @*/
15574f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
15584f58015eSStefano Zampini {
15594f58015eSStefano Zampini   PetscBool ismatis;
15604f58015eSStefano Zampini 
15614f58015eSStefano Zampini   PetscFunctionBegin;
15624f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15634f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
15644f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
15654f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
15664f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
15674f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15684f58015eSStefano Zampini }
15694f58015eSStefano Zampini 
15704f58015eSStefano Zampini /*@
15714f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
15724f58015eSStefano Zampini 
15734f58015eSStefano Zampini   Logically Collective
15744f58015eSStefano Zampini 
15754f58015eSStefano Zampini   Input Parameters:
15764f58015eSStefano Zampini + A   - the matrix
15774f58015eSStefano Zampini - flg - the boolean flag
15784f58015eSStefano Zampini 
15794f58015eSStefano Zampini   Level: intermediate
15804f58015eSStefano Zampini 
15814f58015eSStefano Zampini   Notes:
15824f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
15834f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
15844f58015eSStefano Zampini   if `flg` is different from the previously set value.
15854f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
15864f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
15874f58015eSStefano Zampini 
15884f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
15894f58015eSStefano Zampini @*/
15904f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
15914f58015eSStefano Zampini {
15924f58015eSStefano Zampini   PetscFunctionBegin;
15934f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15944f58015eSStefano Zampini   PetscValidType(A, 1);
15954f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
15964f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
15974f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15984f58015eSStefano Zampini }
15994f58015eSStefano Zampini 
16004f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
16014f58015eSStefano Zampini {
16024f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
16034f58015eSStefano Zampini   Mat                    lA    = NULL;
16044f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
16054f58015eSStefano Zampini 
16064f58015eSStefano Zampini   PetscFunctionBegin;
16074f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
16084f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
16094f58015eSStefano Zampini     matis->allow_repeated = flg;
16104f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
16114f58015eSStefano Zampini   }
16124f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16134f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16144f58015eSStefano Zampini     lA = matis->A;
16154f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16164f58015eSStefano Zampini   }
16174f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16184f58015eSStefano Zampini   matis->allow_repeated = flg;
16194f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16204f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16214f58015eSStefano Zampini     Mat nA = matis->A;
16224f58015eSStefano Zampini 
16234f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16244f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16254f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16264f58015eSStefano Zampini     } else {
16274f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16284f58015eSStefano Zampini       MatProductType ptype;
16294f58015eSStefano Zampini 
16304f58015eSStefano Zampini       if (lrmap == lcmap) {
16314f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16324f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16334f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16344f58015eSStefano Zampini       } else {
16354f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16364f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16374f58015eSStefano Zampini         if (R && P) {
16384f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16394f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16404f58015eSStefano Zampini         } else if (R) {
16414f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16424f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16434f58015eSStefano Zampini         } else {
16444f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16454f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16464f58015eSStefano Zampini         }
16474f58015eSStefano Zampini       }
16484f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16494f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16504f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16514f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16524f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16534f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16544f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16554f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
16564f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
16574f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
16584f58015eSStefano Zampini     }
16594f58015eSStefano Zampini   }
16604f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
16614f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16624f58015eSStefano Zampini }
16634f58015eSStefano Zampini 
16644f58015eSStefano Zampini /*@
16652ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
166675d48cdbSStefano Zampini 
16674f58015eSStefano Zampini   Logically Collective
166875d48cdbSStefano Zampini 
166975d48cdbSStefano Zampini   Input Parameters:
167075d48cdbSStefano Zampini + A     - the matrix
167175d48cdbSStefano Zampini - store - the boolean flag
167275d48cdbSStefano Zampini 
167375d48cdbSStefano Zampini   Level: advanced
167475d48cdbSStefano Zampini 
16751cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
167675d48cdbSStefano Zampini @*/
1677d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1678d71ae5a4SJacob Faibussowitsch {
167975d48cdbSStefano Zampini   PetscFunctionBegin;
168075d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
168175d48cdbSStefano Zampini   PetscValidType(A, 1);
168275d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1683cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
16843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168575d48cdbSStefano Zampini }
168675d48cdbSStefano Zampini 
1687d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1688d71ae5a4SJacob Faibussowitsch {
1689f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
169075d48cdbSStefano Zampini 
169175d48cdbSStefano Zampini   PetscFunctionBegin;
169275d48cdbSStefano Zampini   matis->storel2l = store;
169348a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
16943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
169575d48cdbSStefano Zampini }
169675d48cdbSStefano Zampini 
169775d48cdbSStefano Zampini /*@
1698f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1699f03112d0SStefano Zampini 
17004f58015eSStefano Zampini   Logically Collective
1701f03112d0SStefano Zampini 
1702f03112d0SStefano Zampini   Input Parameters:
1703f03112d0SStefano Zampini + A   - the matrix
1704f03112d0SStefano Zampini - fix - the boolean flag
1705f03112d0SStefano Zampini 
1706f03112d0SStefano Zampini   Level: advanced
1707f03112d0SStefano Zampini 
170811a5261eSBarry Smith   Note:
17092fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1710f03112d0SStefano Zampini 
17111cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1712f03112d0SStefano Zampini @*/
1713d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1714d71ae5a4SJacob Faibussowitsch {
1715f03112d0SStefano Zampini   PetscFunctionBegin;
1716f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1717f03112d0SStefano Zampini   PetscValidType(A, 1);
1718f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1719cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1721f03112d0SStefano Zampini }
1722f03112d0SStefano Zampini 
1723d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1724d71ae5a4SJacob Faibussowitsch {
1725f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1726f03112d0SStefano Zampini 
1727f03112d0SStefano Zampini   PetscFunctionBegin;
1728f03112d0SStefano Zampini   matis->locempty = fix;
17293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1730f03112d0SStefano Zampini }
1731f03112d0SStefano Zampini 
1732f03112d0SStefano Zampini /*@
173311a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1734a88811baSStefano Zampini 
1735d083f849SBarry Smith   Collective
1736a88811baSStefano Zampini 
1737a88811baSStefano Zampini   Input Parameters:
1738a88811baSStefano Zampini + B     - the matrix
1739a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1740a88811baSStefano Zampini            (same value is used for all local rows)
1741a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1742a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17432ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17442ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1745a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1746a88811baSStefano Zampini            the diagonal entry even if it is zero.
1747a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1748a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1749a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1750a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17512ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1752a88811baSStefano Zampini            structure. The size of this array is equal to the number
17532ef1f0ffSBarry Smith            of local rows, i.e `m`.
1754a88811baSStefano Zampini 
1755a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1756a88811baSStefano Zampini 
1757a88811baSStefano Zampini   Level: intermediate
1758a88811baSStefano Zampini 
175911a5261eSBarry Smith   Note:
176011a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
176111a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1762a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1763a88811baSStefano Zampini 
17641cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1765a88811baSStefano Zampini @*/
1766d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1767d71ae5a4SJacob Faibussowitsch {
17682e1947a5SStefano Zampini   PetscFunctionBegin;
17692e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
17702e1947a5SStefano Zampini   PetscValidType(B, 1);
1771cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
17723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17732e1947a5SStefano Zampini }
17742e1947a5SStefano Zampini 
1775844bd0d7SStefano Zampini /* this is used by DMDA */
1776d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1777d71ae5a4SJacob Faibussowitsch {
1778f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
177928f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
17802e1947a5SStefano Zampini 
17812e1947a5SStefano Zampini   PetscFunctionBegin;
17829566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
17839371c9d4SSatish Balay   if (!d_nnz)
17849371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
17859371c9d4SSatish Balay   else
17869371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
17874f2d7cafSStefano Zampini 
17889371c9d4SSatish Balay   if (!o_nnz)
17899371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
17909371c9d4SSatish Balay   else
17919371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
17924f2d7cafSStefano Zampini 
17939566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17949566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
17959566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
17969566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17974f2d7cafSStefano Zampini 
17984f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
17999566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
18000f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
18019566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
18020f2f62c7SStefano Zampini #endif
18034f2d7cafSStefano Zampini 
1804fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1805fc989267SStefano Zampini     PetscInt b;
1806fc989267SStefano Zampini 
1807fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1808ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1809fc989267SStefano Zampini   }
18109566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18114f2d7cafSStefano Zampini 
181200a59248SStefano Zampini   nlocalcols /= bs;
181300a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18149566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18150f2f62c7SStefano Zampini 
18160f2f62c7SStefano Zampini   /* for other matrix types */
18179566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18192e1947a5SStefano Zampini }
1820b4319ba4SBarry Smith 
1821d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1822d71ae5a4SJacob Faibussowitsch {
1823f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
18243927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1825ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
18263927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
18273927de2eSStefano Zampini   PetscInt        lrows, lcols;
18283927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1829f03112d0SStefano Zampini   PetscMPIInt     size;
18303927de2eSStefano Zampini   PetscBool       isdense, issbaij;
18313927de2eSStefano Zampini 
18323927de2eSStefano Zampini   PetscFunctionBegin;
18339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
18349566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
18359566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
18369566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
18379566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
18389566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
18399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1840e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
18419566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
18420dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1843ecf5a873SStefano Zampini 
18449566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
18453927de2eSStefano Zampini   /*
1846ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
18473927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
18483927de2eSStefano Zampini   */
18499566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1850d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
18513927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
18529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
18539566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1854f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
18555f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
18563927de2eSStefano Zampini   }
18579566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
18583927de2eSStefano Zampini 
18593927de2eSStefano Zampini   /*
18603927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
18613927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
18623927de2eSStefano Zampini   */
18639566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
18643927de2eSStefano Zampini   /* preallocation as a MATAIJ */
18653927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
18663927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
186712dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
186812dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1869ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
18703927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
18713927de2eSStefano Zampini           my_dnz[i] += 1;
18723927de2eSStefano Zampini         } else { /* offdiag block */
18733927de2eSStefano Zampini           my_onz[i] += 1;
18743927de2eSStefano Zampini         }
18753927de2eSStefano Zampini       }
18763927de2eSStefano Zampini     }
1877bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1878bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1879bb1015c3SStefano Zampini     PetscBool       done;
18809566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1881f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1882bb1015c3SStefano Zampini     jptr = jj;
1883bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1884bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1885bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1886bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1887bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1888bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1889bb1015c3SStefano Zampini           my_dnz[i] += 1;
1890bb1015c3SStefano Zampini         } else { /* offdiag block */
1891bb1015c3SStefano Zampini           my_onz[i] += 1;
1892bb1015c3SStefano Zampini         }
1893bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1894bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1895bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1896bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1897bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1898bb1015c3SStefano Zampini           } else {
1899bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1900bb1015c3SStefano Zampini           }
1901bb1015c3SStefano Zampini         }
1902bb1015c3SStefano Zampini       }
1903bb1015c3SStefano Zampini     }
19049566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1905f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1906bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
19073927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
19083927de2eSStefano Zampini       const PetscInt *cols;
1909ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
19109566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
19113927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
19123927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1913ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
19143927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
19153927de2eSStefano Zampini           my_dnz[i] += 1;
19163927de2eSStefano Zampini         } else { /* offdiag block */
19173927de2eSStefano Zampini           my_onz[i] += 1;
19183927de2eSStefano Zampini         }
19193927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1920d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
19213927de2eSStefano Zampini           owner = row_ownership[index_col];
19223927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1923d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
19243927de2eSStefano Zampini           } else {
1925d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
19263927de2eSStefano Zampini           }
19273927de2eSStefano Zampini         }
19283927de2eSStefano Zampini       }
19299566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
19303927de2eSStefano Zampini     }
19313927de2eSStefano Zampini   }
193248a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
19339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
19349566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1935ecf5a873SStefano Zampini 
1936ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
19373927de2eSStefano Zampini   if (maxreduce) {
19389566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19399566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19409566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19419566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19423927de2eSStefano Zampini   } else {
19439566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19449566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19459566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19469566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19473927de2eSStefano Zampini   }
19489566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
19493927de2eSStefano Zampini 
19503927de2eSStefano Zampini   /* Resize preallocation if overestimated */
19513927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
19523927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
19533927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
19543927de2eSStefano Zampini   }
19551670daf9Sstefano_zampini 
19561670daf9Sstefano_zampini   /* Set preallocation */
19579566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
19589566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
19599566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
196053b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
196153b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
196253b44cf5SStefano Zampini 
196353b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
196453b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
196553b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
196653b44cf5SStefano Zampini     }
196753b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
196853b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
19693927de2eSStefano Zampini   }
19709566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
19719566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
19729566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1973d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
19749566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
19759566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
19763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19773927de2eSStefano Zampini }
19783927de2eSStefano Zampini 
1979d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1980d71ae5a4SJacob Faibussowitsch {
1981f4f49eeaSPierre Jolivet   Mat_IS            *matis = (Mat_IS *)mat->data;
1982487b449aSStefano Zampini   Mat                local_mat, MT;
198353b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1984b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1985b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1986f03112d0SStefano Zampini   PetscMPIInt        size;
19871683a169SBarry Smith   const PetscScalar *array;
1988b7ce53b6SStefano Zampini 
1989b7ce53b6SStefano Zampini   PetscFunctionBegin;
19909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
19914f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
19921670daf9Sstefano_zampini     Mat      B;
199353b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1994487b449aSStefano Zampini     PetscInt rbs, cbs;
19951670daf9Sstefano_zampini 
19969566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19979566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
199853b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
199953b44cf5SStefano Zampini       IS              rows, cols;
200053b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
20014f58015eSStefano Zampini       PetscInt        i, nw;
20024f58015eSStefano Zampini       PetscBT         work;
200353b44cf5SStefano Zampini 
20049566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
20059566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
200653b44cf5SStefano Zampini       nw = nw / rbs;
20074f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
20084f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
20099371c9d4SSatish Balay       for (i = 0; i < nw; i++)
20104f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
201153b44cf5SStefano Zampini       if (i == nw) {
20129566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
20139566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
20149566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
20159566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
201653b44cf5SStefano Zampini       }
20179566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
20184f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
2019e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
20209566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
20219566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
202253b44cf5SStefano Zampini         nw = nw / cbs;
20234f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
20244f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
20259371c9d4SSatish Balay         for (i = 0; i < nw; i++)
20264f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
202753b44cf5SStefano Zampini         if (i == nw) {
20289566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
20299566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
20309566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
20319566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
203253b44cf5SStefano Zampini         }
20339566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
20344f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
203553b44cf5SStefano Zampini       } else if (irows) {
20369566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
203753b44cf5SStefano Zampini         icols = irows;
203853b44cf5SStefano Zampini       }
203953b44cf5SStefano Zampini     } else {
2040f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
2041f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
20429566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
20439566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
204453b44cf5SStefano Zampini     }
204553b44cf5SStefano Zampini     if (!irows || !icols) {
20469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
20479566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
204853b44cf5SStefano Zampini       goto general_assembly;
204953b44cf5SStefano Zampini     }
20509566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
2051487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
20529566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
2053f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
2054f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
2055487b449aSStefano Zampini     } else {
2056487b449aSStefano Zampini       Mat C;
2057487b449aSStefano Zampini 
20589566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
20599566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
2060487b449aSStefano Zampini     }
20619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
20629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
20639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
20643ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20657c03b4e8SStefano Zampini   }
206653b44cf5SStefano Zampini general_assembly:
20679566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
20689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
20699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
20709566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
20719566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
20729566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
20739566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
20749566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
20759566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
2076f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
207776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
207876bd3646SJed Brown     PetscBool lb[4], bb[4];
207976bd3646SJed Brown 
2080b9ed4604SStefano Zampini     lb[0] = isseqdense;
2081b9ed4604SStefano Zampini     lb[1] = isseqaij;
2082b9ed4604SStefano Zampini     lb[2] = isseqbaij;
2083b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
20841c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
2085aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
208676bd3646SJed Brown   }
2087b7ce53b6SStefano Zampini 
2088487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
20899566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
20909566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
20919566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
20929566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
20939566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
2094b7ce53b6SStefano Zampini   } else {
209553b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
2096487b449aSStefano Zampini 
2097b7ce53b6SStefano Zampini     /* some checks */
2098487b449aSStefano Zampini     MT = *M;
20999566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
21009566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
21019566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
210208401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
210308401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
210408401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
210508401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
210608401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
210708401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
21089566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
2109b7ce53b6SStefano Zampini   }
2110d9a9e74cSStefano Zampini 
21118546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
21129566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
21138546b261SStefano Zampini     isseqaij = PETSC_TRUE;
2114d9a9e74cSStefano Zampini   } else {
21159566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
2116d9a9e74cSStefano Zampini     local_mat = matis->A;
2117d9a9e74cSStefano Zampini   }
2118686e3a49SStefano Zampini 
2119b7ce53b6SStefano Zampini   /* Set values */
21209566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
2121b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
212265066ba5SStefano Zampini     PetscInt i, *dummy;
2123ecf5a873SStefano Zampini 
21249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
212565066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
21269566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
21279566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
21289566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
21299566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
21309566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
2131686e3a49SStefano Zampini   } else if (isseqaij) {
21326afe12f5SStefano Zampini     const PetscInt *blocks;
21336afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
2134686e3a49SStefano Zampini     PetscBool       done;
21351683a169SBarry Smith     PetscScalar    *sarray;
2136686e3a49SStefano Zampini 
21379566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
213828b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
21399566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
21409566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
21416afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
21426afe12f5SStefano Zampini       PetscInt sum;
21436afe12f5SStefano Zampini 
21446afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
21456afe12f5SStefano Zampini       if (sum == nvtxs) {
21466afe12f5SStefano Zampini         PetscInt r;
21476afe12f5SStefano Zampini 
21486afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
21496bdcaf15SBarry 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]);
21509566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
21516afe12f5SStefano Zampini           r += blocks[i];
21526afe12f5SStefano Zampini         }
21536afe12f5SStefano Zampini       } else {
215448a46eb9SPierre 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));
21556afe12f5SStefano Zampini       }
21566afe12f5SStefano Zampini     } else {
21578e3a54c0SPierre 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));
21586afe12f5SStefano Zampini     }
21599566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
216028b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
21619566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2162686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
21634f58015eSStefano Zampini     for (PetscInt i = 0; i < local_rows; i++) {
2164686e3a49SStefano Zampini       PetscInt        j;
2165ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2166686e3a49SStefano Zampini 
21679566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
21689566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
21699566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2170686e3a49SStefano Zampini     }
2171b7ce53b6SStefano Zampini   }
21729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
21734f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
21749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
21751baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2176487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
21779566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2178487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2179487b449aSStefano Zampini     *M = MT;
2180b7ce53b6SStefano Zampini   }
21813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2182b7ce53b6SStefano Zampini }
2183b7ce53b6SStefano Zampini 
2184d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2185d71ae5a4SJacob Faibussowitsch {
2186f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2187c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2188ad6194a2SStefano Zampini   Mat      B, localmat;
2189ad6194a2SStefano Zampini 
2190ad6194a2SStefano Zampini   PetscFunctionBegin;
21919566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
21929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
21939566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
21949566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
21959566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
21969566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
21979566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
21989566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
21999566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
22004f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
22019566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
22029566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
22039566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
22049566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
22059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
22069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
22079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2208ad6194a2SStefano Zampini   *newmat = B;
22093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2210ad6194a2SStefano Zampini }
2211ad6194a2SStefano Zampini 
2212d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2213d71ae5a4SJacob Faibussowitsch {
221469796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
221569796d55SStefano Zampini   PetscBool local_sym;
221669796d55SStefano Zampini 
221769796d55SStefano Zampini   PetscFunctionBegin;
22189566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
22191c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
222169796d55SStefano Zampini }
222269796d55SStefano Zampini 
2223d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2224d71ae5a4SJacob Faibussowitsch {
222569796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
222669796d55SStefano Zampini   PetscBool local_sym;
222769796d55SStefano Zampini 
222869796d55SStefano Zampini   PetscFunctionBegin;
2229e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2230e432b41dSStefano Zampini     *flg = PETSC_FALSE;
22313ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2232e432b41dSStefano Zampini   }
22339566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
22341c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
223669796d55SStefano Zampini }
223769796d55SStefano Zampini 
2238d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2239d71ae5a4SJacob Faibussowitsch {
224045471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
224145471136SStefano Zampini   PetscBool local_sym;
224245471136SStefano Zampini 
224345471136SStefano Zampini   PetscFunctionBegin;
2244e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
224545471136SStefano Zampini     *flg = PETSC_FALSE;
22463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
224745471136SStefano Zampini   }
22489566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
22491c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225145471136SStefano Zampini }
225245471136SStefano Zampini 
2253d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2254d71ae5a4SJacob Faibussowitsch {
2255b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2256b4319ba4SBarry Smith 
2257b4319ba4SBarry Smith   PetscFunctionBegin;
22589566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
22599566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
22609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
22619566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
22629566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
22639566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
22649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
22659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
22669566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
22679566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2268a8116848SStefano Zampini   if (b->sf != b->csf) {
22699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
22709566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2271f03112d0SStefano Zampini   } else b->csf = NULL;
22729566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
22739566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
22749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
22759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2276d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2277d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
22789566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
22799566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
22809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
22829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
22832e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
22849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
22859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
22869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
22879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
22889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
22899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
22909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
22919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
22929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
22939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
22949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
22959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
22969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
22979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
22984f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
22993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2300b4319ba4SBarry Smith }
2301b4319ba4SBarry Smith 
2302d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2303d71ae5a4SJacob Faibussowitsch {
2304b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2305b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2306b4319ba4SBarry Smith 
2307b4319ba4SBarry Smith   PetscFunctionBegin;
2308b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
23099566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
23109566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2311b4319ba4SBarry Smith 
2312b4319ba4SBarry Smith   /* multiply the local matrix */
23139566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2314b4319ba4SBarry Smith 
2315b4319ba4SBarry Smith   /* scatter product back into global memory */
23169566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
23179566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23189566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2320b4319ba4SBarry Smith }
2321b4319ba4SBarry Smith 
2322d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2323d71ae5a4SJacob Faibussowitsch {
2324650997f4SStefano Zampini   Vec temp_vec;
23252e74eeadSLisandro Dalcin 
23262e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2327650997f4SStefano Zampini   if (v3 != v2) {
23289566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
23299566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2330650997f4SStefano Zampini   } else {
23319566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23329566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
23339566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23349566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2336650997f4SStefano Zampini   }
23373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23382e74eeadSLisandro Dalcin }
23392e74eeadSLisandro Dalcin 
2340d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2341d71ae5a4SJacob Faibussowitsch {
23422e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
23432e74eeadSLisandro Dalcin 
2344e176bc59SStefano Zampini   PetscFunctionBegin;
23452e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
23469566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23479566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23482e74eeadSLisandro Dalcin 
23492e74eeadSLisandro Dalcin   /* multiply the local matrix */
23509566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
23512e74eeadSLisandro Dalcin 
23522e74eeadSLisandro Dalcin   /* scatter product back into global vector */
23539566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
23549566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23559566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23572e74eeadSLisandro Dalcin }
23582e74eeadSLisandro Dalcin 
2359d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2360d71ae5a4SJacob Faibussowitsch {
2361650997f4SStefano Zampini   Vec temp_vec;
23622e74eeadSLisandro Dalcin 
23632e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2364650997f4SStefano Zampini   if (v3 != v2) {
23659566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
23669566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2367650997f4SStefano Zampini   } else {
23689566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23699566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
23709566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23719566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2373650997f4SStefano Zampini   }
23743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23752e74eeadSLisandro Dalcin }
23762e74eeadSLisandro Dalcin 
2377d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2378d71ae5a4SJacob Faibussowitsch {
2379b4319ba4SBarry Smith   Mat_IS     *a = (Mat_IS *)A->data;
2380b4319ba4SBarry Smith   PetscViewer sviewer;
2381ee2491ecSStefano Zampini   PetscBool   isascii, view = PETSC_TRUE;
2382b4319ba4SBarry Smith 
2383b4319ba4SBarry Smith   PetscFunctionBegin;
23849566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2385ee2491ecSStefano Zampini   if (isascii) {
2386ee2491ecSStefano Zampini     PetscViewerFormat format;
2387ee2491ecSStefano Zampini 
23889566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
2389ee2491ecSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2390ee2491ecSStefano Zampini   }
23913ba16761SJacob Faibussowitsch   if (!view) PetscFunctionReturn(PETSC_SUCCESS);
23929566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23939566063dSJacob Faibussowitsch   PetscCall(MatView(a->A, sviewer));
23949566063dSJacob Faibussowitsch   PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2396b4319ba4SBarry Smith }
2397b4319ba4SBarry Smith 
2398d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2399d71ae5a4SJacob Faibussowitsch {
2400b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2401b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2402b89f26deSStefano Zampini   const PetscScalar *lv;
2403b89f26deSStefano Zampini   PetscInt           bs;
2404b89f26deSStefano Zampini 
2405b89f26deSStefano Zampini   PetscFunctionBegin;
24069566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
24079566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
24089566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
240948a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
24109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(bs, MPIU_SCALAR, &nodeType));
24119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24129566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
24139566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
24149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2415b89f26deSStefano Zampini   if (values) *values = is->bdiag;
24163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2417b89f26deSStefano Zampini }
2418b89f26deSStefano Zampini 
2419d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2420d71ae5a4SJacob Faibussowitsch {
2421e176bc59SStefano Zampini   Vec             cglobal, rglobal;
24228546b261SStefano Zampini   IS              from;
24238546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2424b89f26deSStefano Zampini   PetscScalar     sum;
24258546b261SStefano Zampini   const PetscInt *garray;
24268546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2427e432b41dSStefano Zampini   VecType         rtype;
2428b4319ba4SBarry Smith 
2429b4319ba4SBarry Smith   PetscFunctionBegin;
24309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
24319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
24329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
24339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
24349566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
24359566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
24369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
24379566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
24389566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
24399566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
24409566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
24419566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
24429566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
24439566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
24449566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
24459566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
24469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
24479566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
24489566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
24499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
24509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2451e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
24529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
24539566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
24549566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
24559566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
24569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
24578546b261SStefano Zampini   } else {
24589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
24598546b261SStefano Zampini     is->cctx = is->rctx;
24608546b261SStefano Zampini   }
24619566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2462b89f26deSStefano Zampini 
24638546b261SStefano Zampini   /* interface counter vector (local) */
24649566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
24659566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
24669566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
24679566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
24689566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
24699566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
24709566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
24719566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
24729566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2473b89f26deSStefano Zampini 
2474b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
24759566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2476b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2477e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
24789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2479b0cc1f67SStefano Zampini 
2480b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
24819566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
24823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24838546b261SStefano Zampini }
24848546b261SStefano Zampini 
2485d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2486d71ae5a4SJacob Faibussowitsch {
24874f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2488e432b41dSStefano Zampini   IS                         is;
2489e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2490e432b41dSStefano Zampini   const PetscInt            *idxs;
2491e432b41dSStefano Zampini   PetscHSetI                 ht;
2492e432b41dSStefano Zampini   PetscInt                  *nidxs;
2493e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2494e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2495e432b41dSStefano Zampini 
2496e432b41dSStefano Zampini   PetscFunctionBegin;
24979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
24989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
24999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
25009566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
25019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2502e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
25034f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
25049371c9d4SSatish Balay     if (idxs[i] < 0) {
25059371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
25069371c9d4SSatish Balay       continue;
25079371c9d4SSatish Balay     }
25084f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2509e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2510e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2511e432b41dSStefano Zampini   }
25129566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
25131c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2514e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2515e432b41dSStefano Zampini     *nmap = NULL;
2516e432b41dSStefano Zampini     *lmap = NULL;
25179566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
25189566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
25193ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2520e432b41dSStefano Zampini   }
2521e432b41dSStefano Zampini 
25224f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
25239566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
25249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
25259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
25269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
25279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2528e432b41dSStefano Zampini 
25294f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
25309566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
25319566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
25329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
25339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
25349566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
25359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
25363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2537e432b41dSStefano Zampini }
2538e432b41dSStefano Zampini 
2539d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2540d71ae5a4SJacob Faibussowitsch {
25418546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2542e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2543e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
25444f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
25458546b261SStefano Zampini 
25468546b261SStefano Zampini   PetscFunctionBegin;
2547fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2548fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2549e432b41dSStefano Zampini 
25509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
25519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
25529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
25539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
25549566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2555e432b41dSStefano Zampini 
2556fc989267SStefano Zampini   /* If NULL, local space matches global space */
2557fc989267SStefano Zampini   if (!rmapping) {
2558fc989267SStefano Zampini     IS is;
2559fc989267SStefano Zampini 
25609566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
25619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
25629566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
25639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2564e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2565e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2566e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
25679566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2568e432b41dSStefano Zampini     if (rmapping == cmapping) {
25699566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2570e432b41dSStefano Zampini       is->cmapping = is->rmapping;
25719566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2572e432b41dSStefano Zampini       localcmapping = localrmapping;
2573fc989267SStefano Zampini     }
2574fc989267SStefano Zampini   }
2575fc989267SStefano Zampini   if (!cmapping) {
2576fc989267SStefano Zampini     IS is;
2577fc989267SStefano Zampini 
25789566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
25799566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
25809566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
25819566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2582e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2583e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
25849566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2585e432b41dSStefano Zampini   }
2586e432b41dSStefano Zampini   if (!is->rmapping) {
25879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2588e432b41dSStefano Zampini     is->rmapping = rmapping;
2589e432b41dSStefano Zampini   }
2590e432b41dSStefano Zampini   if (!is->cmapping) {
25919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2592e432b41dSStefano Zampini     is->cmapping = cmapping;
2593fc989267SStefano Zampini   }
2594fc989267SStefano Zampini 
2595fc989267SStefano Zampini   /* Clean up */
25964f58015eSStefano Zampini   is->lnnzstate = 0;
25974f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
25984f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
25999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2600872cf891SStefano Zampini   if (is->csf != is->sf) {
26019566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
26029566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2603f03112d0SStefano Zampini   } else is->csf = NULL;
26049566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
26059566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
26069566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
26073bbff08aSStefano Zampini 
2608fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2609fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
26109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
26119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
26129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
26139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2614e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2615e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
26166625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
26176625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
26186625354bSStefano Zampini 
26199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
26209566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
26219566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
26229566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
26239566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
26246625354bSStefano Zampini     }
26251c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2626e432b41dSStefano Zampini     if (same) {
26279566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
26289566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2629e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2630e432b41dSStefano Zampini     }
26316625354bSStefano Zampini   }
26329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
26339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2634e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
26359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
26369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
26379566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
26389566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
26396625354bSStefano Zampini 
26406625354bSStefano Zampini   /* Create the local matrix A */
26419566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
26429566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
26439566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
26449566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
26459566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
26469566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
26479566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
26489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
26499566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
26509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
26519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2652b4319ba4SBarry Smith 
2653fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
26549566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2655fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
26563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2657fc989267SStefano Zampini }
2658fc989267SStefano Zampini 
2659d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2660d71ae5a4SJacob Faibussowitsch {
2661fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2662fc989267SStefano Zampini 
2663fc989267SStefano Zampini   PetscFunctionBegin;
26649566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
266548a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
26663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2667b4319ba4SBarry Smith }
2668b4319ba4SBarry Smith 
2669d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2670d71ae5a4SJacob Faibussowitsch {
26712e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2672f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
26732e74eeadSLisandro Dalcin 
26742e74eeadSLisandro Dalcin   PetscFunctionBegin;
26759566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2676e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
26779566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
26789566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2679e432b41dSStefano Zampini   } else {
26809566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2681e432b41dSStefano Zampini   }
26823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26832e74eeadSLisandro Dalcin }
26842e74eeadSLisandro Dalcin 
2685d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2686d71ae5a4SJacob Faibussowitsch {
268797563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2688f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
268997563a80SStefano Zampini 
269097563a80SStefano Zampini   PetscFunctionBegin;
26919566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2692e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
26939566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
26949566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2695e432b41dSStefano Zampini   } else {
26969566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, rows_l, values, addv));
2697e432b41dSStefano Zampini   }
26983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
269997563a80SStefano Zampini }
270097563a80SStefano Zampini 
2701d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2702d71ae5a4SJacob Faibussowitsch {
2703b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2704b4319ba4SBarry Smith 
2705b4319ba4SBarry Smith   PetscFunctionBegin;
2706e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
27079566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2708872cf891SStefano Zampini   } else {
27099566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2710872cf891SStefano Zampini   }
27113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2712b4319ba4SBarry Smith }
2713b4319ba4SBarry Smith 
2714d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2715d71ae5a4SJacob Faibussowitsch {
2716f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2717f0006bf2SLisandro Dalcin 
2718f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2719e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
27209566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2721b4f971dfSStefano Zampini   } else {
27229566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2723b4f971dfSStefano Zampini   }
27243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2725f0006bf2SLisandro Dalcin }
2726f0006bf2SLisandro Dalcin 
2727d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2728d71ae5a4SJacob Faibussowitsch {
2729f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2730f0ae7da4SStefano Zampini 
2731f0ae7da4SStefano Zampini   PetscFunctionBegin;
2732f0ae7da4SStefano Zampini   if (!n) {
2733f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2734f0ae7da4SStefano Zampini   } else {
2735f0ae7da4SStefano Zampini     PetscInt i;
2736f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2737f0ae7da4SStefano Zampini 
2738f0ae7da4SStefano Zampini     if (columns) {
27399566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2740f0ae7da4SStefano Zampini     } else {
27419566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2742f0ae7da4SStefano Zampini     }
2743f0ae7da4SStefano Zampini     if (diag != 0.) {
2744f0ae7da4SStefano Zampini       const PetscScalar *array;
27459566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
274648a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
27479566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2748f0ae7da4SStefano Zampini     }
27499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
27509566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2751f0ae7da4SStefano Zampini   }
27523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2753f0ae7da4SStefano Zampini }
2754f0ae7da4SStefano Zampini 
2755d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2756d71ae5a4SJacob Faibussowitsch {
27576e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
27586e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
27596e520ac8SStefano Zampini   PetscInt *lrows;
27602e74eeadSLisandro Dalcin 
27612e74eeadSLisandro Dalcin   PetscFunctionBegin;
2762cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2763f0ae7da4SStefano Zampini     PetscBool cong;
276426b0207aSStefano Zampini 
27659566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
276626b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
276708401ef6SPierre 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");
2768aed4548fSBarry 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");
2769aed4548fSBarry 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");
2770f0ae7da4SStefano Zampini   }
27716e520ac8SStefano Zampini   /* get locally owned rows */
27729566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
27736e520ac8SStefano Zampini   /* fix right hand side if needed */
27746e520ac8SStefano Zampini   if (x && b) {
27756e520ac8SStefano Zampini     const PetscScalar *xx;
27766e520ac8SStefano Zampini     PetscScalar       *bb;
27776e520ac8SStefano Zampini 
27789566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
27799566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
27806e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
27819566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
27829566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
27832e74eeadSLisandro Dalcin   }
27846e520ac8SStefano Zampini   /* get rows associated to the local matrices */
27859566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
27869566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
27879566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
27886e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
27899566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
27909566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
27919566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
27929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
27939371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
27949371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
27959566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
27969566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2797d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2798d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
27993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28002e74eeadSLisandro Dalcin }
28012e74eeadSLisandro Dalcin 
2802d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2803d71ae5a4SJacob Faibussowitsch {
2804b4319ba4SBarry Smith   PetscFunctionBegin;
28059566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
28063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2807f0ae7da4SStefano Zampini }
28082205254eSKarl Rupp 
2809d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2810d71ae5a4SJacob Faibussowitsch {
2811f0ae7da4SStefano Zampini   PetscFunctionBegin;
28129566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
28133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2814b4319ba4SBarry Smith }
2815b4319ba4SBarry Smith 
2816d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2817d71ae5a4SJacob Faibussowitsch {
2818b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2819b4319ba4SBarry Smith 
2820b4319ba4SBarry Smith   PetscFunctionBegin;
28219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
28223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2823b4319ba4SBarry Smith }
2824b4319ba4SBarry Smith 
2825d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2826d71ae5a4SJacob Faibussowitsch {
2827b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2828d0dbe9f7SStefano Zampini   PetscBool lnnz;
2829b4319ba4SBarry Smith 
2830b4319ba4SBarry Smith   PetscFunctionBegin;
28319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2832872cf891SStefano Zampini   /* fix for local empty rows/cols */
2833872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2834872cf891SStefano Zampini     Mat                    newlA;
2835f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2836f03112d0SStefano Zampini     IS                     nzr, nzc;
2837f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2838f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2839872cf891SStefano Zampini 
28409566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
28419566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
284248a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
28439566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
284448a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
28459566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
28469566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2847e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2848f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
2849712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2850f03112d0SStefano Zampini 
2851872cf891SStefano Zampini       /* extract valid submatrix */
28529566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2853f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2854f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
2855712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
28569566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2857f03112d0SStefano Zampini       newlA = is->A;
2858f03112d0SStefano Zampini     }
2859e432b41dSStefano Zampini 
2860f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2861f03112d0SStefano Zampini     if (newl2g) {
2862e432b41dSStefano Zampini       IS              zr, zc;
2863e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2864e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2865f03112d0SStefano Zampini 
28669566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
28679566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
28689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
28699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
28709566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
28719566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
28729566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
28739566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
28749566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2875e432b41dSStefano Zampini 
28769566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2877e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
28789566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
28799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2880e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
28819566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2882e432b41dSStefano Zampini 
28839566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
28849566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
28859566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
28869566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
28879566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
28889566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
28899566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
28909566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
28919566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
28929566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
28939566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
28949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2895f03112d0SStefano Zampini     }
28969566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
28979566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
28989566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
28999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2900872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2901f03112d0SStefano Zampini   }
2902d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2903d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
29044f58015eSStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
29054f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
29063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2907b4319ba4SBarry Smith }
2908b4319ba4SBarry Smith 
2909d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
2910d71ae5a4SJacob Faibussowitsch {
2911b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2912b4319ba4SBarry Smith 
2913b4319ba4SBarry Smith   PetscFunctionBegin;
2914b4319ba4SBarry Smith   *local = is->A;
29153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2916b4319ba4SBarry Smith }
2917b4319ba4SBarry Smith 
2918d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
2919d71ae5a4SJacob Faibussowitsch {
29203b3b1effSJed Brown   PetscFunctionBegin;
29213b3b1effSJed Brown   *local = NULL;
29223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29233b3b1effSJed Brown }
29243b3b1effSJed Brown 
2925b4319ba4SBarry Smith /*@
292611a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2927b4319ba4SBarry Smith 
29284f58015eSStefano Zampini   Not Collective.
29294f58015eSStefano Zampini 
2930b4319ba4SBarry Smith   Input Parameter:
2931b4319ba4SBarry Smith . mat - the matrix
2932b4319ba4SBarry Smith 
2933b4319ba4SBarry Smith   Output Parameter:
2934eb82efa4SStefano Zampini . local - the local matrix
2935b4319ba4SBarry Smith 
29364f58015eSStefano Zampini   Level: intermediate
2937b4319ba4SBarry Smith 
2938b4319ba4SBarry Smith   Notes:
2939b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
2940b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
294111a5261eSBarry Smith   of the `MatSetValues()` operation.
2942b4319ba4SBarry Smith 
294311a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
294496a6f129SJed Brown 
29451cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
2946b4319ba4SBarry Smith @*/
2947d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
2948d71ae5a4SJacob Faibussowitsch {
2949b4319ba4SBarry Smith   PetscFunctionBegin;
29500700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
29514f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2952cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
29533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2954b4319ba4SBarry Smith }
2955b4319ba4SBarry Smith 
29563b3b1effSJed Brown /*@
295711a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
29583b3b1effSJed Brown 
29594f58015eSStefano Zampini   Not Collective.
29604f58015eSStefano Zampini 
29612ef1f0ffSBarry Smith   Input Parameters:
29622ef1f0ffSBarry Smith + mat   - the matrix
29632ef1f0ffSBarry Smith - local - the local matrix
29643b3b1effSJed Brown 
29654f58015eSStefano Zampini   Level: intermediate
29663b3b1effSJed Brown 
29671cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
29683b3b1effSJed Brown @*/
2969d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
2970d71ae5a4SJacob Faibussowitsch {
29713b3b1effSJed Brown   PetscFunctionBegin;
29723b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
29734f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2974cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
29753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29763b3b1effSJed Brown }
29773b3b1effSJed Brown 
2978d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
2979d71ae5a4SJacob Faibussowitsch {
29808546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
29818546b261SStefano Zampini 
29828546b261SStefano Zampini   PetscFunctionBegin;
29831baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
29849566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
29859566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
29863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29878546b261SStefano Zampini }
29888546b261SStefano Zampini 
2989fe59aa6dSJacob Faibussowitsch /*@C
299011a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
29918546b261SStefano Zampini 
29924f58015eSStefano Zampini   Logically Collective.
29934f58015eSStefano Zampini 
2994d8d19677SJose E. Roman   Input Parameters:
2995a2b725a8SWilliam Gropp + mat   - the matrix
2996a2b725a8SWilliam Gropp - mtype - the local matrix type
29978546b261SStefano Zampini 
29984f58015eSStefano Zampini   Level: intermediate
29998546b261SStefano Zampini 
30001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
30018546b261SStefano Zampini @*/
3002d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3003d71ae5a4SJacob Faibussowitsch {
30048546b261SStefano Zampini   PetscFunctionBegin;
30058546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3006cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
30073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30088546b261SStefano Zampini }
30098546b261SStefano Zampini 
3010d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3011d71ae5a4SJacob Faibussowitsch {
30123b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
30133b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
30148546b261SStefano Zampini   MatType   mtype, otype;
30158546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
30163b03a366Sstefano_zampini 
30173b03a366Sstefano_zampini   PetscFunctionBegin;
3018e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
30199566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
30209566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
3021aed4548fSBarry 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);
30229566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
30239566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
30249566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
30254e4c7dbeSStefano Zampini   }
30269566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
30279566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
30283b03a366Sstefano_zampini   is->A = local;
30299566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
30309566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
303148a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
30324f58015eSStefano Zampini   is->lnnzstate = 0;
30333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30343b03a366Sstefano_zampini }
30353b03a366Sstefano_zampini 
30363b03a366Sstefano_zampini /*@
303711a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
30383b03a366Sstefano_zampini 
30394f58015eSStefano Zampini   Not Collective
30408546b261SStefano Zampini 
3041d8d19677SJose E. Roman   Input Parameters:
3042a2b725a8SWilliam Gropp + mat   - the matrix
3043a2b725a8SWilliam Gropp - local - the local matrix
30443b03a366Sstefano_zampini 
30454f58015eSStefano Zampini   Level: intermediate
304611a5261eSBarry Smith 
30471cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
30483b03a366Sstefano_zampini @*/
3049d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3050d71ae5a4SJacob Faibussowitsch {
30513b03a366Sstefano_zampini   PetscFunctionBegin;
30523b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3053b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3054cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
30553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30563b03a366Sstefano_zampini }
30573b03a366Sstefano_zampini 
3058d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3059d71ae5a4SJacob Faibussowitsch {
30606726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
30616726f965SBarry Smith 
30626726f965SBarry Smith   PetscFunctionBegin;
30639566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
30643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30656726f965SBarry Smith }
30666726f965SBarry Smith 
3067d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3068d71ae5a4SJacob Faibussowitsch {
30692e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
30702e74eeadSLisandro Dalcin 
30712e74eeadSLisandro Dalcin   PetscFunctionBegin;
30729566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
30733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30742e74eeadSLisandro Dalcin }
30752e74eeadSLisandro Dalcin 
3076d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3077d71ae5a4SJacob Faibussowitsch {
30782e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
30792e74eeadSLisandro Dalcin 
30802e74eeadSLisandro Dalcin   PetscFunctionBegin;
30812e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
30829566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
30832e74eeadSLisandro Dalcin 
30842e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
30859566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
30869566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
30879566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
30883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30892e74eeadSLisandro Dalcin }
30902e74eeadSLisandro Dalcin 
3091d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3092d71ae5a4SJacob Faibussowitsch {
30936726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
30946726f965SBarry Smith 
30956726f965SBarry Smith   PetscFunctionBegin;
30969566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
30973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30986726f965SBarry Smith }
30996726f965SBarry Smith 
3100d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3101d71ae5a4SJacob Faibussowitsch {
3102f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3103f26d0771SStefano Zampini   Mat_IS *x;
3104f26d0771SStefano Zampini 
3105f26d0771SStefano Zampini   PetscFunctionBegin;
310676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
310776bd3646SJed Brown     PetscBool ismatis;
31089566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
310928b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
311076bd3646SJed Brown   }
3111f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
31129566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
31133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3114f26d0771SStefano Zampini }
3115f26d0771SStefano Zampini 
3116d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3117d71ae5a4SJacob Faibussowitsch {
3118f26d0771SStefano Zampini   Mat                    lA;
3119f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3120f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3121f26d0771SStefano Zampini   IS                     is;
3122f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3123f26d0771SStefano Zampini   PetscInt               nrg;
3124f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3125f26d0771SStefano Zampini 
3126f26d0771SStefano Zampini   PetscFunctionBegin;
31279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
31289566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
31299566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
31309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
313176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
313208401ef6SPierre 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);
313376bd3646SJed Brown   }
31349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3135f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3136f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3137f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
31389566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
31399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
31409566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
31419566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
31429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3143f26d0771SStefano Zampini   /* compute new l2g map for columns */
3144e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3145f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3146f26d0771SStefano Zampini     PetscInt        ncg;
3147f26d0771SStefano Zampini     PetscInt        ncl;
3148f26d0771SStefano Zampini 
31499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
31509566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
31519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
31529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
315376bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
315408401ef6SPierre 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);
315576bd3646SJed Brown     }
31569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3157f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3158f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3159f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
31609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
31619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
31629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
31639566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
31649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3165f26d0771SStefano Zampini   } else {
31669566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3167f26d0771SStefano Zampini     cl2g = rl2g;
3168f26d0771SStefano Zampini   }
3169f26d0771SStefano Zampini   /* create the MATIS submatrix */
31709566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
31719566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
31729566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
31739566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3174b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3175f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
31769566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
31779566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
31789566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
31799566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
31809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
31819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
31829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
31839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3184e432b41dSStefano Zampini 
3185f26d0771SStefano Zampini   /* remove unsupported ops */
31869566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3187f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3188f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3189f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3190f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3191f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
31923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3193f26d0771SStefano Zampini }
3194f26d0771SStefano Zampini 
3195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject)
3196d71ae5a4SJacob Faibussowitsch {
3197872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
31988546b261SStefano Zampini   char      type[256];
31998546b261SStefano Zampini   PetscBool flg;
3200872cf891SStefano Zampini 
3201872cf891SStefano Zampini   PetscFunctionBegin;
3202d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
32034f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
32044f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
32054f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
32064f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
32074f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
32084f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
32094f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
32104f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
32114f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
32121baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
32131baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3214d0609cedSBarry Smith   PetscOptionsHeadEnd();
32153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3216872cf891SStefano Zampini }
3217872cf891SStefano Zampini 
3218284134d9SBarry Smith /*@
32194f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
32204f58015eSStefano Zampini 
32214f58015eSStefano Zampini   Collective.
3222284134d9SBarry Smith 
3223284134d9SBarry Smith   Input Parameters:
3224284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3225e176bc59SStefano Zampini . bs   - block size of the matrix
32262920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
32272920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
32282920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
32292920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3230e176bc59SStefano Zampini . rmap - local to global map for rows
3231e176bc59SStefano Zampini - cmap - local to global map for cols
3232284134d9SBarry Smith 
3233284134d9SBarry Smith   Output Parameter:
3234284134d9SBarry Smith . A - the resulting matrix
3235284134d9SBarry Smith 
32364f58015eSStefano Zampini   Level: intermediate
32378e6c10adSSatish Balay 
323895452b02SPatrick Sanan   Notes:
32392ef1f0ffSBarry 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
32404f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
324111a5261eSBarry Smith 
32422ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3243284134d9SBarry Smith 
32441cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3245284134d9SBarry Smith @*/
3246d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3247d71ae5a4SJacob Faibussowitsch {
3248284134d9SBarry Smith   PetscFunctionBegin;
32499566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
32509566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
325148a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
32529566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
32539566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
32543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3255284134d9SBarry Smith }
3256284134d9SBarry Smith 
3257d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3258d71ae5a4SJacob Faibussowitsch {
32598b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3260e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
32618b9382cfSStefano Zampini 
32628b9382cfSStefano Zampini   PetscFunctionBegin;
32638b9382cfSStefano Zampini   *has = PETSC_FALSE;
32643ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3265d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
32669371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
32673ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
32689566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
32693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32708b9382cfSStefano Zampini }
32718b9382cfSStefano Zampini 
3272d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3273d71ae5a4SJacob Faibussowitsch {
3274e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3275e432b41dSStefano Zampini 
3276e432b41dSStefano Zampini   PetscFunctionBegin;
32779566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
32789566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
32799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
32803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3281e432b41dSStefano Zampini }
3282e432b41dSStefano Zampini 
3283d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3284d71ae5a4SJacob Faibussowitsch {
3285e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3286e432b41dSStefano Zampini 
3287e432b41dSStefano Zampini   PetscFunctionBegin;
3288e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3289e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
32909566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3291e432b41dSStefano Zampini   } else {
32929566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3293e432b41dSStefano Zampini   }
32949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3295e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
32963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3297e432b41dSStefano Zampini }
3298e432b41dSStefano Zampini 
3299d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3300d71ae5a4SJacob Faibussowitsch {
3301e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3302e432b41dSStefano Zampini 
3303e432b41dSStefano Zampini   PetscFunctionBegin;
3304e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3305e432b41dSStefano 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);
3306e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo, coo_i, NULL, coo_i));
3307e8729f6fSJunchao Zhang   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo, coo_j, NULL, coo_j));
3308e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
33099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3310e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
33113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3312e432b41dSStefano Zampini }
3313e432b41dSStefano Zampini 
3314d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3315d71ae5a4SJacob Faibussowitsch {
3316d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3317d0dbe9f7SStefano Zampini   PetscObjectState Astate, aAstate       = PETSC_MIN_INT;
3318d0dbe9f7SStefano Zampini   PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT;
3319d0dbe9f7SStefano Zampini 
3320d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3321d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3322d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3323d0dbe9f7SStefano Zampini   if (a->assembledA) {
3324d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3325d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3326d0dbe9f7SStefano Zampini   }
3327d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3328d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3329d0dbe9f7SStefano Zampini     MatType     aAtype;
3330d0dbe9f7SStefano Zampini     PetscMPIInt size;
3331d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3332d0dbe9f7SStefano Zampini 
3333d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3334d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3335d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3336d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3337d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3338d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3339d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3340d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3341d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3342d0dbe9f7SStefano Zampini 
3343d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3344d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3345d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3346d0dbe9f7SStefano Zampini   }
3347d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3348d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3349d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
33503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3351d0dbe9f7SStefano Zampini }
3352d0dbe9f7SStefano Zampini 
3353d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3354d71ae5a4SJacob Faibussowitsch {
3355d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3356d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3357d0dbe9f7SStefano Zampini   *tA = NULL;
33583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3359d0dbe9f7SStefano Zampini }
3360d0dbe9f7SStefano Zampini 
3361d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3362d71ae5a4SJacob Faibussowitsch {
3363d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3364d0dbe9f7SStefano Zampini   PetscObjectState Astate, dAstate = PETSC_MIN_INT;
3365d0dbe9f7SStefano Zampini 
3366d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3367d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3368d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3369d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3370d0dbe9f7SStefano Zampini     Mat     tA;
3371d0dbe9f7SStefano Zampini     MatType ltype;
3372d0dbe9f7SStefano Zampini 
3373d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3374d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3375d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3376d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3377d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3378d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3379d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3380d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3381d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3382d0dbe9f7SStefano Zampini   }
3383d0dbe9f7SStefano Zampini   *dA = a->dA;
33843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3385d0dbe9f7SStefano Zampini }
3386d0dbe9f7SStefano Zampini 
3387d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3388d71ae5a4SJacob Faibussowitsch {
3389d0dbe9f7SStefano Zampini   Mat tA;
3390d0dbe9f7SStefano Zampini 
3391d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3392d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3393d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3394d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3395d0dbe9f7SStefano Zampini #if 0
3396d0dbe9f7SStefano Zampini   {
3397d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3398d0dbe9f7SStefano Zampini     MatType   ltype;
3399d0dbe9f7SStefano Zampini     VecType   vtype;
3400d0dbe9f7SStefano Zampini     char      *flg;
3401d0dbe9f7SStefano Zampini 
3402d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3403d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3404d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3405d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3406d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3407d0dbe9f7SStefano Zampini     if (flg) {
3408d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3409d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3410d0dbe9f7SStefano Zampini 
3411d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3412d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3413d0dbe9f7SStefano Zampini       }
3414d0dbe9f7SStefano Zampini     }
3415d0dbe9f7SStefano Zampini   }
3416d0dbe9f7SStefano Zampini #endif
3417d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
34183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3419d0dbe9f7SStefano Zampini }
3420d0dbe9f7SStefano Zampini 
3421d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3422d71ae5a4SJacob Faibussowitsch {
3423d0dbe9f7SStefano Zampini   Mat tA;
3424d0dbe9f7SStefano Zampini 
3425d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3426d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3427d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3428d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
34293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3430d0dbe9f7SStefano Zampini }
3431d0dbe9f7SStefano Zampini 
3432e432b41dSStefano Zampini /*@
343311a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3434e432b41dSStefano Zampini 
3435e432b41dSStefano Zampini   Not Collective
3436e432b41dSStefano Zampini 
3437e432b41dSStefano Zampini   Input Parameter:
3438e432b41dSStefano Zampini . A - the matrix
3439e432b41dSStefano Zampini 
3440e432b41dSStefano Zampini   Output Parameters:
3441e432b41dSStefano Zampini + rmapping - row mapping
3442e432b41dSStefano Zampini - cmapping - column mapping
3443e432b41dSStefano Zampini 
34442ef1f0ffSBarry Smith   Level: advanced
34452ef1f0ffSBarry Smith 
344611a5261eSBarry Smith   Note:
344711a5261eSBarry 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.
3448e432b41dSStefano Zampini 
34491cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatIS`, `MatSetLocalToGlobalMapping()`
3450e432b41dSStefano Zampini @*/
3451d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3452d71ae5a4SJacob Faibussowitsch {
3453e432b41dSStefano Zampini   PetscFunctionBegin;
3454e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3455e432b41dSStefano Zampini   PetscValidType(A, 1);
34564f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
34574f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3458cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
34593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3460e432b41dSStefano Zampini }
3461e432b41dSStefano Zampini 
3462d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3463d71ae5a4SJacob Faibussowitsch {
3464e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3465e432b41dSStefano Zampini 
3466e432b41dSStefano Zampini   PetscFunctionBegin;
3467e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3468e432b41dSStefano Zampini   if (c) *c = a->cmapping;
34693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3470e432b41dSStefano Zampini }
3471e432b41dSStefano Zampini 
3472b4319ba4SBarry Smith /*MC
34734f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
34744f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3475b4319ba4SBarry Smith 
3476b4319ba4SBarry Smith   Options Database Keys:
34774f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
34784f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
34794f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
34804f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
34812ef1f0ffSBarry Smith 
34824f58015eSStefano Zampini   Level: intermediate
3483b4319ba4SBarry Smith 
348495452b02SPatrick Sanan   Notes:
34852ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3486b4319ba4SBarry Smith 
348711a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3488b4319ba4SBarry Smith 
3489b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
34904f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3491b4319ba4SBarry Smith 
34921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3493b4319ba4SBarry Smith M*/
3494d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3495d71ae5a4SJacob Faibussowitsch {
3496e432b41dSStefano Zampini   Mat_IS *a;
3497b4319ba4SBarry Smith 
3498b4319ba4SBarry Smith   PetscFunctionBegin;
34994dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
35009566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3501e432b41dSStefano Zampini   A->data = (void *)a;
3502b4319ba4SBarry Smith 
3503e176bc59SStefano Zampini   /* matrix ops */
35049566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3505b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
35062e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
35072e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
35082e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3509b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3510b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
35112e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
351298921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3513b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3514f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
35152e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3516f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3517b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3518b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3519b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
35206726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
35212e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
35222e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
35236726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
352469796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
352569796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
352645471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3527ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
35286bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
35292b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3530659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
35317dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3532f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
35333fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
35343fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3535d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
35367fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3537ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3538872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3539fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
35408b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3541d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3542d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3543d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3544b4319ba4SBarry Smith 
3545b7ce53b6SStefano Zampini   /* special MATIS functions */
35469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
35479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
35489566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
35499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
35509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
35514f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
35529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
35539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
35549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
35559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
35569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
35579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
35589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
35599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
35609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
35619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
35629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
35639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
35649566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
35653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3566b4319ba4SBarry Smith }
3567