xref: /petsc/src/mat/impls/is/matis.c (revision 1690c2ae071c7584458d4e437df7b47bc4686b3c)
1b4319ba4SBarry Smith /*
2b4319ba4SBarry Smith     Creates a matrix class for using the Neumann-Neumann type preconditioners.
3b4319ba4SBarry Smith     This stores the matrices in globally unassembled form. Each processor
4b4319ba4SBarry Smith     assembles only its local Neumann problem and the parallel matrix vector
5b4319ba4SBarry Smith     product is handled "implicitly".
6b4319ba4SBarry Smith 
7b4319ba4SBarry Smith     Currently this allows for only one subdomain per processor.
8b4319ba4SBarry Smith */
9b4319ba4SBarry Smith 
10d0dbe9f7SStefano Zampini #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/
115042aa92SStefano Zampini #include <../src/mat/impls/aij/mpi/mpiaij.h>
124f2d7cafSStefano Zampini #include <petsc/private/sfimpl.h>
13a72d46e8SStefano Zampini #include <petsc/private/vecimpl.h>
14e432b41dSStefano Zampini #include <petsc/private/hashseti.h>
1528f4e0baSStefano Zampini 
16f26d0771SStefano Zampini #define MATIS_MAX_ENTRIES_INSERTION 2048
17b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
18b4f971dfSStefano Zampini static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
198546b261SStefano Zampini static PetscErrorCode MatISSetUpScatters_Private(Mat);
20f26d0771SStefano Zampini 
21d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr)
22d71ae5a4SJacob Faibussowitsch {
2375d48cdbSStefano Zampini   MatISPtAP ptap = (MatISPtAP)ptr;
2475d48cdbSStefano Zampini 
2575d48cdbSStefano Zampini   PetscFunctionBegin;
269566063dSJacob Faibussowitsch   PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP));
279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis0));
289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->cis1));
299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris0));
309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ptap->ris1));
319566063dSJacob Faibussowitsch   PetscCall(PetscFree(ptap));
323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3375d48cdbSStefano Zampini }
3475d48cdbSStefano Zampini 
35d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
36d71ae5a4SJacob Faibussowitsch {
3775d48cdbSStefano Zampini   MatISPtAP      ptap;
3875d48cdbSStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
3975d48cdbSStefano Zampini   Mat            lA, lC;
4075d48cdbSStefano Zampini   MatReuse       reuse;
4175d48cdbSStefano Zampini   IS             ris[2], cis[2];
4275d48cdbSStefano Zampini   PetscContainer c;
4375d48cdbSStefano Zampini   PetscInt       n;
4475d48cdbSStefano Zampini 
4575d48cdbSStefano Zampini   PetscFunctionBegin;
469566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c));
4728b400f6SJacob Faibussowitsch   PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information");
489566063dSJacob Faibussowitsch   PetscCall(PetscContainerGetPointer(c, (void **)&ptap));
4975d48cdbSStefano Zampini   ris[0] = ptap->ris0;
5075d48cdbSStefano Zampini   ris[1] = ptap->ris1;
5175d48cdbSStefano Zampini   cis[0] = ptap->cis0;
5275d48cdbSStefano Zampini   cis[1] = ptap->cis1;
5375d48cdbSStefano Zampini   n      = ptap->ris1 ? 2 : 1;
5475d48cdbSStefano Zampini   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
559566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP));
5675d48cdbSStefano Zampini 
579566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
589566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(C, &lC));
5975d48cdbSStefano Zampini   if (ptap->ris1) { /* unsymmetric A mapping */
6075d48cdbSStefano Zampini     Mat lPt;
6175d48cdbSStefano Zampini 
629566063dSJacob Faibussowitsch     PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt));
639566063dSJacob Faibussowitsch     PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC));
6448a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", (PetscObject)lPt));
659566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lPt));
6675d48cdbSStefano Zampini   } else {
679566063dSJacob Faibussowitsch     PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC));
6848a46eb9SPierre Jolivet     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0]));
6975d48cdbSStefano Zampini   }
7075d48cdbSStefano Zampini   if (reuse == MAT_INITIAL_MATRIX) {
719566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(C, lC));
729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lC));
7375d48cdbSStefano Zampini   }
749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7775d48cdbSStefano Zampini }
7875d48cdbSStefano Zampini 
79d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis)
80d71ae5a4SJacob Faibussowitsch {
8175d48cdbSStefano Zampini   Mat             Po, Pd;
8275d48cdbSStefano Zampini   IS              zd, zo;
8375d48cdbSStefano Zampini   const PetscInt *garray;
8475d48cdbSStefano Zampini   PetscInt       *aux, i, bs;
8575d48cdbSStefano Zampini   PetscInt        dc, stc, oc, ctd, cto;
8675d48cdbSStefano Zampini   PetscBool       ismpiaij, ismpibaij, isseqaij, isseqbaij;
8775d48cdbSStefano Zampini   MPI_Comm        comm;
8875d48cdbSStefano Zampini 
8975d48cdbSStefano Zampini   PetscFunctionBegin;
9075d48cdbSStefano Zampini   PetscValidHeaderSpecific(PT, MAT_CLASSID, 1);
914f572ea9SToby Isaac   PetscAssertPointer(cis, 2);
929566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)PT, &comm));
9375d48cdbSStefano Zampini   bs = 1;
949566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij));
959566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij));
969566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij));
979566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij));
9875d48cdbSStefano Zampini   if (isseqaij || isseqbaij) {
9975d48cdbSStefano Zampini     Pd     = PT;
10075d48cdbSStefano Zampini     Po     = NULL;
10175d48cdbSStefano Zampini     garray = NULL;
10275d48cdbSStefano Zampini   } else if (ismpiaij) {
1039566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray));
10475d48cdbSStefano Zampini   } else if (ismpibaij) {
1059566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray));
1069566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(PT, &bs));
10798921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)(PT))->type_name);
10875d48cdbSStefano Zampini 
10975d48cdbSStefano Zampini   /* identify any null columns in Pd or Po */
11022f7620eSStefano Zampini   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
11122f7620eSStefano Zampini      some of the columns are not really zero, but very close to */
11275d48cdbSStefano Zampini   zo = zd = NULL;
11348a46eb9SPierre Jolivet   if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo));
1149566063dSJacob Faibussowitsch   PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd));
11575d48cdbSStefano Zampini 
1169566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(PT, NULL, &dc));
1179566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL));
1189566063dSJacob Faibussowitsch   if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc));
11975d48cdbSStefano Zampini   else oc = 0;
1209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
12175d48cdbSStefano Zampini   if (zd) {
12275d48cdbSStefano Zampini     const PetscInt *idxs;
12375d48cdbSStefano Zampini     PetscInt        nz;
12475d48cdbSStefano Zampini 
12575d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1269566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zd, bs));
1279566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zd, &nz));
1289566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zd, &idxs));
12975d48cdbSStefano Zampini     ctd = nz / bs;
13075d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs;
1319566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zd, &idxs));
13275d48cdbSStefano Zampini   } else {
13375d48cdbSStefano Zampini     ctd = dc / bs;
13475d48cdbSStefano Zampini     for (i = 0; i < ctd; i++) aux[i] = i + stc / bs;
13575d48cdbSStefano Zampini   }
13675d48cdbSStefano Zampini   if (zo) {
13775d48cdbSStefano Zampini     const PetscInt *idxs;
13875d48cdbSStefano Zampini     PetscInt        nz;
13975d48cdbSStefano Zampini 
14075d48cdbSStefano Zampini     /* this will throw an error if bs is not valid */
1419566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(zo, bs));
1429566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(zo, &nz));
1439566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(zo, &idxs));
14475d48cdbSStefano Zampini     cto = nz / bs;
14575d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs];
1469566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(zo, &idxs));
14775d48cdbSStefano Zampini   } else {
14875d48cdbSStefano Zampini     cto = oc / bs;
14975d48cdbSStefano Zampini     for (i = 0; i < cto; i++) aux[i + ctd] = garray[i];
15075d48cdbSStefano Zampini   }
1519566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis));
1529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zd));
1539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&zo));
1543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15575d48cdbSStefano Zampini }
15675d48cdbSStefano Zampini 
157d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C)
158d71ae5a4SJacob Faibussowitsch {
1598546b261SStefano Zampini   Mat                    PT, lA;
16075d48cdbSStefano Zampini   MatISPtAP              ptap;
16175d48cdbSStefano Zampini   ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g;
16275d48cdbSStefano Zampini   PetscContainer         c;
1638546b261SStefano Zampini   MatType                lmtype;
16475d48cdbSStefano Zampini   const PetscInt        *garray;
16575d48cdbSStefano Zampini   PetscInt               ibs, N, dc;
16675d48cdbSStefano Zampini   MPI_Comm               comm;
16775d48cdbSStefano Zampini 
16875d48cdbSStefano Zampini   PetscFunctionBegin;
1699566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1709566063dSJacob Faibussowitsch   PetscCall(MatSetType(C, MATIS));
1719566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
1729566063dSJacob Faibussowitsch   PetscCall(MatGetType(lA, &lmtype));
1739566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(C, lmtype));
1749566063dSJacob Faibussowitsch   PetscCall(MatGetSize(P, NULL, &N));
1759566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(P, NULL, &dc));
1769566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(C, dc, dc, N, N));
17775d48cdbSStefano Zampini   /* Not sure about this
1789566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSizes(P,NULL,&ibs));
1799566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(*C,ibs));
18075d48cdbSStefano Zampini */
18175d48cdbSStefano Zampini 
1829566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ptap));
1839566063dSJacob Faibussowitsch   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1849566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetPointer(c, ptap));
1859566063dSJacob Faibussowitsch   PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyPtAP_Private));
1869566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c));
1879566063dSJacob Faibussowitsch   PetscCall(PetscContainerDestroy(&c));
18875d48cdbSStefano Zampini   ptap->fill = fill;
18975d48cdbSStefano Zampini 
1909566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g));
19175d48cdbSStefano Zampini 
1929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs));
1939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N));
1949566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray));
1959566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0));
1969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray));
19775d48cdbSStefano Zampini 
1989566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT));
1999566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0));
2009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g));
2019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&PT));
20275d48cdbSStefano Zampini 
20375d48cdbSStefano Zampini   Crl2g = NULL;
20475d48cdbSStefano Zampini   if (rl2g != cl2g) { /* unsymmetric A mapping */
20575d48cdbSStefano Zampini     PetscBool same, lsame = PETSC_FALSE;
20675d48cdbSStefano Zampini     PetscInt  N1, ibs1;
20775d48cdbSStefano Zampini 
2089566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1));
2099566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1));
2109566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray));
2114f58015eSStefano Zampini     PetscCall(ISCreateBlock(comm, ibs, N1 / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1));
2129566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray));
21375d48cdbSStefano Zampini     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
21475d48cdbSStefano Zampini       const PetscInt *i1, *i2;
21575d48cdbSStefano Zampini 
2169566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris0, &i1));
2179566063dSJacob Faibussowitsch       PetscCall(ISBlockGetIndices(ptap->ris1, &i2));
2189566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(i1, i2, N, &lsame));
21975d48cdbSStefano Zampini     }
2201c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lsame, &same, 1, MPIU_BOOL, MPI_LAND, comm));
22175d48cdbSStefano Zampini     if (same) {
2229566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ptap->ris1));
22375d48cdbSStefano Zampini     } else {
2249566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT));
2259566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1));
2269566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g));
2279566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&PT));
22875d48cdbSStefano Zampini     }
22975d48cdbSStefano Zampini   }
23075d48cdbSStefano Zampini   /* Not sure about this
23175d48cdbSStefano Zampini   if (!Crl2g) {
2329566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(C,&ibs));
2339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs));
23475d48cdbSStefano Zampini   }
23575d48cdbSStefano Zampini */
2369566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g));
2379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g));
2389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g));
23975d48cdbSStefano Zampini 
2404222ddf1SHong Zhang   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
2413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24275d48cdbSStefano Zampini }
24375d48cdbSStefano Zampini 
244d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
245d71ae5a4SJacob Faibussowitsch {
2464222ddf1SHong Zhang   Mat_Product *product = C->product;
2474222ddf1SHong Zhang   Mat          A = product->A, P = product->B;
2484222ddf1SHong Zhang   PetscReal    fill = product->fill;
24975d48cdbSStefano Zampini 
25075d48cdbSStefano Zampini   PetscFunctionBegin;
2519566063dSJacob Faibussowitsch   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
2524222ddf1SHong Zhang   C->ops->productnumeric = MatProductNumeric_PtAP;
2533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25475d48cdbSStefano Zampini }
25575d48cdbSStefano Zampini 
256d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
257d71ae5a4SJacob Faibussowitsch {
2584222ddf1SHong Zhang   PetscFunctionBegin;
2594222ddf1SHong Zhang   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
2603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2614222ddf1SHong Zhang }
2624222ddf1SHong Zhang 
263d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
264d71ae5a4SJacob Faibussowitsch {
2654222ddf1SHong Zhang   Mat_Product *product = C->product;
2664222ddf1SHong Zhang 
2674222ddf1SHong Zhang   PetscFunctionBegin;
26848a46eb9SPierre Jolivet   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
2693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2704222ddf1SHong Zhang }
2714222ddf1SHong Zhang 
272d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
273d71ae5a4SJacob Faibussowitsch {
2745b003df0Sstefano_zampini   MatISLocalFields lf = (MatISLocalFields)ptr;
2755b003df0Sstefano_zampini   PetscInt         i;
2765b003df0Sstefano_zampini 
277ab4d48faSStefano Zampini   PetscFunctionBegin;
27848a46eb9SPierre Jolivet   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
27948a46eb9SPierre Jolivet   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lf->rf, lf->cf));
2819566063dSJacob Faibussowitsch   PetscCall(PetscFree(lf));
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2835b003df0Sstefano_zampini }
284a72627d2SStefano Zampini 
285d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
286d71ae5a4SJacob Faibussowitsch {
287c9225affSStefano Zampini   Mat B, lB;
288c9225affSStefano Zampini 
289c9225affSStefano Zampini   PetscFunctionBegin;
290c9225affSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
291c9225affSStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
292c9225affSStefano Zampini     PetscInt               bs;
293c9225affSStefano Zampini     IS                     is;
294c9225affSStefano Zampini 
2959566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(A, &bs));
2969566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
297c9225affSStefano Zampini     if (bs > 1) {
298c9225affSStefano Zampini       IS       is2;
299c9225affSStefano Zampini       PetscInt i, *aux;
300c9225affSStefano Zampini 
3019566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3029566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3039566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3049566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3059566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
306c9225affSStefano Zampini       is = is2;
307c9225affSStefano Zampini     }
3089566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3099566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3119566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
312c9225affSStefano Zampini     if (bs > 1) {
313c9225affSStefano Zampini       IS       is2;
314c9225affSStefano Zampini       PetscInt i, *aux;
315c9225affSStefano Zampini 
3169566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(is, &i));
3179566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
3189566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
3199566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
3209566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
321c9225affSStefano Zampini       is = is2;
322c9225affSStefano Zampini     }
3239566063dSJacob Faibussowitsch     PetscCall(ISSetIdentity(is));
3249566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3259566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3269566063dSJacob Faibussowitsch     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
3279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3289566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3299566063dSJacob Faibussowitsch     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
330c9225affSStefano Zampini     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
331c9225affSStefano Zampini   } else {
332c9225affSStefano Zampini     B = *newmat;
3339566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
334c9225affSStefano Zampini     lB = A;
335c9225affSStefano Zampini   }
3369566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lB));
3379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lB));
3389566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
34048a46eb9SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
3413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
342c9225affSStefano Zampini }
343c9225affSStefano Zampini 
344d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
345d71ae5a4SJacob Faibussowitsch {
346f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
347c9225affSStefano Zampini   PetscScalar    *aa;
348c9225affSStefano Zampini   const PetscInt *ii, *jj;
349c9225affSStefano Zampini   PetscInt        i, n, m;
350fabe8965SStefano Zampini   PetscInt       *ecount, **eneighs;
351c9225affSStefano Zampini   PetscBool       flg;
352c9225affSStefano Zampini 
353c9225affSStefano Zampini   PetscFunctionBegin;
3549566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
35508401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
3569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
35708401ef6SPierre Jolivet   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
3589566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
359c9225affSStefano Zampini   for (i = 0; i < n; i++) {
360fabe8965SStefano Zampini     if (ecount[i] > 1) {
361c9225affSStefano Zampini       PetscInt j;
362c9225affSStefano Zampini 
363c9225affSStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
364c9225affSStefano Zampini         PetscInt  i2   = jj[j], p, p2;
365fabe8965SStefano Zampini         PetscReal scal = 0.0;
366c9225affSStefano Zampini 
367c9225affSStefano Zampini         for (p = 0; p < ecount[i]; p++) {
368c9225affSStefano Zampini           for (p2 = 0; p2 < ecount[i2]; p2++) {
3699371c9d4SSatish Balay             if (eneighs[i][p] == eneighs[i2][p2]) {
3709371c9d4SSatish Balay               scal += 1.0;
3719371c9d4SSatish Balay               break;
3729371c9d4SSatish Balay             }
373c9225affSStefano Zampini           }
374c9225affSStefano Zampini         }
375fabe8965SStefano Zampini         if (scal) aa[j] /= scal;
376c9225affSStefano Zampini       }
377c9225affSStefano Zampini     }
378c9225affSStefano Zampini   }
3799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
3809566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
3819566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
38208401ef6SPierre Jolivet   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
3833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
384c9225affSStefano Zampini }
385c9225affSStefano Zampini 
3869371c9d4SSatish Balay typedef enum {
3879371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_NATURAL,
3889371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_MAT,
3899371c9d4SSatish Balay   MAT_IS_DISASSEMBLE_L2G_ND
3909371c9d4SSatish Balay } MatISDisassemblel2gType;
391fabe8965SStefano Zampini 
392d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
393d71ae5a4SJacob Faibussowitsch {
394fabe8965SStefano Zampini   Mat                     Ad, Ao;
395fabe8965SStefano Zampini   IS                      is, ndmap, ndsub;
396c9225affSStefano Zampini   MPI_Comm                comm;
397fabe8965SStefano Zampini   const PetscInt         *garray, *ndmapi;
398fabe8965SStefano Zampini   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
399fabe8965SStefano Zampini   PetscBool               ismpiaij, ismpibaij;
400f4259b30SLisandro Dalcin   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
401fabe8965SStefano Zampini   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
402fabe8965SStefano Zampini   MatPartitioning         part;
403fabe8965SStefano Zampini   PetscSF                 sf;
40491d376acSStefano Zampini   PetscObject             dm;
405c9225affSStefano Zampini 
406c9225affSStefano Zampini   PetscFunctionBegin;
407d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
4089566063dSJacob 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));
409d0609cedSBarry Smith   PetscOptionsEnd();
410fabe8965SStefano Zampini   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
4119566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
4123ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
413c9225affSStefano Zampini   }
4149566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
4159566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
4169566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
4179566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
418fabe8965SStefano Zampini   switch (mode) {
419fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_ND:
4209566063dSJacob Faibussowitsch     PetscCall(MatPartitioningCreate(comm, &part));
4219566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetAdjacency(part, A));
4229566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
4239566063dSJacob Faibussowitsch     PetscCall(MatPartitioningSetFromOptions(part));
4249566063dSJacob Faibussowitsch     PetscCall(MatPartitioningApplyND(part, &ndmap));
4259566063dSJacob Faibussowitsch     PetscCall(MatPartitioningDestroy(&part));
4269566063dSJacob Faibussowitsch     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
4279566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
4289566063dSJacob Faibussowitsch     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
4299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
430fabe8965SStefano Zampini 
431fabe8965SStefano Zampini     /* it may happen that a separator node is not properly shared */
4329566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
4339566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &sf));
4349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
4359566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
4369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
4379566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
4389566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4399566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
4409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
4419566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ndmap, &ndmapi));
442fabe8965SStefano Zampini     for (i = 0, cnt = 0; i < A->rmap->n; i++)
4439371c9d4SSatish Balay       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
444fabe8965SStefano Zampini 
4451c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
446fabe8965SStefano Zampini     if (i) { /* we detected isolated separator nodes */
447fabe8965SStefano Zampini       Mat                    A2, A3;
448fabe8965SStefano Zampini       IS                    *workis, is2;
449fabe8965SStefano Zampini       PetscScalar           *vals;
450fabe8965SStefano Zampini       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
451fabe8965SStefano Zampini       ISLocalToGlobalMapping ll2g;
452fabe8965SStefano Zampini       PetscBool              flg;
453fabe8965SStefano Zampini       const PetscInt        *ii, *jj;
454fabe8965SStefano Zampini 
455fabe8965SStefano Zampini       /* communicate global id of separators */
456d0609cedSBarry Smith       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
4579371c9d4SSatish Balay       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
458fabe8965SStefano Zampini 
4599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nl, &lndmapi));
4609566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
461fabe8965SStefano Zampini 
462fabe8965SStefano Zampini       /* compute adjacency of isolated separators node */
4639566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(gcnt, &workis));
464fabe8965SStefano Zampini       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
46548a46eb9SPierre Jolivet         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
466fabe8965SStefano Zampini       }
46748a46eb9SPierre Jolivet       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
468fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4699566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
4709566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
471fabe8965SStefano Zampini       }
472fabe8965SStefano Zampini 
473fabe8965SStefano Zampini       /* no communications since all the ISes correspond to locally owned rows */
4749566063dSJacob Faibussowitsch       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
475fabe8965SStefano Zampini 
476fabe8965SStefano Zampini       /* end communicate global id of separators */
4779566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
478fabe8965SStefano Zampini 
479fabe8965SStefano Zampini       /* communicate new layers : create a matrix and transpose it */
4809566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(dnz, A->rmap->n));
4819566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(onz, A->rmap->n));
482fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) {
483fabe8965SStefano Zampini         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
484fabe8965SStefano Zampini           const PetscInt *idxs;
485fabe8965SStefano Zampini           PetscInt        s;
486fabe8965SStefano Zampini 
4879566063dSJacob Faibussowitsch           PetscCall(ISGetLocalSize(workis[j], &s));
4889566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
4899566063dSJacob Faibussowitsch           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
490fabe8965SStefano Zampini           j++;
491fabe8965SStefano Zampini         }
492fabe8965SStefano Zampini       }
49308401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
494fabe8965SStefano Zampini 
495fabe8965SStefano Zampini       for (i = 0; i < gcnt; i++) {
4969566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
4979566063dSJacob Faibussowitsch         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
498fabe8965SStefano Zampini       }
499fabe8965SStefano Zampini 
500fabe8965SStefano Zampini       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
5019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(j, &vals));
502fabe8965SStefano Zampini       for (i = 0; i < j; i++) vals[i] = 1.0;
503fabe8965SStefano Zampini 
5049566063dSJacob Faibussowitsch       PetscCall(MatCreate(comm, &A2));
5059566063dSJacob Faibussowitsch       PetscCall(MatSetType(A2, MATMPIAIJ));
5069566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
5079566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
5089566063dSJacob Faibussowitsch       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
509fabe8965SStefano Zampini       for (i = 0, j = 0; i < A2->rmap->n; i++) {
510fabe8965SStefano Zampini         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
511fabe8965SStefano Zampini         const PetscInt *idxs;
512fabe8965SStefano Zampini 
513fabe8965SStefano Zampini         if (s) {
5149566063dSJacob Faibussowitsch           PetscCall(ISGetIndices(workis[j], &idxs));
5159566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
5169566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(workis[j], &idxs));
517fabe8965SStefano Zampini           j++;
518fabe8965SStefano Zampini         }
519fabe8965SStefano Zampini       }
52008401ef6SPierre Jolivet       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
5219566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
5229566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
5239566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
5249566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
525fabe8965SStefano Zampini 
526fabe8965SStefano Zampini       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
527fabe8965SStefano Zampini       for (i = 0, j = 0; i < nl; i++)
528fabe8965SStefano Zampini         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
5299566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
5309566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
5319566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5329566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A2));
533fabe8965SStefano Zampini 
534fabe8965SStefano Zampini       /* extend local to global map to include connected isolated separators */
5359566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
53628b400f6SJacob Faibussowitsch       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
5379566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
5389566063dSJacob Faibussowitsch       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
53928b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5409566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
5419566063dSJacob Faibussowitsch       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
54228b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
5439566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
5449566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
5459566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
546fabe8965SStefano Zampini 
547fabe8965SStefano Zampini       /* add new nodes to the local-to-global map */
5489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
5499566063dSJacob Faibussowitsch       PetscCall(ISExpand(ndsub, is2, &is));
5509566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is2));
5519566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5529566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
553fabe8965SStefano Zampini 
5549566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&A3));
5559566063dSJacob Faibussowitsch       PetscCall(PetscFree(lndmapi));
556d0609cedSBarry Smith       MatPreallocateEnd(dnz, onz);
55748a46eb9SPierre Jolivet       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
5589566063dSJacob Faibussowitsch       PetscCall(PetscFree(workis));
559fabe8965SStefano Zampini     }
5609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
5619566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
5629566063dSJacob Faibussowitsch     PetscCall(PetscFree(ndmapc));
5639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndmap));
5649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ndsub));
5659566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
5664f58015eSStefano Zampini     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-mat_is_nd_l2g_view"));
567fabe8965SStefano Zampini     break;
568fabe8965SStefano Zampini   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
56991d376acSStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)&dm));
57091d376acSStefano Zampini     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
57191d376acSStefano Zampini       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
57291d376acSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*l2g));
5733ba16761SJacob Faibussowitsch       if (*l2g) PetscFunctionReturn(PETSC_SUCCESS);
57491d376acSStefano Zampini     }
575fabe8965SStefano Zampini     if (ismpiaij) {
5769566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
577fabe8965SStefano Zampini     } else if (ismpibaij) {
5789566063dSJacob Faibussowitsch       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
57998921bdaSJacob Faibussowitsch     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
580c9225affSStefano Zampini     if (A->rmap->n) {
581fabe8965SStefano Zampini       PetscInt dc, oc, stc, *aux;
582c9225affSStefano Zampini 
583ebf8cefbSJunchao Zhang       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
5849566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
585d0dbe9f7SStefano Zampini       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
5869566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
5879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
588c9225affSStefano Zampini       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
589ebf8cefbSJunchao Zhang       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
5909566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
591c9225affSStefano Zampini     } else {
5929566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
593c9225affSStefano Zampini     }
5949566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
5959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
596fabe8965SStefano Zampini     break;
597d71ae5a4SJacob Faibussowitsch   default:
598d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
599c9225affSStefano Zampini   }
6003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
601c9225affSStefano Zampini }
602c9225affSStefano Zampini 
603d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
604d71ae5a4SJacob Faibussowitsch {
605c9225affSStefano Zampini   Mat                    lA, Ad, Ao, B = NULL;
6066989cf23SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
6076989cf23SStefano Zampini   IS                     is;
6086989cf23SStefano Zampini   MPI_Comm               comm;
6096989cf23SStefano Zampini   void                  *ptrs[2];
6106989cf23SStefano Zampini   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
611c9225affSStefano Zampini   const PetscInt        *garray;
6126989cf23SStefano Zampini   PetscScalar           *dd, *od, *aa, *data;
613c9225affSStefano Zampini   const PetscInt        *di, *dj, *oi, *oj;
614c9225affSStefano Zampini   const PetscInt        *odi, *odj, *ooi, *ooj;
6156989cf23SStefano Zampini   PetscInt              *aux, *ii, *jj;
616a50ef18cSStefano Zampini   PetscInt               rbs, cbs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
617a50ef18cSStefano Zampini   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE, cong;
618c9225affSStefano Zampini   PetscMPIInt            size;
6196989cf23SStefano Zampini 
620ab4d48faSStefano Zampini   PetscFunctionBegin;
6219566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
6229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
623c9225affSStefano Zampini   if (size == 1) {
6249566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
6253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
626c9225affSStefano Zampini   }
627a50ef18cSStefano Zampini   PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
628a50ef18cSStefano Zampini   PetscCall(MatHasCongruentLayouts(A, &cong));
629a50ef18cSStefano Zampini   if (reuse != MAT_REUSE_MATRIX && cong && rbs == cbs) {
6309566063dSJacob Faibussowitsch     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
6319566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
6329566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
633a50ef18cSStefano Zampini     PetscCall(MatSetSizes(B, A->rmap->n, A->rmap->n, A->rmap->N, A->rmap->N));
6349566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
635a50ef18cSStefano Zampini     PetscCall(MatSetBlockSizes(B, rbs, rbs));
6369566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
637c9225affSStefano Zampini     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
638c9225affSStefano Zampini     reuse = MAT_REUSE_MATRIX;
639c9225affSStefano Zampini   }
640c9225affSStefano Zampini   if (reuse == MAT_REUSE_MATRIX) {
641c9225affSStefano Zampini     Mat            *newlA, lA;
642c9225affSStefano Zampini     IS              rows, cols;
643c9225affSStefano Zampini     const PetscInt *ridx, *cidx;
644a50ef18cSStefano Zampini     PetscInt        nr, nc;
645c9225affSStefano Zampini 
646c9225affSStefano Zampini     if (!B) B = *newmat;
6479566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
6489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
6499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
6509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
6519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
6529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
6539566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
6549566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
655c9225affSStefano Zampini     if (rl2g != cl2g) {
6569566063dSJacob Faibussowitsch       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
657c9225affSStefano Zampini     } else {
6589566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)rows));
659c9225affSStefano Zampini       cols = rows;
660c9225affSStefano Zampini     }
6619566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(B, &lA));
6629566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
6639566063dSJacob Faibussowitsch     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
6649566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
6659566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
6669566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rows));
6679566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&cols));
668c9225affSStefano Zampini     if (!lA->preallocated) { /* first time */
6699566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
6709566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(B, lA));
6719566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)lA));
672c9225affSStefano Zampini     }
6739566063dSJacob Faibussowitsch     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
6749566063dSJacob Faibussowitsch     PetscCall(MatDestroySubMatrices(1, &newlA));
6759566063dSJacob Faibussowitsch     PetscCall(MatISScaleDisassembling_Private(B));
6769566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
6779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
6789566063dSJacob Faibussowitsch     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
679c9225affSStefano Zampini     else *newmat = B;
6803ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
681c9225affSStefano Zampini   }
682a50ef18cSStefano Zampini   /* general case, just compress out the column space */
6839566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
6849566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
685c9225affSStefano Zampini   if (ismpiaij) {
686a50ef18cSStefano Zampini     cbs = 1; /* We cannot guarantee the off-process matrix will respect the column block size */
6879566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
688c9225affSStefano Zampini   } else if (ismpibaij) {
6899566063dSJacob Faibussowitsch     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
6909566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
6919566063dSJacob Faibussowitsch     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
69298921bdaSJacob Faibussowitsch   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
6939566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ad, &dd));
6949566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJGetArray(Ao, &od));
6956989cf23SStefano Zampini 
6966989cf23SStefano Zampini   /* access relevant information from MPIAIJ */
6979566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &str, NULL));
6989566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
699a50ef18cSStefano Zampini   PetscCall(MatGetLocalSize(Ad, &dr, &dc));
7009566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
701d72e20dbSStefano Zampini   PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
702d72e20dbSStefano Zampini 
7039566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
70428b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
7059566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
70628b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
707c9225affSStefano Zampini   nnz = di[dr] + oi[dr];
708c9225affSStefano Zampini   /* store original pointers to be restored later */
7099371c9d4SSatish Balay   odi = di;
7109371c9d4SSatish Balay   odj = dj;
7119371c9d4SSatish Balay   ooi = oi;
7129371c9d4SSatish Balay   ooj = oj;
7136989cf23SStefano Zampini 
7146989cf23SStefano Zampini   /* generate l2g maps for rows and cols */
715a50ef18cSStefano Zampini   PetscCall(ISCreateStride(comm, dr / rbs, str / rbs, 1, &is));
716a50ef18cSStefano Zampini   if (rbs > 1) {
717c9225affSStefano Zampini     IS is2;
718c9225affSStefano Zampini 
7199566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is, &i));
7209566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
721a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, rbs, i, aux, PETSC_COPY_VALUES, &is2));
7229566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
7239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
724c9225affSStefano Zampini     is = is2;
725c9225affSStefano Zampini   }
7269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
7279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
728e363d98aSStefano Zampini   if (dr) {
729a50ef18cSStefano Zampini     PetscCall(PetscMalloc1((dc + oc) / cbs, &aux));
730a50ef18cSStefano Zampini     for (i = 0; i < dc / cbs; i++) aux[i] = i + stc / cbs;
731a50ef18cSStefano Zampini     for (i = 0; i < oc / cbs; i++) aux[i + dc / cbs] = garray[i];
732a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, cbs, (dc + oc) / cbs, aux, PETSC_OWN_POINTER, &is));
733e363d98aSStefano Zampini     lc = dc + oc;
734e363d98aSStefano Zampini   } else {
735a50ef18cSStefano Zampini     PetscCall(ISCreateBlock(comm, cbs, 0, NULL, PETSC_OWN_POINTER, &is));
736e363d98aSStefano Zampini     lc = 0;
737e363d98aSStefano Zampini   }
7389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
7399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
7406989cf23SStefano Zampini 
7416989cf23SStefano Zampini   /* create MATIS object */
7429566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &B));
7439566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
7449566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
745a50ef18cSStefano Zampini   PetscCall(MatSetBlockSizes(B, rbs, cbs));
7469566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
7479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
7489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
7496989cf23SStefano Zampini 
7506989cf23SStefano Zampini   /* merge local matrices */
7519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
7529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nnz, &data));
7536989cf23SStefano Zampini   ii  = aux;
7546989cf23SStefano Zampini   jj  = aux + dr + 1;
7556989cf23SStefano Zampini   aa  = data;
7566989cf23SStefano Zampini   *ii = *(di++) + *(oi++);
7579371c9d4SSatish Balay   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
7589371c9d4SSatish Balay     for (; jd < *di; jd++) {
7599371c9d4SSatish Balay       *jj++ = *dj++;
7609371c9d4SSatish Balay       *aa++ = *dd++;
7619371c9d4SSatish Balay     }
7629371c9d4SSatish Balay     for (; jo < *oi; jo++) {
7639371c9d4SSatish Balay       *jj++ = *oj++ + dc;
7649371c9d4SSatish Balay       *aa++ = *od++;
7659371c9d4SSatish Balay     }
7666989cf23SStefano Zampini     *(++ii) = *(di++) + *(oi++);
7676989cf23SStefano Zampini   }
7686989cf23SStefano Zampini   for (; cum < dr; cum++) *(++ii) = nnz;
769c9225affSStefano Zampini 
7709566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
77128b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7729566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
77328b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
7749566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
7759566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
776c9225affSStefano Zampini 
7776989cf23SStefano Zampini   ii = aux;
7786989cf23SStefano Zampini   jj = aux + dr + 1;
7796989cf23SStefano Zampini   aa = data;
7809566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
7816989cf23SStefano Zampini 
7826989cf23SStefano Zampini   /* create containers to destroy the data */
7836989cf23SStefano Zampini   ptrs[0] = aux;
7846989cf23SStefano Zampini   ptrs[1] = data;
7856989cf23SStefano Zampini   for (i = 0; i < 2; i++) {
7866989cf23SStefano Zampini     PetscContainer c;
7876989cf23SStefano Zampini 
7889566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
7899566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, ptrs[i]));
7909566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, PetscContainerUserDestroyDefault));
7919566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)lA, names[i], (PetscObject)c));
7929566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
7936989cf23SStefano Zampini   }
794c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7969566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
797c9225affSStefano Zampini   }
7986989cf23SStefano Zampini 
7996989cf23SStefano Zampini   /* finalize matrix */
8009566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
8019566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
8029566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
8039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
804c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
8059566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
806c9225affSStefano Zampini   } else *newmat = B;
8073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8086989cf23SStefano Zampini }
8096989cf23SStefano Zampini 
810d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
811d71ae5a4SJacob Faibussowitsch {
8125e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8135e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8145e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8155e3038f0Sstefano_zampini   MPI_Comm               comm;
8165b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8175b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8189e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8194f58015eSStefano Zampini   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
8205e3038f0Sstefano_zampini 
821ab4d48faSStefano Zampini   PetscFunctionBegin;
8229566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8235e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8245e3038f0Sstefano_zampini   rnest  = NULL;
8255e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8265e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8275e3038f0Sstefano_zampini 
8289566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
829f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8309566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8319566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8325e3038f0Sstefano_zampini     if (isnest) {
8339566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8345e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8355e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8365e3038f0Sstefano_zampini     }
8375e3038f0Sstefano_zampini   }
8389566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8399566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8419566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8425e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8435e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8444f58015eSStefano Zampini       PetscBool ismatis, sallow;
8459e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8465e3038f0Sstefano_zampini 
8475e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8485e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8495e3038f0Sstefano_zampini 
8505e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
851013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8529e7b2b25Sstefano_zampini       if (istrans[ij]) {
8539e7b2b25Sstefano_zampini         Mat T, lT;
8549566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8559566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
85628b400f6SJacob 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);
8574f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(T, &sallow));
8589566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8599566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8609e7b2b25Sstefano_zampini       } else {
8619566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
86228b400f6SJacob 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);
8634f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
8649566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8659e7b2b25Sstefano_zampini       }
8664f58015eSStefano Zampini       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
8674f58015eSStefano Zampini       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
8685e3038f0Sstefano_zampini 
8695e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8709566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8719566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8725e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
873aed4548fSBarry 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);
874aed4548fSBarry 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);
8755e3038f0Sstefano_zampini       lr[i] = l1;
8765e3038f0Sstefano_zampini       lc[j] = l2;
8775e3038f0Sstefano_zampini 
878da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8795e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8805e3038f0Sstefano_zampini     }
8815e3038f0Sstefano_zampini   }
8825e3038f0Sstefano_zampini 
88376bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8845e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8855e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8865e3038f0Sstefano_zampini       rl2g = NULL;
8875e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8885e3038f0Sstefano_zampini         PetscInt n1, n2;
8895e3038f0Sstefano_zampini 
8905e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8919e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8929e7b2b25Sstefano_zampini           Mat T;
8939e7b2b25Sstefano_zampini 
8949566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8959566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8969e7b2b25Sstefano_zampini         } else {
8979566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8989e7b2b25Sstefano_zampini         }
8999566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9005e3038f0Sstefano_zampini         if (!n1) continue;
9015e3038f0Sstefano_zampini         if (!rl2g) {
9025e3038f0Sstefano_zampini           rl2g = cl2g;
9035e3038f0Sstefano_zampini         } else {
9045e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9055e3038f0Sstefano_zampini           PetscBool       same;
9065e3038f0Sstefano_zampini 
9079566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
90808401ef6SPierre 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);
9099566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9109566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9119566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9129566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9139566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
91428b400f6SJacob 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);
9155e3038f0Sstefano_zampini         }
9165e3038f0Sstefano_zampini       }
9175e3038f0Sstefano_zampini     }
9185e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9195e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9205e3038f0Sstefano_zampini       rl2g = NULL;
9215e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9225e3038f0Sstefano_zampini         PetscInt n1, n2;
9235e3038f0Sstefano_zampini 
9245e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9259e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9269e7b2b25Sstefano_zampini           Mat T;
9279e7b2b25Sstefano_zampini 
9289566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9299566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9309e7b2b25Sstefano_zampini         } else {
9319566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9329e7b2b25Sstefano_zampini         }
9339566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9345e3038f0Sstefano_zampini         if (!n1) continue;
9355e3038f0Sstefano_zampini         if (!rl2g) {
9365e3038f0Sstefano_zampini           rl2g = cl2g;
9375e3038f0Sstefano_zampini         } else {
9385e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9395e3038f0Sstefano_zampini           PetscBool       same;
9405e3038f0Sstefano_zampini 
9419566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
94208401ef6SPierre 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);
9439566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9449566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9459566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9469566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9479566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
94828b400f6SJacob 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);
9495e3038f0Sstefano_zampini         }
9505e3038f0Sstefano_zampini       }
9515e3038f0Sstefano_zampini     }
95276bd3646SJed Brown   }
9535e3038f0Sstefano_zampini 
9545e3038f0Sstefano_zampini   B = NULL;
9555e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9565b003df0Sstefano_zampini     PetscInt stl;
9575b003df0Sstefano_zampini 
9585e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9595e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9609566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9615b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9625e3038f0Sstefano_zampini       Mat             usedmat;
9635e3038f0Sstefano_zampini       Mat_IS         *matis;
9645e3038f0Sstefano_zampini       const PetscInt *idxs;
9655e3038f0Sstefano_zampini 
9665e3038f0Sstefano_zampini       /* local IS for local NEST */
9679566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9685e3038f0Sstefano_zampini 
9695e3038f0Sstefano_zampini       /* l2gmap */
9705e3038f0Sstefano_zampini       j       = 0;
9715e3038f0Sstefano_zampini       usedmat = nest[i][j];
9729e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
97328b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9749e7b2b25Sstefano_zampini 
9759e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9769e7b2b25Sstefano_zampini         Mat T;
9779566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9789e7b2b25Sstefano_zampini         usedmat = T;
9799e7b2b25Sstefano_zampini       }
980f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9819566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9829e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9839566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9849566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9859e7b2b25Sstefano_zampini       } else {
9869566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9879566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9889e7b2b25Sstefano_zampini       }
9899566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9905e3038f0Sstefano_zampini       stl += lr[i];
9915e3038f0Sstefano_zampini     }
9929566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9935e3038f0Sstefano_zampini 
9945e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9955e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9975b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9985e3038f0Sstefano_zampini       Mat             usedmat;
9995e3038f0Sstefano_zampini       Mat_IS         *matis;
10005e3038f0Sstefano_zampini       const PetscInt *idxs;
10015e3038f0Sstefano_zampini 
10025e3038f0Sstefano_zampini       /* local IS for local NEST */
10039566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10045e3038f0Sstefano_zampini 
10055e3038f0Sstefano_zampini       /* l2gmap */
10065e3038f0Sstefano_zampini       j       = 0;
10075e3038f0Sstefano_zampini       usedmat = nest[j][i];
10089e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100928b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10109e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10119e7b2b25Sstefano_zampini         Mat T;
10129566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10139e7b2b25Sstefano_zampini         usedmat = T;
10149e7b2b25Sstefano_zampini       }
1015f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10169566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10179e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10189566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10199566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10209e7b2b25Sstefano_zampini       } else {
10219566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10229566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10239e7b2b25Sstefano_zampini       }
10249566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10255e3038f0Sstefano_zampini       stl += lc[i];
10265e3038f0Sstefano_zampini     }
10279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10285e3038f0Sstefano_zampini 
10295e3038f0Sstefano_zampini     /* Create MATIS */
10309566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10319566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10329566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10339566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10349566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10359566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10364f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
10378546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1038f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
10398546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10408546b261SStefano Zampini     }
10419566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10449566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10459566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10469e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
104748a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10489e7b2b25Sstefano_zampini     }
10499566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10518546b261SStefano Zampini     { /* hack : setup of scatters done here */
1052f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10538546b261SStefano Zampini 
10548546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10559566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10568546b261SStefano Zampini     }
10579566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10589566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10595e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10609566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10615e3038f0Sstefano_zampini     } else {
10625e3038f0Sstefano_zampini       *newmat = B;
10635e3038f0Sstefano_zampini     }
10645e3038f0Sstefano_zampini   } else {
10655e3038f0Sstefano_zampini     if (lreuse) {
10669566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10675e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10685e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10695e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10709566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
107148a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10725e3038f0Sstefano_zampini           }
10735e3038f0Sstefano_zampini         }
10745e3038f0Sstefano_zampini       }
10755e3038f0Sstefano_zampini     } else {
10765b003df0Sstefano_zampini       PetscInt stl;
10775b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10789566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10795b003df0Sstefano_zampini         stl += lr[i];
10805e3038f0Sstefano_zampini       }
10815b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10829566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10835b003df0Sstefano_zampini         stl += lc[i];
10845e3038f0Sstefano_zampini       }
10859566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1086ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
108748a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1088ab4d48faSStefano Zampini       }
10899566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10909566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10915e3038f0Sstefano_zampini     }
10929566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10939566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10945e3038f0Sstefano_zampini   }
10955e3038f0Sstefano_zampini 
10965b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10975b003df0Sstefano_zampini   convert = PETSC_FALSE;
10984f58015eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
10995b003df0Sstefano_zampini   if (convert) {
11005b003df0Sstefano_zampini     Mat              M;
11015b003df0Sstefano_zampini     MatISLocalFields lf;
11025b003df0Sstefano_zampini     PetscContainer   c;
11035b003df0Sstefano_zampini 
11049566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
11059566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
11069566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
11079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
11085b003df0Sstefano_zampini 
11095b003df0Sstefano_zampini     /* attach local fields to the matrix */
11109566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11125b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11135b003df0Sstefano_zampini       PetscInt n, st;
11145b003df0Sstefano_zampini 
11159566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11169566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11179566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11185b003df0Sstefano_zampini     }
11195b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11205b003df0Sstefano_zampini       PetscInt n, st;
11215b003df0Sstefano_zampini 
11229566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11239566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11249566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11255b003df0Sstefano_zampini     }
11265b003df0Sstefano_zampini     lf->nr = nr;
11275b003df0Sstefano_zampini     lf->nc = nc;
1128f4f49eeaSPierre Jolivet     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)*newmat), &c));
11299566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(c, lf));
11309566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(c, MatISContainerDestroyFields_Private));
1131f4f49eeaSPierre Jolivet     PetscCall(PetscObjectCompose((PetscObject)*newmat, "_convert_nest_lfields", (PetscObject)c));
11329566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&c));
11335b003df0Sstefano_zampini   }
11345b003df0Sstefano_zampini 
11355e3038f0Sstefano_zampini   /* Free workspace */
113648a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
113748a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11389566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11415e3038f0Sstefano_zampini }
11425e3038f0Sstefano_zampini 
1143d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1144d71ae5a4SJacob Faibussowitsch {
1145ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1146ad219c80Sstefano_zampini   Vec                ll, rr;
1147ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1148ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1149ad219c80Sstefano_zampini 
1150ad219c80Sstefano_zampini   PetscFunctionBegin;
1151ad219c80Sstefano_zampini   if (l) {
1152ad219c80Sstefano_zampini     ll = matis->y;
11539566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11549566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11559566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1156ad219c80Sstefano_zampini   } else {
1157ad219c80Sstefano_zampini     ll = NULL;
1158ad219c80Sstefano_zampini   }
1159ad219c80Sstefano_zampini   if (r) {
1160ad219c80Sstefano_zampini     rr = matis->x;
11619566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11629566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11639566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1164ad219c80Sstefano_zampini   } else {
1165ad219c80Sstefano_zampini     rr = NULL;
1166ad219c80Sstefano_zampini   }
1167ad219c80Sstefano_zampini   if (ll) {
11689566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11699566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11709566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1171ad219c80Sstefano_zampini   }
1172ad219c80Sstefano_zampini   if (rr) {
11739566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11749566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11759566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1176ad219c80Sstefano_zampini   }
11779566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1179ad219c80Sstefano_zampini }
1180ad219c80Sstefano_zampini 
1181d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1182d71ae5a4SJacob Faibussowitsch {
11837fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11847fa8f2d3SStefano Zampini   MatInfo        info;
11853966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11867fa8f2d3SStefano Zampini   PetscInt       bs;
11877fa8f2d3SStefano Zampini 
11887fa8f2d3SStefano Zampini   PetscFunctionBegin;
11899566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1190a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11919566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11927fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11937fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11947fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11957fa8f2d3SStefano Zampini     isend[3] = info.memory;
11967fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1197a2ccb5f9Sstefano_zampini   } else {
1198a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1199a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1200a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1201a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1202a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1203a2ccb5f9Sstefano_zampini   }
1204314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
12057fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
12067fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
12077fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
12087fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
12097fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
12107fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1211314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
12127fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
12131c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12147fa8f2d3SStefano Zampini 
12157fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12167fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12177fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12187fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12197fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1220314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12217fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
12221c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12237fa8f2d3SStefano Zampini 
12247fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12257fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12267fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12277fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12287fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12297fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12307fa8f2d3SStefano Zampini   }
12317fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12327fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12337fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12347fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12365e3038f0Sstefano_zampini }
12375e3038f0Sstefano_zampini 
1238d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1239d71ae5a4SJacob Faibussowitsch {
1240d7f69cd0SStefano Zampini   Mat C, lC, lA;
1241d7f69cd0SStefano Zampini 
1242d7f69cd0SStefano Zampini   PetscFunctionBegin;
12437fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1244cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1245cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12464f58015eSStefano Zampini     PetscBool              allow_repeated;
12474f58015eSStefano Zampini 
12489566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12499566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
12509566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
12519566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12524f58015eSStefano Zampini     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
12534f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
12549566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12559566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1256e432b41dSStefano Zampini   } else C = *B;
1257d7f69cd0SStefano Zampini 
1258d7f69cd0SStefano Zampini   /* perform local transposition */
12599566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12609566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12619566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12629566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1264d7f69cd0SStefano Zampini 
1265cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1266d7f69cd0SStefano Zampini     *B = C;
1267d7f69cd0SStefano Zampini   } else {
12689566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1269d7f69cd0SStefano Zampini   }
12709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1273d7f69cd0SStefano Zampini }
1274d7f69cd0SStefano Zampini 
1275d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1276d71ae5a4SJacob Faibussowitsch {
12773fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12783fd1c9e7SStefano Zampini 
12793fd1c9e7SStefano Zampini   PetscFunctionBegin;
12804f58015eSStefano Zampini   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
12814b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12829566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12839566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12843fd1c9e7SStefano Zampini   }
12859566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12869566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12883fd1c9e7SStefano Zampini }
12893fd1c9e7SStefano Zampini 
1290d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1291d71ae5a4SJacob Faibussowitsch {
12924b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12933fd1c9e7SStefano Zampini 
12943fd1c9e7SStefano Zampini   PetscFunctionBegin;
12959566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12969566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12983fd1c9e7SStefano Zampini }
12993fd1c9e7SStefano Zampini 
1300d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1301d71ae5a4SJacob Faibussowitsch {
1302f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1303f26d0771SStefano Zampini 
1304f26d0771SStefano Zampini   PetscFunctionBegin;
1305aed4548fSBarry 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);
13069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
13079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
13089566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1310f26d0771SStefano Zampini }
1311f26d0771SStefano Zampini 
1312d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1313d71ae5a4SJacob Faibussowitsch {
1314f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1315f26d0771SStefano Zampini 
1316f26d0771SStefano Zampini   PetscFunctionBegin;
1317aed4548fSBarry 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);
13189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13209566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1322f26d0771SStefano Zampini }
1323f26d0771SStefano Zampini 
1324d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1325d71ae5a4SJacob Faibussowitsch {
1326a8116848SStefano Zampini   Mat             locmat, newlocmat;
1327a8116848SStefano Zampini   Mat_IS         *newmatis;
1328a8116848SStefano Zampini   const PetscInt *idxs;
1329a8116848SStefano Zampini   PetscInt        i, m, n;
1330a8116848SStefano Zampini 
1331a8116848SStefano Zampini   PetscFunctionBegin;
1332a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1333a8116848SStefano Zampini     PetscBool ismatis;
1334a8116848SStefano Zampini 
13359566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
133628b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1337a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
133828b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
133928b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1340a8116848SStefano Zampini   }
1341a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
134276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
134376bd3646SJed Brown     Vec                rtest, ltest;
134476bd3646SJed Brown     const PetscScalar *array;
134576bd3646SJed Brown 
13469566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13489566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
134948a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13509566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13519566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13529566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13539566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13549566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1355aed4548fSBarry Smith     for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Irow may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i]));
13569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13579566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13589566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13599566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
136048a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13619566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13629566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13639566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13649566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13659566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1366aed4548fSBarry 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]));
13679566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13689566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
137176bd3646SJed Brown   }
1372a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1373a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1374a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1375a8116848SStefano Zampini     IS                     is;
1376a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1377306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
137894342113SStefano Zampini     PetscBool              cong;
1379a8116848SStefano Zampini     MPI_Comm               comm;
1380a8116848SStefano Zampini 
13819566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13829566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13839566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13849566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1385306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1386306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13889566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13899566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13909566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13914f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
13929566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13939566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1394a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13959566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13969566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13989566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1399a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14009566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
14019566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
14029566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14039566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14049371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
14059371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
14069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
14079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
14083d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1409a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1410a8116848SStefano Zampini         lidxs[newloc]      = i;
1411a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1412a8116848SStefano Zampini       }
14139566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14149566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14159566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1417a8116848SStefano Zampini     /* local is to extract local submatrix */
1418a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14199566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14209566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
142194342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14229566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14239566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1424a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1425a8116848SStefano Zampini     } else {
1426a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1427a8116848SStefano Zampini 
1428a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14299566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14309566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14319566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14329566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1433a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14349566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14359566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14369566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14379566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14389371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14399371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14409566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14419566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14423d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1443a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1444a8116848SStefano Zampini           lidxs[newloc]      = i;
1445a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1446a8116848SStefano Zampini         }
14479566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14499566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14509566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1451a8116848SStefano Zampini       /* local is to extract local submatrix */
14529566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14539566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14549566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1455a8116848SStefano Zampini     }
14569566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1457a8116848SStefano Zampini   } else {
14589566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1459a8116848SStefano Zampini   }
14609566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1461a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14629566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1463a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14649566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14659566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1466a8116848SStefano Zampini   }
14679566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14689566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1470a8116848SStefano Zampini }
1471a8116848SStefano Zampini 
1472d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1473d71ae5a4SJacob Faibussowitsch {
14742b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14752b404112SStefano Zampini   PetscBool ismatis;
14762b404112SStefano Zampini 
14772b404112SStefano Zampini   PetscFunctionBegin;
14789566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
147928b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14802b404112SStefano Zampini   b = (Mat_IS *)B->data;
14819566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14829566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14842b404112SStefano Zampini }
14852b404112SStefano Zampini 
1486d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1487d71ae5a4SJacob Faibussowitsch {
1488527b2640SStefano Zampini   Vec                v;
1489527b2640SStefano Zampini   const PetscScalar *array;
1490527b2640SStefano Zampini   PetscInt           i, n;
14916bd84002SStefano Zampini 
14926bd84002SStefano Zampini   PetscFunctionBegin;
1493527b2640SStefano Zampini   *missing = PETSC_FALSE;
14949566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14959566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14969566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14979566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14989371c9d4SSatish Balay   for (i = 0; i < n; i++)
14999371c9d4SSatish Balay     if (array[i] == 0.) break;
15009566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
15019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1502527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1503527b2640SStefano Zampini   if (d) {
1504527b2640SStefano Zampini     *d = -1;
1505527b2640SStefano Zampini     if (*missing) {
1506527b2640SStefano Zampini       PetscInt rstart;
15079566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1508527b2640SStefano Zampini       *d = i + rstart;
1509527b2640SStefano Zampini     }
1510527b2640SStefano Zampini   }
15113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15126bd84002SStefano Zampini }
15136bd84002SStefano Zampini 
1514d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1515d71ae5a4SJacob Faibussowitsch {
1516f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
151728f4e0baSStefano Zampini   const PetscInt *gidxs;
15184f2d7cafSStefano Zampini   PetscInt        nleaves;
151928f4e0baSStefano Zampini 
152028f4e0baSStefano Zampini   PetscFunctionBegin;
15213ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15229566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15259566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1528e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15309566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15329566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1535a8116848SStefano Zampini   } else {
1536a8116848SStefano Zampini     matis->csf          = matis->sf;
1537a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1538a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1539a8116848SStefano Zampini   }
15403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154128f4e0baSStefano Zampini }
15422e1947a5SStefano Zampini 
1543eb82efa4SStefano Zampini /*@
15444f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15454f58015eSStefano Zampini 
15464f58015eSStefano Zampini   Not Collective
15474f58015eSStefano Zampini 
15484f58015eSStefano Zampini   Input Parameter:
15494f58015eSStefano Zampini . A - the matrix
15504f58015eSStefano Zampini 
15514f58015eSStefano Zampini   Output Parameter:
15524f58015eSStefano Zampini . flg - the boolean flag
15534f58015eSStefano Zampini 
15544f58015eSStefano Zampini   Level: intermediate
15554f58015eSStefano Zampini 
15564f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
15574f58015eSStefano Zampini @*/
15584f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
15594f58015eSStefano Zampini {
15604f58015eSStefano Zampini   PetscBool ismatis;
15614f58015eSStefano Zampini 
15624f58015eSStefano Zampini   PetscFunctionBegin;
15634f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15644f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
15654f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
15664f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
15674f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
15684f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15694f58015eSStefano Zampini }
15704f58015eSStefano Zampini 
15714f58015eSStefano Zampini /*@
15724f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
15734f58015eSStefano Zampini 
15744f58015eSStefano Zampini   Logically Collective
15754f58015eSStefano Zampini 
15764f58015eSStefano Zampini   Input Parameters:
15774f58015eSStefano Zampini + A   - the matrix
15784f58015eSStefano Zampini - flg - the boolean flag
15794f58015eSStefano Zampini 
15804f58015eSStefano Zampini   Level: intermediate
15814f58015eSStefano Zampini 
15824f58015eSStefano Zampini   Notes:
15834f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
15844f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
15854f58015eSStefano Zampini   if `flg` is different from the previously set value.
15864f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
15874f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
15884f58015eSStefano Zampini 
15894f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
15904f58015eSStefano Zampini @*/
15914f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
15924f58015eSStefano Zampini {
15934f58015eSStefano Zampini   PetscFunctionBegin;
15944f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15954f58015eSStefano Zampini   PetscValidType(A, 1);
15964f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
15974f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
15984f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15994f58015eSStefano Zampini }
16004f58015eSStefano Zampini 
16014f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
16024f58015eSStefano Zampini {
16034f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
16044f58015eSStefano Zampini   Mat                    lA    = NULL;
16054f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
16064f58015eSStefano Zampini 
16074f58015eSStefano Zampini   PetscFunctionBegin;
16084f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
16094f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
16104f58015eSStefano Zampini     matis->allow_repeated = flg;
16114f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
16124f58015eSStefano Zampini   }
16134f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16144f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16154f58015eSStefano Zampini     lA = matis->A;
16164f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16174f58015eSStefano Zampini   }
16184f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16194f58015eSStefano Zampini   matis->allow_repeated = flg;
16204f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16214f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16224f58015eSStefano Zampini     Mat nA = matis->A;
16234f58015eSStefano Zampini 
16244f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16254f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16264f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16274f58015eSStefano Zampini     } else {
16284f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16294f58015eSStefano Zampini       MatProductType ptype;
16304f58015eSStefano Zampini 
16314f58015eSStefano Zampini       if (lrmap == lcmap) {
16324f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16334f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16344f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16354f58015eSStefano Zampini       } else {
16364f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16374f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16384f58015eSStefano Zampini         if (R && P) {
16394f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16404f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16414f58015eSStefano Zampini         } else if (R) {
16424f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16434f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16444f58015eSStefano Zampini         } else {
16454f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16464f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16474f58015eSStefano Zampini         }
16484f58015eSStefano Zampini       }
16494f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16504f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16514f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16524f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16534f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16544f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16554f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16564f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
16574f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
16584f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
16594f58015eSStefano Zampini     }
16604f58015eSStefano Zampini   }
16614f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
16624f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16634f58015eSStefano Zampini }
16644f58015eSStefano Zampini 
16654f58015eSStefano Zampini /*@
16662ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
166775d48cdbSStefano Zampini 
16684f58015eSStefano Zampini   Logically Collective
166975d48cdbSStefano Zampini 
167075d48cdbSStefano Zampini   Input Parameters:
167175d48cdbSStefano Zampini + A     - the matrix
167275d48cdbSStefano Zampini - store - the boolean flag
167375d48cdbSStefano Zampini 
167475d48cdbSStefano Zampini   Level: advanced
167575d48cdbSStefano Zampini 
16761cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
167775d48cdbSStefano Zampini @*/
1678d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1679d71ae5a4SJacob Faibussowitsch {
168075d48cdbSStefano Zampini   PetscFunctionBegin;
168175d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
168275d48cdbSStefano Zampini   PetscValidType(A, 1);
168375d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1684cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
16853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168675d48cdbSStefano Zampini }
168775d48cdbSStefano Zampini 
1688d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1689d71ae5a4SJacob Faibussowitsch {
1690f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
169175d48cdbSStefano Zampini 
169275d48cdbSStefano Zampini   PetscFunctionBegin;
169375d48cdbSStefano Zampini   matis->storel2l = store;
169448a46eb9SPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)(A), "_MatIS_PtAP_l2l", NULL));
16953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
169675d48cdbSStefano Zampini }
169775d48cdbSStefano Zampini 
169875d48cdbSStefano Zampini /*@
1699f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1700f03112d0SStefano Zampini 
17014f58015eSStefano Zampini   Logically Collective
1702f03112d0SStefano Zampini 
1703f03112d0SStefano Zampini   Input Parameters:
1704f03112d0SStefano Zampini + A   - the matrix
1705f03112d0SStefano Zampini - fix - the boolean flag
1706f03112d0SStefano Zampini 
1707f03112d0SStefano Zampini   Level: advanced
1708f03112d0SStefano Zampini 
170911a5261eSBarry Smith   Note:
17102fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1711f03112d0SStefano Zampini 
17121cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1713f03112d0SStefano Zampini @*/
1714d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1715d71ae5a4SJacob Faibussowitsch {
1716f03112d0SStefano Zampini   PetscFunctionBegin;
1717f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1718f03112d0SStefano Zampini   PetscValidType(A, 1);
1719f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1720cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1722f03112d0SStefano Zampini }
1723f03112d0SStefano Zampini 
1724d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1725d71ae5a4SJacob Faibussowitsch {
1726f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1727f03112d0SStefano Zampini 
1728f03112d0SStefano Zampini   PetscFunctionBegin;
1729f03112d0SStefano Zampini   matis->locempty = fix;
17303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1731f03112d0SStefano Zampini }
1732f03112d0SStefano Zampini 
1733f03112d0SStefano Zampini /*@
173411a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1735a88811baSStefano Zampini 
1736d083f849SBarry Smith   Collective
1737a88811baSStefano Zampini 
1738a88811baSStefano Zampini   Input Parameters:
1739a88811baSStefano Zampini + B     - the matrix
1740a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1741a88811baSStefano Zampini            (same value is used for all local rows)
1742a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1743a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17442ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17452ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1746a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1747a88811baSStefano Zampini            the diagonal entry even if it is zero.
1748a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1749a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1750a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1751a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17522ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1753a88811baSStefano Zampini            structure. The size of this array is equal to the number
17542ef1f0ffSBarry Smith            of local rows, i.e `m`.
1755a88811baSStefano Zampini 
1756a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1757a88811baSStefano Zampini 
1758a88811baSStefano Zampini   Level: intermediate
1759a88811baSStefano Zampini 
176011a5261eSBarry Smith   Note:
176111a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
176211a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1763a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1764a88811baSStefano Zampini 
17651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1766a88811baSStefano Zampini @*/
1767d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1768d71ae5a4SJacob Faibussowitsch {
17692e1947a5SStefano Zampini   PetscFunctionBegin;
17702e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
17712e1947a5SStefano Zampini   PetscValidType(B, 1);
1772cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
17733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17742e1947a5SStefano Zampini }
17752e1947a5SStefano Zampini 
1776844bd0d7SStefano Zampini /* this is used by DMDA */
1777d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1778d71ae5a4SJacob Faibussowitsch {
1779f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
178028f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
17812e1947a5SStefano Zampini 
17822e1947a5SStefano Zampini   PetscFunctionBegin;
17839566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
17849371c9d4SSatish Balay   if (!d_nnz)
17859371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
17869371c9d4SSatish Balay   else
17879371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
17884f2d7cafSStefano Zampini 
17899371c9d4SSatish Balay   if (!o_nnz)
17909371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
17919371c9d4SSatish Balay   else
17929371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
17934f2d7cafSStefano Zampini 
17949566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17959566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
17969566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
17979566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17984f2d7cafSStefano Zampini 
17994f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
18009566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
18010f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
18029566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
18030f2f62c7SStefano Zampini #endif
18044f2d7cafSStefano Zampini 
1805fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1806fc989267SStefano Zampini     PetscInt b;
1807fc989267SStefano Zampini 
1808fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1809ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1810fc989267SStefano Zampini   }
18119566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18124f2d7cafSStefano Zampini 
181300a59248SStefano Zampini   nlocalcols /= bs;
181400a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18159566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18160f2f62c7SStefano Zampini 
18170f2f62c7SStefano Zampini   /* for other matrix types */
18189566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18202e1947a5SStefano Zampini }
1821b4319ba4SBarry Smith 
1822d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1823d71ae5a4SJacob Faibussowitsch {
1824f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
18253927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1826ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
18273927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
18283927de2eSStefano Zampini   PetscInt        lrows, lcols;
18293927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1830f03112d0SStefano Zampini   PetscMPIInt     size;
18313927de2eSStefano Zampini   PetscBool       isdense, issbaij;
18323927de2eSStefano Zampini 
18333927de2eSStefano Zampini   PetscFunctionBegin;
18349566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
18359566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
18369566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
18379566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
18389566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
18399566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
18409566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1841e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
18429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
18430dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1844ecf5a873SStefano Zampini 
18459566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
18463927de2eSStefano Zampini   /*
1847ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
18483927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
18493927de2eSStefano Zampini   */
18509566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1851d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
18523927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
18539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
18549566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1855f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
18565f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
18573927de2eSStefano Zampini   }
18589566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
18593927de2eSStefano Zampini 
18603927de2eSStefano Zampini   /*
18613927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
18623927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
18633927de2eSStefano Zampini   */
18649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
18653927de2eSStefano Zampini   /* preallocation as a MATAIJ */
18663927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
18673927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
186812dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
186912dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1870ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
18713927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
18723927de2eSStefano Zampini           my_dnz[i] += 1;
18733927de2eSStefano Zampini         } else { /* offdiag block */
18743927de2eSStefano Zampini           my_onz[i] += 1;
18753927de2eSStefano Zampini         }
18763927de2eSStefano Zampini       }
18773927de2eSStefano Zampini     }
1878bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1879bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1880bb1015c3SStefano Zampini     PetscBool       done;
18819566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1882f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1883bb1015c3SStefano Zampini     jptr = jj;
1884bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1885bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1886bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1887bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1888bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1889bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1890bb1015c3SStefano Zampini           my_dnz[i] += 1;
1891bb1015c3SStefano Zampini         } else { /* offdiag block */
1892bb1015c3SStefano Zampini           my_onz[i] += 1;
1893bb1015c3SStefano Zampini         }
1894bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1895bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1896bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1897bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1898bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1899bb1015c3SStefano Zampini           } else {
1900bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1901bb1015c3SStefano Zampini           }
1902bb1015c3SStefano Zampini         }
1903bb1015c3SStefano Zampini       }
1904bb1015c3SStefano Zampini     }
19059566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1906f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1907bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
19083927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
19093927de2eSStefano Zampini       const PetscInt *cols;
1910ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
19119566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
19123927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
19133927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1914ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
19153927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
19163927de2eSStefano Zampini           my_dnz[i] += 1;
19173927de2eSStefano Zampini         } else { /* offdiag block */
19183927de2eSStefano Zampini           my_onz[i] += 1;
19193927de2eSStefano Zampini         }
19203927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1921d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
19223927de2eSStefano Zampini           owner = row_ownership[index_col];
19233927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1924d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
19253927de2eSStefano Zampini           } else {
1926d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
19273927de2eSStefano Zampini           }
19283927de2eSStefano Zampini         }
19293927de2eSStefano Zampini       }
19309566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
19313927de2eSStefano Zampini     }
19323927de2eSStefano Zampini   }
193348a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
19349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
19359566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1936ecf5a873SStefano Zampini 
1937ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
19383927de2eSStefano Zampini   if (maxreduce) {
19399566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19409566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19419566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19429566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19433927de2eSStefano Zampini   } else {
19449566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19459566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19469566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19479566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19483927de2eSStefano Zampini   }
19499566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
19503927de2eSStefano Zampini 
19513927de2eSStefano Zampini   /* Resize preallocation if overestimated */
19523927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
19533927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
19543927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
19553927de2eSStefano Zampini   }
19561670daf9Sstefano_zampini 
19571670daf9Sstefano_zampini   /* Set preallocation */
19589566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
19599566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
19609566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
196153b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
196253b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
196353b44cf5SStefano Zampini 
196453b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
196553b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
196653b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
196753b44cf5SStefano Zampini     }
196853b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
196953b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
19703927de2eSStefano Zampini   }
19719566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
19729566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
19739566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1974d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
19759566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
19769566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
19773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19783927de2eSStefano Zampini }
19793927de2eSStefano Zampini 
1980d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1981d71ae5a4SJacob Faibussowitsch {
1982f4f49eeaSPierre Jolivet   Mat_IS            *matis = (Mat_IS *)mat->data;
1983487b449aSStefano Zampini   Mat                local_mat, MT;
198453b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1985b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1986b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1987f03112d0SStefano Zampini   PetscMPIInt        size;
19881683a169SBarry Smith   const PetscScalar *array;
1989b7ce53b6SStefano Zampini 
1990b7ce53b6SStefano Zampini   PetscFunctionBegin;
19919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
19924f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
19931670daf9Sstefano_zampini     Mat      B;
199453b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1995487b449aSStefano Zampini     PetscInt rbs, cbs;
19961670daf9Sstefano_zampini 
19979566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19989566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
199953b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
200053b44cf5SStefano Zampini       IS              rows, cols;
200153b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
20024f58015eSStefano Zampini       PetscInt        i, nw;
20034f58015eSStefano Zampini       PetscBT         work;
200453b44cf5SStefano Zampini 
20059566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
20069566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
200753b44cf5SStefano Zampini       nw = nw / rbs;
20084f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
20094f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
20109371c9d4SSatish Balay       for (i = 0; i < nw; i++)
20114f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
201253b44cf5SStefano Zampini       if (i == nw) {
20139566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
20149566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
20159566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
20169566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
201753b44cf5SStefano Zampini       }
20189566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
20194f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
2020e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
20219566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
20229566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
202353b44cf5SStefano Zampini         nw = nw / cbs;
20244f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
20254f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
20269371c9d4SSatish Balay         for (i = 0; i < nw; i++)
20274f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
202853b44cf5SStefano Zampini         if (i == nw) {
20299566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
20309566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
20319566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
20329566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
203353b44cf5SStefano Zampini         }
20349566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
20354f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
203653b44cf5SStefano Zampini       } else if (irows) {
20379566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
203853b44cf5SStefano Zampini         icols = irows;
203953b44cf5SStefano Zampini       }
204053b44cf5SStefano Zampini     } else {
2041f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
2042f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
20439566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
20449566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
204553b44cf5SStefano Zampini     }
204653b44cf5SStefano Zampini     if (!irows || !icols) {
20479566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
20489566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
204953b44cf5SStefano Zampini       goto general_assembly;
205053b44cf5SStefano Zampini     }
20519566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
2052487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
20539566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
2054f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
2055f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
2056487b449aSStefano Zampini     } else {
2057487b449aSStefano Zampini       Mat C;
2058487b449aSStefano Zampini 
20599566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
20609566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
2061487b449aSStefano Zampini     }
20629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
20639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
20649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
20653ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20667c03b4e8SStefano Zampini   }
206753b44cf5SStefano Zampini general_assembly:
20689566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
20699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
20709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
20719566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
20729566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
20739566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
20749566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
20759566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
20769566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
2077f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
207876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
207976bd3646SJed Brown     PetscBool lb[4], bb[4];
208076bd3646SJed Brown 
2081b9ed4604SStefano Zampini     lb[0] = isseqdense;
2082b9ed4604SStefano Zampini     lb[1] = isseqaij;
2083b9ed4604SStefano Zampini     lb[2] = isseqbaij;
2084b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
20851c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
2086aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
208776bd3646SJed Brown   }
2088b7ce53b6SStefano Zampini 
2089487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
20909566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
20919566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
20929566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
20939566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
20949566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
2095b7ce53b6SStefano Zampini   } else {
209653b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
2097487b449aSStefano Zampini 
2098b7ce53b6SStefano Zampini     /* some checks */
2099487b449aSStefano Zampini     MT = *M;
21009566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
21019566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
21029566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
210308401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
210408401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
210508401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
210608401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
210708401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
210808401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
21099566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
2110b7ce53b6SStefano Zampini   }
2111d9a9e74cSStefano Zampini 
21128546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
21139566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
21148546b261SStefano Zampini     isseqaij = PETSC_TRUE;
2115d9a9e74cSStefano Zampini   } else {
21169566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
2117d9a9e74cSStefano Zampini     local_mat = matis->A;
2118d9a9e74cSStefano Zampini   }
2119686e3a49SStefano Zampini 
2120b7ce53b6SStefano Zampini   /* Set values */
21219566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
2122b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
212365066ba5SStefano Zampini     PetscInt i, *dummy;
2124ecf5a873SStefano Zampini 
21259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
212665066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
21279566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
21289566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
21299566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
21309566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
21319566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
2132686e3a49SStefano Zampini   } else if (isseqaij) {
21336afe12f5SStefano Zampini     const PetscInt *blocks;
21346afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
2135686e3a49SStefano Zampini     PetscBool       done;
21361683a169SBarry Smith     PetscScalar    *sarray;
2137686e3a49SStefano Zampini 
21389566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
213928b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
21409566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
21419566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
21426afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
21436afe12f5SStefano Zampini       PetscInt sum;
21446afe12f5SStefano Zampini 
21456afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
21466afe12f5SStefano Zampini       if (sum == nvtxs) {
21476afe12f5SStefano Zampini         PetscInt r;
21486afe12f5SStefano Zampini 
21496afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
21506bdcaf15SBarry 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]);
21519566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
21526afe12f5SStefano Zampini           r += blocks[i];
21536afe12f5SStefano Zampini         }
21546afe12f5SStefano Zampini       } else {
215548a46eb9SPierre 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));
21566afe12f5SStefano Zampini       }
21576afe12f5SStefano Zampini     } else {
21588e3a54c0SPierre 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));
21596afe12f5SStefano Zampini     }
21609566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
216128b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
21629566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2163686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
21644f58015eSStefano Zampini     for (PetscInt i = 0; i < local_rows; i++) {
2165686e3a49SStefano Zampini       PetscInt        j;
2166ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2167686e3a49SStefano Zampini 
21689566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
21699566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
21709566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2171686e3a49SStefano Zampini     }
2172b7ce53b6SStefano Zampini   }
21739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
21744f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
21759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
21761baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2177487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
21789566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2179487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2180487b449aSStefano Zampini     *M = MT;
2181b7ce53b6SStefano Zampini   }
21823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2183b7ce53b6SStefano Zampini }
2184b7ce53b6SStefano Zampini 
2185d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2186d71ae5a4SJacob Faibussowitsch {
2187f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2188c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2189ad6194a2SStefano Zampini   Mat      B, localmat;
2190ad6194a2SStefano Zampini 
2191ad6194a2SStefano Zampini   PetscFunctionBegin;
21929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
21939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
21949566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
21959566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
21969566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
21979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
21989566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
21999566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
22009566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
22014f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
22029566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
22039566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
22049566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
22059566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
22069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
22079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
22089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2209ad6194a2SStefano Zampini   *newmat = B;
22103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2211ad6194a2SStefano Zampini }
2212ad6194a2SStefano Zampini 
2213d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2214d71ae5a4SJacob Faibussowitsch {
221569796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
221669796d55SStefano Zampini   PetscBool local_sym;
221769796d55SStefano Zampini 
221869796d55SStefano Zampini   PetscFunctionBegin;
22199566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
22201c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
222269796d55SStefano Zampini }
222369796d55SStefano Zampini 
2224d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2225d71ae5a4SJacob Faibussowitsch {
222669796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
222769796d55SStefano Zampini   PetscBool local_sym;
222869796d55SStefano Zampini 
222969796d55SStefano Zampini   PetscFunctionBegin;
2230e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2231e432b41dSStefano Zampini     *flg = PETSC_FALSE;
22323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2233e432b41dSStefano Zampini   }
22349566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
22351c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
223769796d55SStefano Zampini }
223869796d55SStefano Zampini 
2239d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2240d71ae5a4SJacob Faibussowitsch {
224145471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
224245471136SStefano Zampini   PetscBool local_sym;
224345471136SStefano Zampini 
224445471136SStefano Zampini   PetscFunctionBegin;
2245e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
224645471136SStefano Zampini     *flg = PETSC_FALSE;
22473ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
224845471136SStefano Zampini   }
22499566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
22501c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225245471136SStefano Zampini }
225345471136SStefano Zampini 
2254d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2255d71ae5a4SJacob Faibussowitsch {
2256b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2257b4319ba4SBarry Smith 
2258b4319ba4SBarry Smith   PetscFunctionBegin;
22599566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
22609566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
22619566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
22629566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
22639566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
22649566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
22659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
22669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
22679566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
22689566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2269a8116848SStefano Zampini   if (b->sf != b->csf) {
22709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
22719566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2272f03112d0SStefano Zampini   } else b->csf = NULL;
22739566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
22749566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
22759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
22769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2277d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2278d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
22799566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
22809566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
22829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
22839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
22842e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
22859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
22869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
22879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
22889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
22899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
22909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
22919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
22929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
22939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
22949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
22959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
22969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
22979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
22989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
22994f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
23003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2301b4319ba4SBarry Smith }
2302b4319ba4SBarry Smith 
2303d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2304d71ae5a4SJacob Faibussowitsch {
2305b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2306b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2307b4319ba4SBarry Smith 
2308b4319ba4SBarry Smith   PetscFunctionBegin;
2309b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
23109566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
23119566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2312b4319ba4SBarry Smith 
2313b4319ba4SBarry Smith   /* multiply the local matrix */
23149566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2315b4319ba4SBarry Smith 
2316b4319ba4SBarry Smith   /* scatter product back into global memory */
23179566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
23189566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23199566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2321b4319ba4SBarry Smith }
2322b4319ba4SBarry Smith 
2323d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2324d71ae5a4SJacob Faibussowitsch {
2325650997f4SStefano Zampini   Vec temp_vec;
23262e74eeadSLisandro Dalcin 
23272e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2328650997f4SStefano Zampini   if (v3 != v2) {
23299566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
23309566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2331650997f4SStefano Zampini   } else {
23329566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23339566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
23349566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23359566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2337650997f4SStefano Zampini   }
23383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23392e74eeadSLisandro Dalcin }
23402e74eeadSLisandro Dalcin 
2341d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2342d71ae5a4SJacob Faibussowitsch {
23432e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
23442e74eeadSLisandro Dalcin 
2345e176bc59SStefano Zampini   PetscFunctionBegin;
23462e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
23479566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23489566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23492e74eeadSLisandro Dalcin 
23502e74eeadSLisandro Dalcin   /* multiply the local matrix */
23519566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
23522e74eeadSLisandro Dalcin 
23532e74eeadSLisandro Dalcin   /* scatter product back into global vector */
23549566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
23559566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23569566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23582e74eeadSLisandro Dalcin }
23592e74eeadSLisandro Dalcin 
2360d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2361d71ae5a4SJacob Faibussowitsch {
2362650997f4SStefano Zampini   Vec temp_vec;
23632e74eeadSLisandro Dalcin 
23642e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2365650997f4SStefano Zampini   if (v3 != v2) {
23669566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
23679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2368650997f4SStefano Zampini   } else {
23699566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23709566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
23719566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23729566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2374650997f4SStefano Zampini   }
23753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23762e74eeadSLisandro Dalcin }
23772e74eeadSLisandro Dalcin 
2378d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2379d71ae5a4SJacob Faibussowitsch {
2380b4319ba4SBarry Smith   Mat_IS                *a = (Mat_IS *)A->data;
2381b4319ba4SBarry Smith   PetscViewer            sviewer;
23825042aa92SStefano Zampini   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
23835042aa92SStefano Zampini   PetscViewerFormat      format;
23845042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2385b4319ba4SBarry Smith 
2386b4319ba4SBarry Smith   PetscFunctionBegin;
23879566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
23885042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
23899566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
23905042aa92SStefano Zampini   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
23915042aa92SStefano Zampini   if (native) {
23925042aa92SStefano Zampini     rmap = A->rmap->mapping;
23935042aa92SStefano Zampini     cmap = A->cmap->mapping;
23945042aa92SStefano Zampini   } else {
23955042aa92SStefano Zampini     rmap = a->rmapping;
23965042aa92SStefano Zampini     cmap = a->cmapping;
2397ee2491ecSStefano Zampini   }
23985042aa92SStefano Zampini   if (isascii) {
23995042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
24005042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
24015042aa92SStefano Zampini   } else if (isbinary) {
24025042aa92SStefano Zampini     PetscInt    tr[6], nr, nc;
24035042aa92SStefano Zampini     char        lmattype[64] = {'\0'};
24045042aa92SStefano Zampini     PetscMPIInt size;
24055042aa92SStefano Zampini     PetscBool   skipHeader;
24065042aa92SStefano Zampini     IS          is;
24075042aa92SStefano Zampini 
24085042aa92SStefano Zampini     PetscCall(PetscViewerSetUp(viewer));
24095042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
24105042aa92SStefano Zampini     tr[0] = MAT_FILE_CLASSID;
24115042aa92SStefano Zampini     tr[1] = A->rmap->N;
24125042aa92SStefano Zampini     tr[2] = A->cmap->N;
24135042aa92SStefano Zampini     tr[3] = -size; /* AIJ stores nnz here */
24145042aa92SStefano Zampini     tr[4] = (PetscInt)(rmap == cmap);
24155042aa92SStefano Zampini     tr[5] = a->allow_repeated;
24165042aa92SStefano Zampini     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
24175042aa92SStefano Zampini 
24185042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
24195042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
24205042aa92SStefano Zampini 
24215042aa92SStefano Zampini     /* first dump l2g info (we need the header for proper loading on different number of processes) */
24225042aa92SStefano Zampini     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
24235042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
24245042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24255042aa92SStefano Zampini     if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24265042aa92SStefano Zampini 
24275042aa92SStefano Zampini     /* then the sizes of the local matrices */
24285042aa92SStefano Zampini     PetscCall(MatGetSize(a->A, &nr, &nc));
24295042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
24305042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
24315042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
24325042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
24335042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
24345042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
24355042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
24365042aa92SStefano Zampini   }
24375042aa92SStefano Zampini   if (format == PETSC_VIEWER_ASCII_MATLAB) {
24385042aa92SStefano Zampini     char        name[64];
24395042aa92SStefano Zampini     PetscMPIInt size, rank;
24405042aa92SStefano Zampini 
24415042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
24425042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
24435042aa92SStefano Zampini     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
24445042aa92SStefano Zampini     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
24455042aa92SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
24465042aa92SStefano Zampini   }
24475042aa92SStefano Zampini 
24485042aa92SStefano Zampini   /* Dump the local matrices */
24495042aa92SStefano Zampini   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
24505042aa92SStefano Zampini     PetscBool   isaij;
24515042aa92SStefano Zampini     PetscInt    nr, nc;
24525042aa92SStefano Zampini     Mat         lA, B;
24535042aa92SStefano Zampini     Mat_MPIAIJ *b;
24545042aa92SStefano Zampini 
24555042aa92SStefano Zampini     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
24565042aa92SStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
24575042aa92SStefano Zampini     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
24585042aa92SStefano Zampini     else {
24595042aa92SStefano Zampini       PetscCall(PetscObjectReference((PetscObject)a->A));
24605042aa92SStefano Zampini       lA = a->A;
24615042aa92SStefano Zampini     }
24625042aa92SStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
24635042aa92SStefano Zampini     PetscCall(MatSetType(B, MATMPIAIJ));
24645042aa92SStefano Zampini     PetscCall(MatGetSize(lA, &nr, &nc));
24655042aa92SStefano Zampini     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
24665042aa92SStefano Zampini     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
24675042aa92SStefano Zampini 
24685042aa92SStefano Zampini     b = (Mat_MPIAIJ *)B->data;
24695042aa92SStefano Zampini     PetscCall(MatDestroy(&b->A));
24705042aa92SStefano Zampini     b->A = lA;
24715042aa92SStefano Zampini 
24725042aa92SStefano Zampini     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
24735042aa92SStefano Zampini     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
24745042aa92SStefano Zampini     PetscCall(MatView(B, viewer));
24755042aa92SStefano Zampini     PetscCall(MatDestroy(&B));
24765042aa92SStefano Zampini   } else {
24779566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
24789566063dSJacob Faibussowitsch     PetscCall(MatView(a->A, sviewer));
24799566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
24805042aa92SStefano Zampini   }
24815042aa92SStefano Zampini 
24825042aa92SStefano Zampini   /* with ASCII, we dump the l2gmaps at the end */
24835042aa92SStefano Zampini   if (viewl2g) {
24845042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
24855042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
24865042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24875042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
24885042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24895042aa92SStefano Zampini     } else {
24905042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24915042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24925042aa92SStefano Zampini     }
24935042aa92SStefano Zampini   }
24945042aa92SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
24955042aa92SStefano Zampini }
24965042aa92SStefano Zampini 
24975042aa92SStefano Zampini static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
24985042aa92SStefano Zampini {
24995042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
25005042aa92SStefano Zampini   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
25015042aa92SStefano Zampini   PetscBool              isbinary, samel, allow, isbaij;
25025042aa92SStefano Zampini   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
25035042aa92SStefano Zampini   const PetscInt        *idx;
25045042aa92SStefano Zampini   PetscMPIInt            size;
25055042aa92SStefano Zampini   char                   lmattype[64];
25065042aa92SStefano Zampini   Mat                    dA, lA;
25075042aa92SStefano Zampini   IS                     is;
25085042aa92SStefano Zampini 
25095042aa92SStefano Zampini   PetscFunctionBegin;
25105042aa92SStefano Zampini   PetscCheckSameComm(A, 1, viewer, 2);
25115042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
25125042aa92SStefano Zampini   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
25135042aa92SStefano Zampini 
25145042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
25155042aa92SStefano Zampini   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
25165042aa92SStefano Zampini   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25175042aa92SStefano Zampini   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25185042aa92SStefano Zampini   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25195042aa92SStefano Zampini   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25205042aa92SStefano Zampini   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25215042aa92SStefano Zampini   M     = tr[1];
25225042aa92SStefano Zampini   N     = tr[2];
25235042aa92SStefano Zampini   Asize = -tr[3];
25245042aa92SStefano Zampini   samel = (PetscBool)tr[4];
25255042aa92SStefano Zampini   allow = (PetscBool)tr[5];
25265042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
25275042aa92SStefano Zampini 
25285042aa92SStefano Zampini   /* if we are loading from a larger set of processes, allow repeated entries */
25295042aa92SStefano Zampini   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
25305042aa92SStefano Zampini   if (Asize > size) allow = PETSC_TRUE;
25315042aa92SStefano Zampini 
25325042aa92SStefano Zampini   /* set global sizes if not set already */
25335042aa92SStefano Zampini   if (A->rmap->N < 0) A->rmap->N = M;
25345042aa92SStefano Zampini   if (A->cmap->N < 0) A->cmap->N = N;
25355042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->rmap));
25365042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->cmap));
25375042aa92SStefano Zampini   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
25385042aa92SStefano Zampini   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
25395042aa92SStefano Zampini 
25405042aa92SStefano Zampini   /* load l2g maps */
25415042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
25425042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
25435042aa92SStefano Zampini   if (!samel) {
25445042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
25455042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
25465042aa92SStefano Zampini   } else {
25475042aa92SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)rmap));
25485042aa92SStefano Zampini     cmap = rmap;
25495042aa92SStefano Zampini   }
25505042aa92SStefano Zampini 
25515042aa92SStefano Zampini   /* load sizes of local matrices */
25525042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
25535042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
25545042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
25555042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
25565042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
25575042aa92SStefano Zampini   nr = 0;
25585042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
25595042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
25605042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
25615042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
25625042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
25635042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
25645042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
25655042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
25665042aa92SStefano Zampini   nc = 0;
25675042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
25685042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
25695042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
25705042aa92SStefano Zampini 
25715042aa92SStefano Zampini   /* now load the unassembled operator */
25725042aa92SStefano Zampini   PetscCall(MatCreate(comm, &dA));
25735042aa92SStefano Zampini   PetscCall(MatSetType(dA, MATMPIAIJ));
25745042aa92SStefano Zampini   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
25755042aa92SStefano Zampini   PetscCall(MatLoad(dA, viewer));
25765042aa92SStefano Zampini   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
25775042aa92SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)lA));
25785042aa92SStefano Zampini   PetscCall(MatDestroy(&dA));
25795042aa92SStefano Zampini 
25805042aa92SStefano Zampini   /* and convert to the desired format */
25815042aa92SStefano Zampini   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
25825042aa92SStefano Zampini   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
25835042aa92SStefano Zampini   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
25845042aa92SStefano Zampini 
25855042aa92SStefano Zampini   /* assemble the MATIS object */
25865042aa92SStefano Zampini   PetscCall(MatISSetAllowRepeated(A, allow));
25875042aa92SStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
25885042aa92SStefano Zampini   PetscCall(MatISSetLocalMat(A, lA));
25895042aa92SStefano Zampini   PetscCall(MatDestroy(&lA));
25905042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
25915042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
25925042aa92SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
25935042aa92SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
25943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2595b4319ba4SBarry Smith }
2596b4319ba4SBarry Smith 
2597d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2598d71ae5a4SJacob Faibussowitsch {
2599b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2600b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2601b89f26deSStefano Zampini   const PetscScalar *lv;
2602b89f26deSStefano Zampini   PetscInt           bs;
2603b89f26deSStefano Zampini 
2604b89f26deSStefano Zampini   PetscFunctionBegin;
26059566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
26069566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
26079566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
260848a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
26096497c311SBarry Smith   PetscCallMPI(MPI_Type_contiguous((PetscMPIInt)bs, MPIU_SCALAR, &nodeType));
26109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
26119566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
26129566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
26139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2614b89f26deSStefano Zampini   if (values) *values = is->bdiag;
26153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2616b89f26deSStefano Zampini }
2617b89f26deSStefano Zampini 
2618d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2619d71ae5a4SJacob Faibussowitsch {
2620e176bc59SStefano Zampini   Vec             cglobal, rglobal;
26218546b261SStefano Zampini   IS              from;
26228546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2623b89f26deSStefano Zampini   PetscScalar     sum;
26248546b261SStefano Zampini   const PetscInt *garray;
26258546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2626e432b41dSStefano Zampini   VecType         rtype;
2627b4319ba4SBarry Smith 
2628b4319ba4SBarry Smith   PetscFunctionBegin;
26299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
26309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
26319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
26329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
26339566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
26349566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
26359566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
26369566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
26379566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
26389566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
26399566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
26409566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
26419566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
26429566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
26439566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
26449566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
26459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
26469566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
26479566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
26489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
26499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2650e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
26519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
26529566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
26539566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
26549566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
26559566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
26568546b261SStefano Zampini   } else {
26579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
26588546b261SStefano Zampini     is->cctx = is->rctx;
26598546b261SStefano Zampini   }
26609566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2661b89f26deSStefano Zampini 
26628546b261SStefano Zampini   /* interface counter vector (local) */
26639566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
26649566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
26659566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
26669566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26679566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26689566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26699566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26709566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
26719566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2672b89f26deSStefano Zampini 
2673b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
26749566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2675b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2676e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
26779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2678b0cc1f67SStefano Zampini 
2679b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
26809566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
26813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26828546b261SStefano Zampini }
26838546b261SStefano Zampini 
2684d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2685d71ae5a4SJacob Faibussowitsch {
26864f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2687e432b41dSStefano Zampini   IS                         is;
2688e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2689e432b41dSStefano Zampini   const PetscInt            *idxs;
2690e432b41dSStefano Zampini   PetscHSetI                 ht;
2691e432b41dSStefano Zampini   PetscInt                  *nidxs;
2692e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2693e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2694e432b41dSStefano Zampini 
2695e432b41dSStefano Zampini   PetscFunctionBegin;
26969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
26979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
26989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
26999566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
27009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2701e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
27024f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
27039371c9d4SSatish Balay     if (idxs[i] < 0) {
27049371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
27059371c9d4SSatish Balay       continue;
27069371c9d4SSatish Balay     }
27074f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2708e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2709e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2710e432b41dSStefano Zampini   }
27119566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
27121c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2713e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2714e432b41dSStefano Zampini     *nmap = NULL;
2715e432b41dSStefano Zampini     *lmap = NULL;
27169566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
27179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
27183ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2719e432b41dSStefano Zampini   }
2720e432b41dSStefano Zampini 
27214f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
27229566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
27239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
27249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
27259566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
27269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2727e432b41dSStefano Zampini 
27284f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
27299566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
27309566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
27319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
27329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
27339566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
27349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
27353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2736e432b41dSStefano Zampini }
2737e432b41dSStefano Zampini 
2738d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2739d71ae5a4SJacob Faibussowitsch {
27408546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2741e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2742e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
27434f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
27448546b261SStefano Zampini 
27458546b261SStefano Zampini   PetscFunctionBegin;
2746fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2747fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2748e432b41dSStefano Zampini 
27499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
27509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
27519566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
27529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
27539566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2754e432b41dSStefano Zampini 
2755fc989267SStefano Zampini   /* If NULL, local space matches global space */
2756fc989267SStefano Zampini   if (!rmapping) {
2757fc989267SStefano Zampini     IS is;
2758fc989267SStefano Zampini 
27599566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
27609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
27619566063dSJacob Faibussowitsch     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
27629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2763e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2764e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2765e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
27669566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2767e432b41dSStefano Zampini     if (rmapping == cmapping) {
27689566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2769e432b41dSStefano Zampini       is->cmapping = is->rmapping;
27709566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2771e432b41dSStefano Zampini       localcmapping = localrmapping;
2772fc989267SStefano Zampini     }
2773fc989267SStefano Zampini   }
2774fc989267SStefano Zampini   if (!cmapping) {
2775fc989267SStefano Zampini     IS is;
2776fc989267SStefano Zampini 
27779566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
27789566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
27799566063dSJacob Faibussowitsch     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
27809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2781e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2782e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
27839566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2784e432b41dSStefano Zampini   }
2785e432b41dSStefano Zampini   if (!is->rmapping) {
27869566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2787e432b41dSStefano Zampini     is->rmapping = rmapping;
2788e432b41dSStefano Zampini   }
2789e432b41dSStefano Zampini   if (!is->cmapping) {
27909566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2791e432b41dSStefano Zampini     is->cmapping = cmapping;
2792fc989267SStefano Zampini   }
2793fc989267SStefano Zampini 
2794fc989267SStefano Zampini   /* Clean up */
27954f58015eSStefano Zampini   is->lnnzstate = 0;
27964f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
27974f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
27989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2799872cf891SStefano Zampini   if (is->csf != is->sf) {
28009566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
28019566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2802f03112d0SStefano Zampini   } else is->csf = NULL;
28039566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
28049566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
28059566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
28063bbff08aSStefano Zampini 
2807fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2808fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
28099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
28109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
28119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
28129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2813e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2814e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
28156625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
28166625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
28176625354bSStefano Zampini 
28189566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
28199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
28209566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
28219566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
28229566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
28236625354bSStefano Zampini     }
28241c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2825e432b41dSStefano Zampini     if (same) {
28269566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
28279566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2828e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2829e432b41dSStefano Zampini     }
28306625354bSStefano Zampini   }
28319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
28329566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2833e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
28349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
28359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
28369566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
28379566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
28386625354bSStefano Zampini 
28396625354bSStefano Zampini   /* Create the local matrix A */
28409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
28419566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
28429566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
28439566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
28449566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
28459566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
28469566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
28479566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
28489566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
28499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
28509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2851b4319ba4SBarry Smith 
2852fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
28539566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2854fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
28553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2856fc989267SStefano Zampini }
2857fc989267SStefano Zampini 
2858d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2859d71ae5a4SJacob Faibussowitsch {
2860fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2861fc989267SStefano Zampini 
2862fc989267SStefano Zampini   PetscFunctionBegin;
28639566063dSJacob Faibussowitsch   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
286448a46eb9SPierre Jolivet   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
28653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2866b4319ba4SBarry Smith }
2867b4319ba4SBarry Smith 
2868d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2869d71ae5a4SJacob Faibussowitsch {
28702e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2871f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
28722e74eeadSLisandro Dalcin 
28732e74eeadSLisandro Dalcin   PetscFunctionBegin;
28749566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2875e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
28769566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28779566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2878e432b41dSStefano Zampini   } else {
28799566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2880e432b41dSStefano Zampini   }
28813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28822e74eeadSLisandro Dalcin }
28832e74eeadSLisandro Dalcin 
2884d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2885d71ae5a4SJacob Faibussowitsch {
288697563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2887f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
288897563a80SStefano Zampini 
288997563a80SStefano Zampini   PetscFunctionBegin;
28909566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2891e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
289284a95373SStefano Zampini     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28939566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2894e432b41dSStefano Zampini   } else {
289584a95373SStefano Zampini     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2896e432b41dSStefano Zampini   }
28973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
289897563a80SStefano Zampini }
289997563a80SStefano Zampini 
2900d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2901d71ae5a4SJacob Faibussowitsch {
2902b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2903b4319ba4SBarry Smith 
2904b4319ba4SBarry Smith   PetscFunctionBegin;
2905e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
29069566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2907872cf891SStefano Zampini   } else {
29089566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2909872cf891SStefano Zampini   }
29103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2911b4319ba4SBarry Smith }
2912b4319ba4SBarry Smith 
2913d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2914d71ae5a4SJacob Faibussowitsch {
2915f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2916f0006bf2SLisandro Dalcin 
2917f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2918e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
29199566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2920b4f971dfSStefano Zampini   } else {
29219566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2922b4f971dfSStefano Zampini   }
29233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2924f0006bf2SLisandro Dalcin }
2925f0006bf2SLisandro Dalcin 
2926d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2927d71ae5a4SJacob Faibussowitsch {
2928f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2929f0ae7da4SStefano Zampini 
2930f0ae7da4SStefano Zampini   PetscFunctionBegin;
2931f0ae7da4SStefano Zampini   if (!n) {
2932f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2933f0ae7da4SStefano Zampini   } else {
2934f0ae7da4SStefano Zampini     PetscInt i;
2935f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2936f0ae7da4SStefano Zampini 
2937f0ae7da4SStefano Zampini     if (columns) {
29389566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2939f0ae7da4SStefano Zampini     } else {
29409566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2941f0ae7da4SStefano Zampini     }
2942f0ae7da4SStefano Zampini     if (diag != 0.) {
2943f0ae7da4SStefano Zampini       const PetscScalar *array;
29449566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
294548a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
29469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2947f0ae7da4SStefano Zampini     }
29489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
29499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2950f0ae7da4SStefano Zampini   }
29513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2952f0ae7da4SStefano Zampini }
2953f0ae7da4SStefano Zampini 
2954d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2955d71ae5a4SJacob Faibussowitsch {
29566e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
29576e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
29586e520ac8SStefano Zampini   PetscInt *lrows;
29592e74eeadSLisandro Dalcin 
29602e74eeadSLisandro Dalcin   PetscFunctionBegin;
2961cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2962f0ae7da4SStefano Zampini     PetscBool cong;
296326b0207aSStefano Zampini 
29649566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
296526b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
296608401ef6SPierre 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");
2967aed4548fSBarry 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");
2968aed4548fSBarry 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");
2969f0ae7da4SStefano Zampini   }
29706e520ac8SStefano Zampini   /* get locally owned rows */
29719566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2972dd8e379bSPierre Jolivet   /* fix right-hand side if needed */
29736e520ac8SStefano Zampini   if (x && b) {
29746e520ac8SStefano Zampini     const PetscScalar *xx;
29756e520ac8SStefano Zampini     PetscScalar       *bb;
29766e520ac8SStefano Zampini 
29779566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
29789566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
29796e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
29809566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
29819566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
29822e74eeadSLisandro Dalcin   }
29836e520ac8SStefano Zampini   /* get rows associated to the local matrices */
29849566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
29859566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
29869566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
29876e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
29889566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29899566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29909566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
29929371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
29939371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
29949566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
29959566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2996d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2997d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
29983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29992e74eeadSLisandro Dalcin }
30002e74eeadSLisandro Dalcin 
3001d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
3002d71ae5a4SJacob Faibussowitsch {
3003b4319ba4SBarry Smith   PetscFunctionBegin;
30049566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
30053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3006f0ae7da4SStefano Zampini }
30072205254eSKarl Rupp 
3008d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
3009d71ae5a4SJacob Faibussowitsch {
3010f0ae7da4SStefano Zampini   PetscFunctionBegin;
30119566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
30123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3013b4319ba4SBarry Smith }
3014b4319ba4SBarry Smith 
3015d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
3016d71ae5a4SJacob Faibussowitsch {
3017b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
3018b4319ba4SBarry Smith 
3019b4319ba4SBarry Smith   PetscFunctionBegin;
30209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
30213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3022b4319ba4SBarry Smith }
3023b4319ba4SBarry Smith 
3024d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
3025d71ae5a4SJacob Faibussowitsch {
3026b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
3027d0dbe9f7SStefano Zampini   PetscBool lnnz;
3028b4319ba4SBarry Smith 
3029b4319ba4SBarry Smith   PetscFunctionBegin;
30309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
3031872cf891SStefano Zampini   /* fix for local empty rows/cols */
3032872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
3033872cf891SStefano Zampini     Mat                    newlA;
3034f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
3035f03112d0SStefano Zampini     IS                     nzr, nzc;
3036f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
3037f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
3038872cf891SStefano Zampini 
30399566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
30409566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
304148a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
30429566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
304348a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
30449566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
30459566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
3046e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
3047f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
3048712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
3049f03112d0SStefano Zampini 
3050872cf891SStefano Zampini       /* extract valid submatrix */
30519566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
3052f03112d0SStefano Zampini     } else { /* local matrix fully populated */
3053f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
3054712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
30559566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
3056f03112d0SStefano Zampini       newlA = is->A;
3057f03112d0SStefano Zampini     }
3058e432b41dSStefano Zampini 
3059f03112d0SStefano Zampini     /* attach new global l2g map if needed */
3060f03112d0SStefano Zampini     if (newl2g) {
3061e432b41dSStefano Zampini       IS              zr, zc;
3062e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
3063e432b41dSStefano Zampini       PetscInt       *nidxs, i;
3064f03112d0SStefano Zampini 
30659566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
30669566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
30679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
30689566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
30699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
30709566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
30719566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
30729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
30739566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
3074e432b41dSStefano Zampini 
30759566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
3076e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
30779566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
30789566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
3079e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
30809566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
3081e432b41dSStefano Zampini 
30829566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
30839566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
30849566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
30859566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
30869566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
30879566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
30889566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
30899566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
30909566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
30919566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
30929566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30939566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3094f03112d0SStefano Zampini     }
30959566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
30969566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
30979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
30989566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
3099872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
3100f03112d0SStefano Zampini   }
3101d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
3102d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
31034f58015eSStefano Zampini   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
31044f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
31053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3106b4319ba4SBarry Smith }
3107b4319ba4SBarry Smith 
3108d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
3109d71ae5a4SJacob Faibussowitsch {
3110b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
3111b4319ba4SBarry Smith 
3112b4319ba4SBarry Smith   PetscFunctionBegin;
3113b4319ba4SBarry Smith   *local = is->A;
31143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3115b4319ba4SBarry Smith }
3116b4319ba4SBarry Smith 
3117d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
3118d71ae5a4SJacob Faibussowitsch {
31193b3b1effSJed Brown   PetscFunctionBegin;
31203b3b1effSJed Brown   *local = NULL;
31213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31223b3b1effSJed Brown }
31233b3b1effSJed Brown 
3124b4319ba4SBarry Smith /*@
312511a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
3126b4319ba4SBarry Smith 
31274f58015eSStefano Zampini   Not Collective.
31284f58015eSStefano Zampini 
3129b4319ba4SBarry Smith   Input Parameter:
3130b4319ba4SBarry Smith . mat - the matrix
3131b4319ba4SBarry Smith 
3132b4319ba4SBarry Smith   Output Parameter:
3133eb82efa4SStefano Zampini . local - the local matrix
3134b4319ba4SBarry Smith 
31354f58015eSStefano Zampini   Level: intermediate
3136b4319ba4SBarry Smith 
3137b4319ba4SBarry Smith   Notes:
3138b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
3139b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
314011a5261eSBarry Smith   of the `MatSetValues()` operation.
3141b4319ba4SBarry Smith 
314211a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
314396a6f129SJed Brown 
31441cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
3145b4319ba4SBarry Smith @*/
3146d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
3147d71ae5a4SJacob Faibussowitsch {
3148b4319ba4SBarry Smith   PetscFunctionBegin;
31490700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31504f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3151cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
31523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3153b4319ba4SBarry Smith }
3154b4319ba4SBarry Smith 
31553b3b1effSJed Brown /*@
315611a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
31573b3b1effSJed Brown 
31584f58015eSStefano Zampini   Not Collective.
31594f58015eSStefano Zampini 
31602ef1f0ffSBarry Smith   Input Parameters:
31612ef1f0ffSBarry Smith + mat   - the matrix
31622ef1f0ffSBarry Smith - local - the local matrix
31633b3b1effSJed Brown 
31644f58015eSStefano Zampini   Level: intermediate
31653b3b1effSJed Brown 
31661cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
31673b3b1effSJed Brown @*/
3168d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
3169d71ae5a4SJacob Faibussowitsch {
31703b3b1effSJed Brown   PetscFunctionBegin;
31713b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31724f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3173cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
31743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31753b3b1effSJed Brown }
31763b3b1effSJed Brown 
3177d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3178d71ae5a4SJacob Faibussowitsch {
31798546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
31808546b261SStefano Zampini 
31818546b261SStefano Zampini   PetscFunctionBegin;
31821baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
31839566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
31849566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
31853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31868546b261SStefano Zampini }
31878546b261SStefano Zampini 
31885d83a8b1SBarry Smith /*@
318911a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
31908546b261SStefano Zampini 
31914f58015eSStefano Zampini   Logically Collective.
31924f58015eSStefano Zampini 
3193d8d19677SJose E. Roman   Input Parameters:
3194a2b725a8SWilliam Gropp + mat   - the matrix
3195a2b725a8SWilliam Gropp - mtype - the local matrix type
31968546b261SStefano Zampini 
31974f58015eSStefano Zampini   Level: intermediate
31988546b261SStefano Zampini 
31991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
32008546b261SStefano Zampini @*/
3201d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3202d71ae5a4SJacob Faibussowitsch {
32038546b261SStefano Zampini   PetscFunctionBegin;
32048546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3205cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
32063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32078546b261SStefano Zampini }
32088546b261SStefano Zampini 
3209d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3210d71ae5a4SJacob Faibussowitsch {
32113b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
32123b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
32138546b261SStefano Zampini   MatType   mtype, otype;
32148546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
32153b03a366Sstefano_zampini 
32163b03a366Sstefano_zampini   PetscFunctionBegin;
3217e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
32189566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
32199566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
32205042aa92SStefano Zampini     PetscCheck(orows == nrows && ocols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)", orows, ocols, nrows, ncols);
32219566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
32229566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
32239566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
32244e4c7dbeSStefano Zampini   }
32259566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
32269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
32273b03a366Sstefano_zampini   is->A = local;
32289566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
32299566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
323048a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
32314f58015eSStefano Zampini   is->lnnzstate = 0;
32323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32333b03a366Sstefano_zampini }
32343b03a366Sstefano_zampini 
32353b03a366Sstefano_zampini /*@
323611a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
32373b03a366Sstefano_zampini 
32384f58015eSStefano Zampini   Not Collective
32398546b261SStefano Zampini 
3240d8d19677SJose E. Roman   Input Parameters:
3241a2b725a8SWilliam Gropp + mat   - the matrix
3242a2b725a8SWilliam Gropp - local - the local matrix
32433b03a366Sstefano_zampini 
32444f58015eSStefano Zampini   Level: intermediate
324511a5261eSBarry Smith 
32461cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
32473b03a366Sstefano_zampini @*/
3248d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3249d71ae5a4SJacob Faibussowitsch {
32503b03a366Sstefano_zampini   PetscFunctionBegin;
32513b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3252b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3253cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
32543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32553b03a366Sstefano_zampini }
32563b03a366Sstefano_zampini 
3257d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3258d71ae5a4SJacob Faibussowitsch {
32596726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32606726f965SBarry Smith 
32616726f965SBarry Smith   PetscFunctionBegin;
32629566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
32633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32646726f965SBarry Smith }
32656726f965SBarry Smith 
3266d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3267d71ae5a4SJacob Faibussowitsch {
32682e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32692e74eeadSLisandro Dalcin 
32702e74eeadSLisandro Dalcin   PetscFunctionBegin;
32719566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
32723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32732e74eeadSLisandro Dalcin }
32742e74eeadSLisandro Dalcin 
3275d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3276d71ae5a4SJacob Faibussowitsch {
32772e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32782e74eeadSLisandro Dalcin 
32792e74eeadSLisandro Dalcin   PetscFunctionBegin;
32802e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
32819566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
32822e74eeadSLisandro Dalcin 
32832e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
32849566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
32859566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32869566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32882e74eeadSLisandro Dalcin }
32892e74eeadSLisandro Dalcin 
3290d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3291d71ae5a4SJacob Faibussowitsch {
32926726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32936726f965SBarry Smith 
32946726f965SBarry Smith   PetscFunctionBegin;
32959566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
32963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32976726f965SBarry Smith }
32986726f965SBarry Smith 
3299d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3300d71ae5a4SJacob Faibussowitsch {
3301f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3302f26d0771SStefano Zampini   Mat_IS *x;
3303f26d0771SStefano Zampini 
3304f26d0771SStefano Zampini   PetscFunctionBegin;
330576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
330676bd3646SJed Brown     PetscBool ismatis;
33079566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
330828b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
330976bd3646SJed Brown   }
3310f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
33119566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
33123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3313f26d0771SStefano Zampini }
3314f26d0771SStefano Zampini 
3315d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3316d71ae5a4SJacob Faibussowitsch {
3317f26d0771SStefano Zampini   Mat                    lA;
3318f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3319f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3320f26d0771SStefano Zampini   IS                     is;
3321f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3322f26d0771SStefano Zampini   PetscInt               nrg;
3323f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3324f26d0771SStefano Zampini 
3325f26d0771SStefano Zampini   PetscFunctionBegin;
33269566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
33279566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
33289566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
33299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
333076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
333108401ef6SPierre 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);
333276bd3646SJed Brown   }
33339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3334f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3335f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3336f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
33379566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
33389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
33399566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
33409566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
33419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3342f26d0771SStefano Zampini   /* compute new l2g map for columns */
3343e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3344f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3345f26d0771SStefano Zampini     PetscInt        ncg;
3346f26d0771SStefano Zampini     PetscInt        ncl;
3347f26d0771SStefano Zampini 
33489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
33499566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
33509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
33519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
335276bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
335308401ef6SPierre 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);
335476bd3646SJed Brown     }
33559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3356f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3357f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3358f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
33599566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
33609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
33619566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
33629566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
33639566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3364f26d0771SStefano Zampini   } else {
33659566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3366f26d0771SStefano Zampini     cl2g = rl2g;
3367f26d0771SStefano Zampini   }
3368f26d0771SStefano Zampini   /* create the MATIS submatrix */
33699566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
33709566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
33719566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
33729566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3373b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3374f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
33759566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
33769566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
33779566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
33789566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
33799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
33809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
33819566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
33829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3383e432b41dSStefano Zampini 
3384f26d0771SStefano Zampini   /* remove unsupported ops */
33859566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3386f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3387f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3388f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3389f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3390f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
33913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3392f26d0771SStefano Zampini }
3393f26d0771SStefano Zampini 
3394d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject)
3395d71ae5a4SJacob Faibussowitsch {
3396872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
33978546b261SStefano Zampini   char      type[256];
33988546b261SStefano Zampini   PetscBool flg;
3399872cf891SStefano Zampini 
3400872cf891SStefano Zampini   PetscFunctionBegin;
3401d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
34024f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
34034f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
34044f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
34054f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
34064f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
34074f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
34084f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
34094f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
34104f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
34111baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
34121baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3413d0609cedSBarry Smith   PetscOptionsHeadEnd();
34143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3415872cf891SStefano Zampini }
3416872cf891SStefano Zampini 
3417284134d9SBarry Smith /*@
34184f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
34194f58015eSStefano Zampini 
34204f58015eSStefano Zampini   Collective.
3421284134d9SBarry Smith 
3422284134d9SBarry Smith   Input Parameters:
3423284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3424e176bc59SStefano Zampini . bs   - block size of the matrix
34252920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
34262920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
34272920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
34282920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3429e176bc59SStefano Zampini . rmap - local to global map for rows
3430e176bc59SStefano Zampini - cmap - local to global map for cols
3431284134d9SBarry Smith 
3432284134d9SBarry Smith   Output Parameter:
3433284134d9SBarry Smith . A - the resulting matrix
3434284134d9SBarry Smith 
34354f58015eSStefano Zampini   Level: intermediate
34368e6c10adSSatish Balay 
343795452b02SPatrick Sanan   Notes:
34382ef1f0ffSBarry 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
34394f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
344011a5261eSBarry Smith 
34412ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3442284134d9SBarry Smith 
34431cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3444284134d9SBarry Smith @*/
3445d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3446d71ae5a4SJacob Faibussowitsch {
3447284134d9SBarry Smith   PetscFunctionBegin;
34489566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
34499566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
345048a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
34519566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
34529566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
34533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3454284134d9SBarry Smith }
3455284134d9SBarry Smith 
3456d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3457d71ae5a4SJacob Faibussowitsch {
34588b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3459e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
34608b9382cfSStefano Zampini 
34618b9382cfSStefano Zampini   PetscFunctionBegin;
34628b9382cfSStefano Zampini   *has = PETSC_FALSE;
34633ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3464d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
34659371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
34663ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
34679566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
34683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34698b9382cfSStefano Zampini }
34708b9382cfSStefano Zampini 
3471d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3472d71ae5a4SJacob Faibussowitsch {
3473e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3474e432b41dSStefano Zampini 
3475e432b41dSStefano Zampini   PetscFunctionBegin;
34769566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
34779566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
34789566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
34793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3480e432b41dSStefano Zampini }
3481e432b41dSStefano Zampini 
3482d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3483d71ae5a4SJacob Faibussowitsch {
3484e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3485e432b41dSStefano Zampini 
3486e432b41dSStefano Zampini   PetscFunctionBegin;
3487e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3488e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
34899566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3490e432b41dSStefano Zampini   } else {
34919566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3492e432b41dSStefano Zampini   }
34939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3494e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3496e432b41dSStefano Zampini }
3497e432b41dSStefano Zampini 
3498d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3499d71ae5a4SJacob Faibussowitsch {
3500e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3501e432b41dSStefano Zampini 
3502e432b41dSStefano Zampini   PetscFunctionBegin;
3503e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3504*1690c2aeSBarry Smith   PetscCheck(ncoo <= PETSC_INT_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support", ncoo);
35056497c311SBarry Smith   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, (PetscInt)ncoo, coo_i, NULL, coo_i));
35066497c311SBarry Smith   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, (PetscInt)ncoo, coo_j, NULL, coo_j));
3507e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
35089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3509e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
35103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3511e432b41dSStefano Zampini }
3512e432b41dSStefano Zampini 
3513d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3514d71ae5a4SJacob Faibussowitsch {
3515d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3516*1690c2aeSBarry Smith   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
3517*1690c2aeSBarry Smith   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3518d0dbe9f7SStefano Zampini 
3519d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3520d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3521d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3522d0dbe9f7SStefano Zampini   if (a->assembledA) {
3523d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3524d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3525d0dbe9f7SStefano Zampini   }
3526d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3527d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3528d0dbe9f7SStefano Zampini     MatType     aAtype;
3529d0dbe9f7SStefano Zampini     PetscMPIInt size;
3530d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3531d0dbe9f7SStefano Zampini 
3532d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3533d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3534d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3535d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3536d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3537d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3538d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3539d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3540d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3541d0dbe9f7SStefano Zampini 
3542d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3543d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3544d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3545d0dbe9f7SStefano Zampini   }
3546d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3547d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3548d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
35493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3550d0dbe9f7SStefano Zampini }
3551d0dbe9f7SStefano Zampini 
3552d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3553d71ae5a4SJacob Faibussowitsch {
3554d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3555d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3556d0dbe9f7SStefano Zampini   *tA = NULL;
35573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3558d0dbe9f7SStefano Zampini }
3559d0dbe9f7SStefano Zampini 
3560d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3561d71ae5a4SJacob Faibussowitsch {
3562d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
3563*1690c2aeSBarry Smith   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3564d0dbe9f7SStefano Zampini 
3565d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3566d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3567d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3568d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3569d0dbe9f7SStefano Zampini     Mat     tA;
3570d0dbe9f7SStefano Zampini     MatType ltype;
3571d0dbe9f7SStefano Zampini 
3572d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3573d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3574d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3575d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3576d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3577d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3578d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3579d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3580d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3581d0dbe9f7SStefano Zampini   }
3582d0dbe9f7SStefano Zampini   *dA = a->dA;
35833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3584d0dbe9f7SStefano Zampini }
3585d0dbe9f7SStefano Zampini 
3586d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3587d71ae5a4SJacob Faibussowitsch {
3588d0dbe9f7SStefano Zampini   Mat tA;
3589d0dbe9f7SStefano Zampini 
3590d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3591d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3592d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3593d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3594d0dbe9f7SStefano Zampini #if 0
3595d0dbe9f7SStefano Zampini   {
3596d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3597d0dbe9f7SStefano Zampini     MatType   ltype;
3598d0dbe9f7SStefano Zampini     VecType   vtype;
3599d0dbe9f7SStefano Zampini     char      *flg;
3600d0dbe9f7SStefano Zampini 
3601d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3602d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3603d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3604d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3605d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3606d0dbe9f7SStefano Zampini     if (flg) {
3607d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3608d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3609d0dbe9f7SStefano Zampini 
3610d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3611d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3612d0dbe9f7SStefano Zampini       }
3613d0dbe9f7SStefano Zampini     }
3614d0dbe9f7SStefano Zampini   }
3615d0dbe9f7SStefano Zampini #endif
3616d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
36173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3618d0dbe9f7SStefano Zampini }
3619d0dbe9f7SStefano Zampini 
3620d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3621d71ae5a4SJacob Faibussowitsch {
3622d0dbe9f7SStefano Zampini   Mat tA;
3623d0dbe9f7SStefano Zampini 
3624d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3625d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3626d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3627d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
36283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3629d0dbe9f7SStefano Zampini }
3630d0dbe9f7SStefano Zampini 
3631e432b41dSStefano Zampini /*@
363211a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3633e432b41dSStefano Zampini 
3634e432b41dSStefano Zampini   Not Collective
3635e432b41dSStefano Zampini 
3636e432b41dSStefano Zampini   Input Parameter:
3637e432b41dSStefano Zampini . A - the matrix
3638e432b41dSStefano Zampini 
3639e432b41dSStefano Zampini   Output Parameters:
3640e432b41dSStefano Zampini + rmapping - row mapping
3641e432b41dSStefano Zampini - cmapping - column mapping
3642e432b41dSStefano Zampini 
36432ef1f0ffSBarry Smith   Level: advanced
36442ef1f0ffSBarry Smith 
364511a5261eSBarry Smith   Note:
364611a5261eSBarry 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.
3647e432b41dSStefano Zampini 
36481cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatIS`, `MatSetLocalToGlobalMapping()`
3649e432b41dSStefano Zampini @*/
3650d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3651d71ae5a4SJacob Faibussowitsch {
3652e432b41dSStefano Zampini   PetscFunctionBegin;
3653e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3654e432b41dSStefano Zampini   PetscValidType(A, 1);
36554f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
36564f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3657cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
36583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3659e432b41dSStefano Zampini }
3660e432b41dSStefano Zampini 
3661d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3662d71ae5a4SJacob Faibussowitsch {
3663e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3664e432b41dSStefano Zampini 
3665e432b41dSStefano Zampini   PetscFunctionBegin;
3666e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3667e432b41dSStefano Zampini   if (c) *c = a->cmapping;
36683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3669e432b41dSStefano Zampini }
3670e432b41dSStefano Zampini 
3671a50ef18cSStefano Zampini static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3672a50ef18cSStefano Zampini {
3673a50ef18cSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3674a50ef18cSStefano Zampini 
3675a50ef18cSStefano Zampini   PetscFunctionBegin;
3676a50ef18cSStefano Zampini   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3677a50ef18cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
3678a50ef18cSStefano Zampini }
3679a50ef18cSStefano Zampini 
3680b4319ba4SBarry Smith /*MC
36814f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
36824f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3683b4319ba4SBarry Smith 
3684b4319ba4SBarry Smith   Options Database Keys:
36854f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
36864f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
36874f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
36884f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
36892ef1f0ffSBarry Smith 
36904f58015eSStefano Zampini   Level: intermediate
3691b4319ba4SBarry Smith 
369295452b02SPatrick Sanan   Notes:
36932ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3694b4319ba4SBarry Smith 
369511a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3696b4319ba4SBarry Smith 
3697b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
36984f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3699b4319ba4SBarry Smith 
37001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3701b4319ba4SBarry Smith M*/
3702d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3703d71ae5a4SJacob Faibussowitsch {
3704e432b41dSStefano Zampini   Mat_IS *a;
3705b4319ba4SBarry Smith 
3706b4319ba4SBarry Smith   PetscFunctionBegin;
37074dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
37089566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3709e432b41dSStefano Zampini   A->data = (void *)a;
3710b4319ba4SBarry Smith 
3711e176bc59SStefano Zampini   /* matrix ops */
37129566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3713b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
37142e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
37152e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
37162e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3717b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3718b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
37192e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
372098921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3721b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3722f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
37232e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3724f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3725b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3726b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3727b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
37285042aa92SStefano Zampini   A->ops->load                    = MatLoad_IS;
37296726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
37302e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
37312e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
37326726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
373369796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
373469796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
373545471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3736ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
37376bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
37382b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3739659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
37407dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3741f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
37423fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
37433fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3744d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
37457fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3746ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3747872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3748fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
37498b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3750d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3751d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3752d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3753a50ef18cSStefano Zampini   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3754b4319ba4SBarry Smith 
3755b7ce53b6SStefano Zampini   /* special MATIS functions */
37569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
37579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
37589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
37599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
37609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
37614f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
37629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
37639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
37649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
37659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
37669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
37679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
37689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
37699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
37709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
37719566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
37729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
37739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
37749566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
37753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3776b4319ba4SBarry Smith }
3777