xref: /petsc/src/mat/impls/is/matis.c (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
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 
2149abdd8aSBarry Smith static PetscErrorCode MatISContainerDestroyPtAP_Private(void **ptr)
22d71ae5a4SJacob Faibussowitsch {
2349abdd8aSBarry Smith   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));
6457508eceSPierre 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));
10757508eceSPierre Jolivet   } 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));
18549abdd8aSBarry Smith   PetscCall(PetscContainerSetCtxDestroy(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     }
220462c564dSBarry Smith     PetscCallMPI(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 
27249abdd8aSBarry Smith static PetscErrorCode MatISContainerDestroyFields_Private(void **ptr)
273d71ae5a4SJacob Faibussowitsch {
27449abdd8aSBarry Smith   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 
445462c564dSBarry Smith     PetscCallMPI(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:
569835f2295SStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", &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;
78549abdd8aSBarry Smith   for (i = 0; i < 2; i++) PetscCall(PetscObjectContainerCompose((PetscObject)lA, names[i], ptrs[i], PetscCtxDestroyDefault));
786c9225affSStefano Zampini   if (ismpibaij) { /* destroy converted local matrices */
7879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ad));
7889566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Ao));
789c9225affSStefano Zampini   }
7906989cf23SStefano Zampini 
7916989cf23SStefano Zampini   /* finalize matrix */
7929566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, lA));
7939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lA));
7949566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
7959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
796c9225affSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
7979566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
798c9225affSStefano Zampini   } else *newmat = B;
7993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8006989cf23SStefano Zampini }
8016989cf23SStefano Zampini 
802d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
803d71ae5a4SJacob Faibussowitsch {
8045e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8055e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8065e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8075e3038f0Sstefano_zampini   MPI_Comm               comm;
8085b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8095b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8109e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8114f58015eSStefano Zampini   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
8125e3038f0Sstefano_zampini 
813ab4d48faSStefano Zampini   PetscFunctionBegin;
8149566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8155e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8165e3038f0Sstefano_zampini   rnest  = NULL;
8175e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8185e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8195e3038f0Sstefano_zampini 
8209566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
821f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8229566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8239566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8245e3038f0Sstefano_zampini     if (isnest) {
8259566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8265e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8275e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8285e3038f0Sstefano_zampini     }
8295e3038f0Sstefano_zampini   }
8309566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8329566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8339566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8345e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8355e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8364f58015eSStefano Zampini       PetscBool ismatis, sallow;
8379e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8385e3038f0Sstefano_zampini 
8395e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8405e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8415e3038f0Sstefano_zampini 
8425e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
843013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8449e7b2b25Sstefano_zampini       if (istrans[ij]) {
8459e7b2b25Sstefano_zampini         Mat T, lT;
8469566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8479566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
84828b400f6SJacob 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);
8494f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(T, &sallow));
8509566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8519566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8529e7b2b25Sstefano_zampini       } else {
8539566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
85428b400f6SJacob 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);
8554f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
8569566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8579e7b2b25Sstefano_zampini       }
8584f58015eSStefano Zampini       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
8594f58015eSStefano Zampini       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
8605e3038f0Sstefano_zampini 
8615e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8629566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8639566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8645e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
865aed4548fSBarry 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);
866aed4548fSBarry 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);
8675e3038f0Sstefano_zampini       lr[i] = l1;
8685e3038f0Sstefano_zampini       lc[j] = l2;
8695e3038f0Sstefano_zampini 
870da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8715e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8725e3038f0Sstefano_zampini     }
8735e3038f0Sstefano_zampini   }
8745e3038f0Sstefano_zampini 
87576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8765e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8775e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8785e3038f0Sstefano_zampini       rl2g = NULL;
8795e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8805e3038f0Sstefano_zampini         PetscInt n1, n2;
8815e3038f0Sstefano_zampini 
8825e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8839e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8849e7b2b25Sstefano_zampini           Mat T;
8859e7b2b25Sstefano_zampini 
8869566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8879566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8889e7b2b25Sstefano_zampini         } else {
8899566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8909e7b2b25Sstefano_zampini         }
8919566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8925e3038f0Sstefano_zampini         if (!n1) continue;
8935e3038f0Sstefano_zampini         if (!rl2g) {
8945e3038f0Sstefano_zampini           rl2g = cl2g;
8955e3038f0Sstefano_zampini         } else {
8965e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
8975e3038f0Sstefano_zampini           PetscBool       same;
8985e3038f0Sstefano_zampini 
8999566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
90008401ef6SPierre 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);
9019566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9029566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9039566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9049566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9059566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
90628b400f6SJacob 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);
9075e3038f0Sstefano_zampini         }
9085e3038f0Sstefano_zampini       }
9095e3038f0Sstefano_zampini     }
9105e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9115e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9125e3038f0Sstefano_zampini       rl2g = NULL;
9135e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9145e3038f0Sstefano_zampini         PetscInt n1, n2;
9155e3038f0Sstefano_zampini 
9165e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9179e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9189e7b2b25Sstefano_zampini           Mat T;
9199e7b2b25Sstefano_zampini 
9209566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9219566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9229e7b2b25Sstefano_zampini         } else {
9239566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9249e7b2b25Sstefano_zampini         }
9259566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9265e3038f0Sstefano_zampini         if (!n1) continue;
9275e3038f0Sstefano_zampini         if (!rl2g) {
9285e3038f0Sstefano_zampini           rl2g = cl2g;
9295e3038f0Sstefano_zampini         } else {
9305e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9315e3038f0Sstefano_zampini           PetscBool       same;
9325e3038f0Sstefano_zampini 
9339566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
93408401ef6SPierre 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);
9359566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9369566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9379566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9389566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9399566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
94028b400f6SJacob 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);
9415e3038f0Sstefano_zampini         }
9425e3038f0Sstefano_zampini       }
9435e3038f0Sstefano_zampini     }
94476bd3646SJed Brown   }
9455e3038f0Sstefano_zampini 
9465e3038f0Sstefano_zampini   B = NULL;
9475e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9485b003df0Sstefano_zampini     PetscInt stl;
9495b003df0Sstefano_zampini 
9505e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9515e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9535b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9545e3038f0Sstefano_zampini       Mat             usedmat;
9555e3038f0Sstefano_zampini       Mat_IS         *matis;
9565e3038f0Sstefano_zampini       const PetscInt *idxs;
9575e3038f0Sstefano_zampini 
9585e3038f0Sstefano_zampini       /* local IS for local NEST */
9599566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9605e3038f0Sstefano_zampini 
9615e3038f0Sstefano_zampini       /* l2gmap */
9625e3038f0Sstefano_zampini       j       = 0;
9635e3038f0Sstefano_zampini       usedmat = nest[i][j];
9649e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
96528b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9669e7b2b25Sstefano_zampini 
9679e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9689e7b2b25Sstefano_zampini         Mat T;
9699566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9709e7b2b25Sstefano_zampini         usedmat = T;
9719e7b2b25Sstefano_zampini       }
972f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9739566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9749e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9759566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9769566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9779e7b2b25Sstefano_zampini       } else {
9789566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9799566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9809e7b2b25Sstefano_zampini       }
9819566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9825e3038f0Sstefano_zampini       stl += lr[i];
9835e3038f0Sstefano_zampini     }
9849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9855e3038f0Sstefano_zampini 
9865e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9875e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9895b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9905e3038f0Sstefano_zampini       Mat             usedmat;
9915e3038f0Sstefano_zampini       Mat_IS         *matis;
9925e3038f0Sstefano_zampini       const PetscInt *idxs;
9935e3038f0Sstefano_zampini 
9945e3038f0Sstefano_zampini       /* local IS for local NEST */
9959566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
9965e3038f0Sstefano_zampini 
9975e3038f0Sstefano_zampini       /* l2gmap */
9985e3038f0Sstefano_zampini       j       = 0;
9995e3038f0Sstefano_zampini       usedmat = nest[j][i];
10009e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100128b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10029e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10039e7b2b25Sstefano_zampini         Mat T;
10049566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10059e7b2b25Sstefano_zampini         usedmat = T;
10069e7b2b25Sstefano_zampini       }
1007f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10089566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10099e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10109566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10119566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10129e7b2b25Sstefano_zampini       } else {
10139566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10149566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10159e7b2b25Sstefano_zampini       }
10169566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10175e3038f0Sstefano_zampini       stl += lc[i];
10185e3038f0Sstefano_zampini     }
10199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10205e3038f0Sstefano_zampini 
10215e3038f0Sstefano_zampini     /* Create MATIS */
10229566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10239566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10249566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10259566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10269566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10279566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10284f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
10298546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1030f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
10318546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
10328546b261SStefano Zampini     }
10339566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10359566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10369566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10379566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10389e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
103948a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10409e7b2b25Sstefano_zampini     }
10419566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10438546b261SStefano Zampini     { /* hack : setup of scatters done here */
1044f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10458546b261SStefano Zampini 
10468546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
10479566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10488546b261SStefano Zampini     }
10499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10509566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10515e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10529566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10535e3038f0Sstefano_zampini     } else {
10545e3038f0Sstefano_zampini       *newmat = B;
10555e3038f0Sstefano_zampini     }
10565e3038f0Sstefano_zampini   } else {
10575e3038f0Sstefano_zampini     if (lreuse) {
10589566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10595e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10605e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10615e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10629566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
106348a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10645e3038f0Sstefano_zampini           }
10655e3038f0Sstefano_zampini         }
10665e3038f0Sstefano_zampini       }
10675e3038f0Sstefano_zampini     } else {
10685b003df0Sstefano_zampini       PetscInt stl;
10695b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10709566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10715b003df0Sstefano_zampini         stl += lr[i];
10725e3038f0Sstefano_zampini       }
10735b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10749566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10755b003df0Sstefano_zampini         stl += lc[i];
10765e3038f0Sstefano_zampini       }
10779566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1078ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
107948a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1080ab4d48faSStefano Zampini       }
10819566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10829566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10835e3038f0Sstefano_zampini     }
10849566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10859566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10865e3038f0Sstefano_zampini   }
10875e3038f0Sstefano_zampini 
10885b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10895b003df0Sstefano_zampini   convert = PETSC_FALSE;
10904f58015eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
10915b003df0Sstefano_zampini   if (convert) {
10925b003df0Sstefano_zampini     Mat              M;
10935b003df0Sstefano_zampini     MatISLocalFields lf;
10945b003df0Sstefano_zampini 
10959566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
10969566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
10979566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
10989566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
10995b003df0Sstefano_zampini 
11005b003df0Sstefano_zampini     /* attach local fields to the matrix */
11019566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11035b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11045b003df0Sstefano_zampini       PetscInt n, st;
11055b003df0Sstefano_zampini 
11069566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11079566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11089566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11095b003df0Sstefano_zampini     }
11105b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11115b003df0Sstefano_zampini       PetscInt n, st;
11125b003df0Sstefano_zampini 
11139566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11149566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11159566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11165b003df0Sstefano_zampini     }
11175b003df0Sstefano_zampini     lf->nr = nr;
11185b003df0Sstefano_zampini     lf->nc = nc;
111903e76207SPierre Jolivet     PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private));
11205b003df0Sstefano_zampini   }
11215b003df0Sstefano_zampini 
11225e3038f0Sstefano_zampini   /* Free workspace */
112348a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
112448a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11259566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11269566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11285e3038f0Sstefano_zampini }
11295e3038f0Sstefano_zampini 
1130d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1131d71ae5a4SJacob Faibussowitsch {
1132ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1133ad219c80Sstefano_zampini   Vec                ll, rr;
1134ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1135ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1136ad219c80Sstefano_zampini 
1137ad219c80Sstefano_zampini   PetscFunctionBegin;
1138ad219c80Sstefano_zampini   if (l) {
1139ad219c80Sstefano_zampini     ll = matis->y;
11409566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11419566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11429566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1143ad219c80Sstefano_zampini   } else {
1144ad219c80Sstefano_zampini     ll = NULL;
1145ad219c80Sstefano_zampini   }
1146ad219c80Sstefano_zampini   if (r) {
1147ad219c80Sstefano_zampini     rr = matis->x;
11489566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11499566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11509566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1151ad219c80Sstefano_zampini   } else {
1152ad219c80Sstefano_zampini     rr = NULL;
1153ad219c80Sstefano_zampini   }
1154ad219c80Sstefano_zampini   if (ll) {
11559566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11579566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1158ad219c80Sstefano_zampini   }
1159ad219c80Sstefano_zampini   if (rr) {
11609566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11629566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1163ad219c80Sstefano_zampini   }
11649566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1166ad219c80Sstefano_zampini }
1167ad219c80Sstefano_zampini 
1168d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1169d71ae5a4SJacob Faibussowitsch {
11707fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11717fa8f2d3SStefano Zampini   MatInfo        info;
11723966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11737fa8f2d3SStefano Zampini   PetscInt       bs;
11747fa8f2d3SStefano Zampini 
11757fa8f2d3SStefano Zampini   PetscFunctionBegin;
11769566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1177a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11789566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11797fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11807fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11817fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11827fa8f2d3SStefano Zampini     isend[3] = info.memory;
11837fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1184a2ccb5f9Sstefano_zampini   } else {
1185a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1186a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1187a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1188a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1189a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1190a2ccb5f9Sstefano_zampini   }
1191314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
11927fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
11937fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
11947fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
11957fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
11967fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
11977fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1198314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
11997fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
1200462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12017fa8f2d3SStefano Zampini 
12027fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12037fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12047fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12057fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12067fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1207314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12087fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
1209462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12107fa8f2d3SStefano Zampini 
12117fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12127fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12137fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12147fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12157fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12167fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12177fa8f2d3SStefano Zampini   }
12187fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12197fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12207fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12217fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12235e3038f0Sstefano_zampini }
12245e3038f0Sstefano_zampini 
1225d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1226d71ae5a4SJacob Faibussowitsch {
1227d7f69cd0SStefano Zampini   Mat C, lC, lA;
1228d7f69cd0SStefano Zampini 
1229d7f69cd0SStefano Zampini   PetscFunctionBegin;
12307fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1231cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1232cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12334f58015eSStefano Zampini     PetscBool              allow_repeated;
12344f58015eSStefano Zampini 
12359566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12369566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
123758b7e2c1SStefano Zampini     PetscCall(MatSetBlockSizes(C, A->cmap->bs, A->rmap->bs));
12389566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12394f58015eSStefano Zampini     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
12404f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
12419566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12429566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1243e432b41dSStefano Zampini   } else C = *B;
1244d7f69cd0SStefano Zampini 
1245d7f69cd0SStefano Zampini   /* perform local transposition */
12469566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12479566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12489566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12499566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1251d7f69cd0SStefano Zampini 
1252cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1253d7f69cd0SStefano Zampini     *B = C;
1254d7f69cd0SStefano Zampini   } else {
12559566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1256d7f69cd0SStefano Zampini   }
12579566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1260d7f69cd0SStefano Zampini }
1261d7f69cd0SStefano Zampini 
1262d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1263d71ae5a4SJacob Faibussowitsch {
12643fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12653fd1c9e7SStefano Zampini 
12663fd1c9e7SStefano Zampini   PetscFunctionBegin;
12674f58015eSStefano Zampini   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
12684b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12699566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12709566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12713fd1c9e7SStefano Zampini   }
12729566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12739566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12753fd1c9e7SStefano Zampini }
12763fd1c9e7SStefano Zampini 
1277d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1278d71ae5a4SJacob Faibussowitsch {
12794b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12803fd1c9e7SStefano Zampini 
12813fd1c9e7SStefano Zampini   PetscFunctionBegin;
12829566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12839566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12853fd1c9e7SStefano Zampini }
12863fd1c9e7SStefano Zampini 
1287d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1288d71ae5a4SJacob Faibussowitsch {
1289f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1290f26d0771SStefano Zampini 
1291f26d0771SStefano Zampini   PetscFunctionBegin;
1292aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
12939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
12949566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
12959566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
12963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1297f26d0771SStefano Zampini }
1298f26d0771SStefano Zampini 
1299d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1300d71ae5a4SJacob Faibussowitsch {
1301f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1302f26d0771SStefano Zampini 
1303f26d0771SStefano Zampini   PetscFunctionBegin;
1304aed4548fSBarry Smith   PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of row/column block indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT, MATIS_MAX_ENTRIES_INSERTION, m, n);
13059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13079566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1309f26d0771SStefano Zampini }
1310f26d0771SStefano Zampini 
1311d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1312d71ae5a4SJacob Faibussowitsch {
1313a8116848SStefano Zampini   Mat             locmat, newlocmat;
1314a8116848SStefano Zampini   Mat_IS         *newmatis;
1315a8116848SStefano Zampini   const PetscInt *idxs;
1316a8116848SStefano Zampini   PetscInt        i, m, n;
1317a8116848SStefano Zampini 
1318a8116848SStefano Zampini   PetscFunctionBegin;
1319a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1320a8116848SStefano Zampini     PetscBool ismatis;
1321a8116848SStefano Zampini 
13229566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
132328b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1324a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
132528b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
132628b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1327a8116848SStefano Zampini   }
1328a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
132976bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
133076bd3646SJed Brown     Vec                rtest, ltest;
133176bd3646SJed Brown     const PetscScalar *array;
133276bd3646SJed Brown 
13339566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13349566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13359566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
133648a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13389566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13399566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13409566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13419566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1342aed4548fSBarry Smith     for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Irow may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i]));
13439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13449566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13459566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13469566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
134748a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13489566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13499566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13509566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13519566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13529566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1353aed4548fSBarry Smith     for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Icol may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i]));
13549566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13559566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13579566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
135876bd3646SJed Brown   }
1359a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1360a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1361a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1362a8116848SStefano Zampini     IS                     is;
1363a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1364306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
136594342113SStefano Zampini     PetscBool              cong;
1366a8116848SStefano Zampini     MPI_Comm               comm;
1367a8116848SStefano Zampini 
13689566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13699566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13709566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13719566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1372306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1373306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13769566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13779566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13784f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
13799566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13809566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1381a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13829566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13839566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13849566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13859566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1386a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13879566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
13889566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
13899566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13909566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13919371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
13929371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
13939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
13949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
13953d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1396a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1397a8116848SStefano Zampini         lidxs[newloc]      = i;
1398a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1399a8116848SStefano Zampini       }
14009566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1404a8116848SStefano Zampini     /* local is to extract local submatrix */
1405a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14069566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14079566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
140894342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14099566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14109566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1411a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1412a8116848SStefano Zampini     } else {
1413a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1414a8116848SStefano Zampini 
1415a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14169566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14179566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14189566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14199566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1420a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14219566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14229566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14259371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14269371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14279566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14289566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14293d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1430a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1431a8116848SStefano Zampini           lidxs[newloc]      = i;
1432a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1433a8116848SStefano Zampini         }
14349566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14369566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14379566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1438a8116848SStefano Zampini       /* local is to extract local submatrix */
14399566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14409566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1442a8116848SStefano Zampini     }
14439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1444a8116848SStefano Zampini   } else {
14459566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1446a8116848SStefano Zampini   }
14479566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1448a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14499566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1450a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14519566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14529566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1453a8116848SStefano Zampini   }
14549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1457a8116848SStefano Zampini }
1458a8116848SStefano Zampini 
1459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1460d71ae5a4SJacob Faibussowitsch {
14612b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14622b404112SStefano Zampini   PetscBool ismatis;
14632b404112SStefano Zampini 
14642b404112SStefano Zampini   PetscFunctionBegin;
14659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
146628b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14672b404112SStefano Zampini   b = (Mat_IS *)B->data;
14689566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14699566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14712b404112SStefano Zampini }
14722b404112SStefano Zampini 
1473d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1474d71ae5a4SJacob Faibussowitsch {
1475527b2640SStefano Zampini   Vec                v;
1476527b2640SStefano Zampini   const PetscScalar *array;
1477527b2640SStefano Zampini   PetscInt           i, n;
14786bd84002SStefano Zampini 
14796bd84002SStefano Zampini   PetscFunctionBegin;
1480527b2640SStefano Zampini   *missing = PETSC_FALSE;
14819566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14829566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14839566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14849566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14859371c9d4SSatish Balay   for (i = 0; i < n; i++)
14869371c9d4SSatish Balay     if (array[i] == 0.) break;
14879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
14889566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1489527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1490527b2640SStefano Zampini   if (d) {
1491527b2640SStefano Zampini     *d = -1;
1492527b2640SStefano Zampini     if (*missing) {
1493527b2640SStefano Zampini       PetscInt rstart;
14949566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1495527b2640SStefano Zampini       *d = i + rstart;
1496527b2640SStefano Zampini     }
1497527b2640SStefano Zampini   }
14983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14996bd84002SStefano Zampini }
15006bd84002SStefano Zampini 
1501d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1502d71ae5a4SJacob Faibussowitsch {
1503f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
150428f4e0baSStefano Zampini   const PetscInt *gidxs;
15054f2d7cafSStefano Zampini   PetscInt        nleaves;
150628f4e0baSStefano Zampini 
150728f4e0baSStefano Zampini   PetscFunctionBegin;
15083ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15099566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15119566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15129566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1515e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15169566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15179566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15189566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15199566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15209566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1522a8116848SStefano Zampini   } else {
1523a8116848SStefano Zampini     matis->csf          = matis->sf;
1524a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1525a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1526a8116848SStefano Zampini   }
15273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152828f4e0baSStefano Zampini }
15292e1947a5SStefano Zampini 
1530eb82efa4SStefano Zampini /*@
15314f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15324f58015eSStefano Zampini 
15334f58015eSStefano Zampini   Not Collective
15344f58015eSStefano Zampini 
15354f58015eSStefano Zampini   Input Parameter:
15364f58015eSStefano Zampini . A - the matrix
15374f58015eSStefano Zampini 
15384f58015eSStefano Zampini   Output Parameter:
15394f58015eSStefano Zampini . flg - the boolean flag
15404f58015eSStefano Zampini 
15414f58015eSStefano Zampini   Level: intermediate
15424f58015eSStefano Zampini 
15434f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
15444f58015eSStefano Zampini @*/
15454f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
15464f58015eSStefano Zampini {
15474f58015eSStefano Zampini   PetscBool ismatis;
15484f58015eSStefano Zampini 
15494f58015eSStefano Zampini   PetscFunctionBegin;
15504f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15514f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
15524f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
15534f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
15544f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
15554f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15564f58015eSStefano Zampini }
15574f58015eSStefano Zampini 
15584f58015eSStefano Zampini /*@
15594f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
15604f58015eSStefano Zampini 
15614f58015eSStefano Zampini   Logically Collective
15624f58015eSStefano Zampini 
15634f58015eSStefano Zampini   Input Parameters:
15644f58015eSStefano Zampini + A   - the matrix
15654f58015eSStefano Zampini - flg - the boolean flag
15664f58015eSStefano Zampini 
15674f58015eSStefano Zampini   Level: intermediate
15684f58015eSStefano Zampini 
15694f58015eSStefano Zampini   Notes:
15704f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
15714f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
15724f58015eSStefano Zampini   if `flg` is different from the previously set value.
15734f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
15744f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
15754f58015eSStefano Zampini 
15764f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
15774f58015eSStefano Zampini @*/
15784f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
15794f58015eSStefano Zampini {
15804f58015eSStefano Zampini   PetscFunctionBegin;
15814f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15824f58015eSStefano Zampini   PetscValidType(A, 1);
15834f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
15844f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
15854f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15864f58015eSStefano Zampini }
15874f58015eSStefano Zampini 
15884f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
15894f58015eSStefano Zampini {
15904f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
15914f58015eSStefano Zampini   Mat                    lA    = NULL;
15924f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
15934f58015eSStefano Zampini 
15944f58015eSStefano Zampini   PetscFunctionBegin;
15954f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
15964f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
15974f58015eSStefano Zampini     matis->allow_repeated = flg;
15984f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
15994f58015eSStefano Zampini   }
16004f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16014f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16024f58015eSStefano Zampini     lA = matis->A;
16034f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16044f58015eSStefano Zampini   }
16054f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16064f58015eSStefano Zampini   matis->allow_repeated = flg;
16074f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16084f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16094f58015eSStefano Zampini     Mat nA = matis->A;
16104f58015eSStefano Zampini 
16114f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16124f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16134f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16144f58015eSStefano Zampini     } else {
16154f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16164f58015eSStefano Zampini       MatProductType ptype;
16174f58015eSStefano Zampini 
16184f58015eSStefano Zampini       if (lrmap == lcmap) {
16194f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16204f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16214f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16224f58015eSStefano Zampini       } else {
16234f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16244f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16254f58015eSStefano Zampini         if (R && P) {
16264f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16274f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16284f58015eSStefano Zampini         } else if (R) {
16294f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16304f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16314f58015eSStefano Zampini         } else {
16324f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16334f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16344f58015eSStefano Zampini         }
16354f58015eSStefano Zampini       }
16364f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16374f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16384f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16394f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16404f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16414f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16424f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16434f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
16444f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
16454f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
16464f58015eSStefano Zampini     }
16474f58015eSStefano Zampini   }
16484f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
16494f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16504f58015eSStefano Zampini }
16514f58015eSStefano Zampini 
16524f58015eSStefano Zampini /*@
16532ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
165475d48cdbSStefano Zampini 
16554f58015eSStefano Zampini   Logically Collective
165675d48cdbSStefano Zampini 
165775d48cdbSStefano Zampini   Input Parameters:
165875d48cdbSStefano Zampini + A     - the matrix
165975d48cdbSStefano Zampini - store - the boolean flag
166075d48cdbSStefano Zampini 
166175d48cdbSStefano Zampini   Level: advanced
166275d48cdbSStefano Zampini 
16631cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
166475d48cdbSStefano Zampini @*/
1665d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1666d71ae5a4SJacob Faibussowitsch {
166775d48cdbSStefano Zampini   PetscFunctionBegin;
166875d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
166975d48cdbSStefano Zampini   PetscValidType(A, 1);
167075d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1671cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
16723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
167375d48cdbSStefano Zampini }
167475d48cdbSStefano Zampini 
1675d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1676d71ae5a4SJacob Faibussowitsch {
1677f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
167875d48cdbSStefano Zampini 
167975d48cdbSStefano Zampini   PetscFunctionBegin;
168075d48cdbSStefano Zampini   matis->storel2l = store;
168157508eceSPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
16823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168375d48cdbSStefano Zampini }
168475d48cdbSStefano Zampini 
168575d48cdbSStefano Zampini /*@
1686f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1687f03112d0SStefano Zampini 
16884f58015eSStefano Zampini   Logically Collective
1689f03112d0SStefano Zampini 
1690f03112d0SStefano Zampini   Input Parameters:
1691f03112d0SStefano Zampini + A   - the matrix
1692f03112d0SStefano Zampini - fix - the boolean flag
1693f03112d0SStefano Zampini 
1694f03112d0SStefano Zampini   Level: advanced
1695f03112d0SStefano Zampini 
169611a5261eSBarry Smith   Note:
16972fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1698f03112d0SStefano Zampini 
16991cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1700f03112d0SStefano Zampini @*/
1701d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1702d71ae5a4SJacob Faibussowitsch {
1703f03112d0SStefano Zampini   PetscFunctionBegin;
1704f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1705f03112d0SStefano Zampini   PetscValidType(A, 1);
1706f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1707cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1709f03112d0SStefano Zampini }
1710f03112d0SStefano Zampini 
1711d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1712d71ae5a4SJacob Faibussowitsch {
1713f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1714f03112d0SStefano Zampini 
1715f03112d0SStefano Zampini   PetscFunctionBegin;
1716f03112d0SStefano Zampini   matis->locempty = fix;
17173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1718f03112d0SStefano Zampini }
1719f03112d0SStefano Zampini 
1720f03112d0SStefano Zampini /*@
172111a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1722a88811baSStefano Zampini 
1723d083f849SBarry Smith   Collective
1724a88811baSStefano Zampini 
1725a88811baSStefano Zampini   Input Parameters:
1726a88811baSStefano Zampini + B     - the matrix
1727a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1728a88811baSStefano Zampini            (same value is used for all local rows)
1729a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1730a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17312ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17322ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1733a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1734a88811baSStefano Zampini            the diagonal entry even if it is zero.
1735a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1736a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1737a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1738a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17392ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1740a88811baSStefano Zampini            structure. The size of this array is equal to the number
17412ef1f0ffSBarry Smith            of local rows, i.e `m`.
1742a88811baSStefano Zampini 
1743a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1744a88811baSStefano Zampini 
1745a88811baSStefano Zampini   Level: intermediate
1746a88811baSStefano Zampini 
174711a5261eSBarry Smith   Note:
174811a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
174911a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1750a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1751a88811baSStefano Zampini 
17521cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1753a88811baSStefano Zampini @*/
1754d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1755d71ae5a4SJacob Faibussowitsch {
17562e1947a5SStefano Zampini   PetscFunctionBegin;
17572e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
17582e1947a5SStefano Zampini   PetscValidType(B, 1);
1759cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
17603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17612e1947a5SStefano Zampini }
17622e1947a5SStefano Zampini 
1763844bd0d7SStefano Zampini /* this is used by DMDA */
1764d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1765d71ae5a4SJacob Faibussowitsch {
1766f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
176728f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
17682e1947a5SStefano Zampini 
17692e1947a5SStefano Zampini   PetscFunctionBegin;
17709566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
17719371c9d4SSatish Balay   if (!d_nnz)
17729371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
17739371c9d4SSatish Balay   else
17749371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
17754f2d7cafSStefano Zampini 
17769371c9d4SSatish Balay   if (!o_nnz)
17779371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
17789371c9d4SSatish Balay   else
17799371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
17804f2d7cafSStefano Zampini 
17819566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17829566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
17839566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
17849566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17854f2d7cafSStefano Zampini 
17864f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
17879566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
17880f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
17899566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
17900f2f62c7SStefano Zampini #endif
17914f2d7cafSStefano Zampini 
1792fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1793fc989267SStefano Zampini     PetscInt b;
1794fc989267SStefano Zampini 
1795fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1796ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1797fc989267SStefano Zampini   }
17989566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
17994f2d7cafSStefano Zampini 
180000a59248SStefano Zampini   nlocalcols /= bs;
180100a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18029566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18030f2f62c7SStefano Zampini 
18040f2f62c7SStefano Zampini   /* for other matrix types */
18059566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18072e1947a5SStefano Zampini }
1808b4319ba4SBarry Smith 
1809d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1810d71ae5a4SJacob Faibussowitsch {
1811f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)A->data;
18123927de2eSStefano Zampini   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1813ecf5a873SStefano Zampini   const PetscInt *global_indices_r, *global_indices_c;
18143927de2eSStefano Zampini   PetscInt        i, j, bs, rows, cols;
18153927de2eSStefano Zampini   PetscInt        lrows, lcols;
18163927de2eSStefano Zampini   PetscInt        local_rows, local_cols;
1817f03112d0SStefano Zampini   PetscMPIInt     size;
18183927de2eSStefano Zampini   PetscBool       isdense, issbaij;
18193927de2eSStefano Zampini 
18203927de2eSStefano Zampini   PetscFunctionBegin;
18219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
18229566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &rows, &cols));
18239566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
18249566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
18259566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
18269566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
18279566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1828e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
18299566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
18300dfc91b7SStefano Zampini   } else global_indices_c = global_indices_r;
1831ecf5a873SStefano Zampini 
18329566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
18333927de2eSStefano Zampini   /*
1834ecf5a873SStefano Zampini      An SF reduce is needed to sum up properly on shared rows.
18353927de2eSStefano Zampini      Note that generally preallocation is not exact, since it overestimates nonzeros
18363927de2eSStefano Zampini   */
18379566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1838d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
18393927de2eSStefano Zampini   /* All processes need to compute entire row ownership */
18409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rows, &row_ownership));
18419566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1842f03112d0SStefano Zampini   for (i = 0; i < size; i++) {
18435f80ce2aSJacob Faibussowitsch     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
18443927de2eSStefano Zampini   }
18459566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
18463927de2eSStefano Zampini 
18473927de2eSStefano Zampini   /*
18483927de2eSStefano Zampini      my_dnz and my_onz contains exact contribution to preallocation from each local mat
18493927de2eSStefano Zampini      then, they will be summed up properly. This way, preallocation is always sufficient
18503927de2eSStefano Zampini   */
18519566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
18523927de2eSStefano Zampini   /* preallocation as a MATAIJ */
18533927de2eSStefano Zampini   if (isdense) { /* special case for dense local matrices */
18543927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
185512dfadf8SStefano Zampini       PetscInt owner = row_ownership[global_indices_r[i]];
185612dfadf8SStefano Zampini       for (j = 0; j < local_cols; j++) {
1857ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[j];
18583927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
18593927de2eSStefano Zampini           my_dnz[i] += 1;
18603927de2eSStefano Zampini         } else { /* offdiag block */
18613927de2eSStefano Zampini           my_onz[i] += 1;
18623927de2eSStefano Zampini         }
18633927de2eSStefano Zampini       }
18643927de2eSStefano Zampini     }
1865bb1015c3SStefano Zampini   } else if (matis->A->ops->getrowij) {
1866bb1015c3SStefano Zampini     const PetscInt *ii, *jj, *jptr;
1867bb1015c3SStefano Zampini     PetscBool       done;
18689566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1869f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1870bb1015c3SStefano Zampini     jptr = jj;
1871bb1015c3SStefano Zampini     for (i = 0; i < local_rows; i++) {
1872bb1015c3SStefano Zampini       PetscInt index_row = global_indices_r[i];
1873bb1015c3SStefano Zampini       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1874bb1015c3SStefano Zampini         PetscInt owner     = row_ownership[index_row];
1875bb1015c3SStefano Zampini         PetscInt index_col = global_indices_c[*jptr];
1876bb1015c3SStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1877bb1015c3SStefano Zampini           my_dnz[i] += 1;
1878bb1015c3SStefano Zampini         } else { /* offdiag block */
1879bb1015c3SStefano Zampini           my_onz[i] += 1;
1880bb1015c3SStefano Zampini         }
1881bb1015c3SStefano Zampini         /* same as before, interchanging rows and cols */
1882bb1015c3SStefano Zampini         if (issbaij && index_col != index_row) {
1883bb1015c3SStefano Zampini           owner = row_ownership[index_col];
1884bb1015c3SStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1885bb1015c3SStefano Zampini             my_dnz[*jptr] += 1;
1886bb1015c3SStefano Zampini           } else {
1887bb1015c3SStefano Zampini             my_onz[*jptr] += 1;
1888bb1015c3SStefano Zampini           }
1889bb1015c3SStefano Zampini         }
1890bb1015c3SStefano Zampini       }
1891bb1015c3SStefano Zampini     }
18929566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1893f4f49eeaSPierre Jolivet     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1894bb1015c3SStefano Zampini   } else { /* loop over rows and use MatGetRow */
18953927de2eSStefano Zampini     for (i = 0; i < local_rows; i++) {
18963927de2eSStefano Zampini       const PetscInt *cols;
1897ecf5a873SStefano Zampini       PetscInt        ncols, index_row = global_indices_r[i];
18989566063dSJacob Faibussowitsch       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
18993927de2eSStefano Zampini       for (j = 0; j < ncols; j++) {
19003927de2eSStefano Zampini         PetscInt owner     = row_ownership[index_row];
1901ecf5a873SStefano Zampini         PetscInt index_col = global_indices_c[cols[j]];
19023927de2eSStefano Zampini         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
19033927de2eSStefano Zampini           my_dnz[i] += 1;
19043927de2eSStefano Zampini         } else { /* offdiag block */
19053927de2eSStefano Zampini           my_onz[i] += 1;
19063927de2eSStefano Zampini         }
19073927de2eSStefano Zampini         /* same as before, interchanging rows and cols */
1908d9a9e74cSStefano Zampini         if (issbaij && index_col != index_row) {
19093927de2eSStefano Zampini           owner = row_ownership[index_col];
19103927de2eSStefano Zampini           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1911d9a9e74cSStefano Zampini             my_dnz[cols[j]] += 1;
19123927de2eSStefano Zampini           } else {
1913d9a9e74cSStefano Zampini             my_onz[cols[j]] += 1;
19143927de2eSStefano Zampini           }
19153927de2eSStefano Zampini         }
19163927de2eSStefano Zampini       }
19179566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
19183927de2eSStefano Zampini     }
19193927de2eSStefano Zampini   }
192048a46eb9SPierre Jolivet   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
19219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
19229566063dSJacob Faibussowitsch   PetscCall(PetscFree(row_ownership));
1923ecf5a873SStefano Zampini 
1924ecf5a873SStefano Zampini   /* Reduce my_dnz and my_onz */
19253927de2eSStefano Zampini   if (maxreduce) {
19269566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19279566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19289566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
19299566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
19303927de2eSStefano Zampini   } else {
19319566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19329566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19339566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
19349566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
19353927de2eSStefano Zampini   }
19369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(my_dnz, my_onz));
19373927de2eSStefano Zampini 
19383927de2eSStefano Zampini   /* Resize preallocation if overestimated */
19393927de2eSStefano Zampini   for (i = 0; i < lrows; i++) {
19403927de2eSStefano Zampini     dnz[i] = PetscMin(dnz[i], lcols);
19413927de2eSStefano Zampini     onz[i] = PetscMin(onz[i], cols - lcols);
19423927de2eSStefano Zampini   }
19431670daf9Sstefano_zampini 
19441670daf9Sstefano_zampini   /* Set preallocation */
19459566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(B, A, A));
19469566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
19479566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
194853b44cf5SStefano Zampini   for (i = 0; i < lrows; i += bs) {
194953b44cf5SStefano Zampini     PetscInt b, d = dnz[i], o = onz[i];
195053b44cf5SStefano Zampini 
195153b44cf5SStefano Zampini     for (b = 1; b < bs; b++) {
195253b44cf5SStefano Zampini       d = PetscMax(d, dnz[i + b]);
195353b44cf5SStefano Zampini       o = PetscMax(o, onz[i + b]);
195453b44cf5SStefano Zampini     }
195553b44cf5SStefano Zampini     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
195653b44cf5SStefano Zampini     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
19573927de2eSStefano Zampini   }
19589566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
19599566063dSJacob Faibussowitsch   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
19609566063dSJacob Faibussowitsch   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1961d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
19629566063dSJacob Faibussowitsch   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
19639566063dSJacob Faibussowitsch   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
19643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19653927de2eSStefano Zampini }
19663927de2eSStefano Zampini 
1967d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1968d71ae5a4SJacob Faibussowitsch {
1969f4f49eeaSPierre Jolivet   Mat_IS            *matis = (Mat_IS *)mat->data;
1970487b449aSStefano Zampini   Mat                local_mat, MT;
197153b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1972b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1973b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1974f03112d0SStefano Zampini   PetscMPIInt        size;
19751683a169SBarry Smith   const PetscScalar *array;
1976b7ce53b6SStefano Zampini 
1977b7ce53b6SStefano Zampini   PetscFunctionBegin;
19789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
19794f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
19801670daf9Sstefano_zampini     Mat      B;
198153b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1982487b449aSStefano Zampini     PetscInt rbs, cbs;
19831670daf9Sstefano_zampini 
19849566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19859566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
198653b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
198753b44cf5SStefano Zampini       IS              rows, cols;
198853b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
19894f58015eSStefano Zampini       PetscInt        i, nw;
19904f58015eSStefano Zampini       PetscBT         work;
199153b44cf5SStefano Zampini 
19929566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
19939566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
199453b44cf5SStefano Zampini       nw = nw / rbs;
19954f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
19964f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
19979371c9d4SSatish Balay       for (i = 0; i < nw; i++)
19984f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
199953b44cf5SStefano Zampini       if (i == nw) {
20009566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
20019566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
20029566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
20039566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
200453b44cf5SStefano Zampini       }
20059566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
20064f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
2007e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
20089566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
20099566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
201053b44cf5SStefano Zampini         nw = nw / cbs;
20114f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
20124f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
20139371c9d4SSatish Balay         for (i = 0; i < nw; i++)
20144f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
201553b44cf5SStefano Zampini         if (i == nw) {
20169566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
20179566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
20189566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
20199566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
202053b44cf5SStefano Zampini         }
20219566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
20224f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
202353b44cf5SStefano Zampini       } else if (irows) {
20249566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
202553b44cf5SStefano Zampini         icols = irows;
202653b44cf5SStefano Zampini       }
202753b44cf5SStefano Zampini     } else {
2028f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
2029f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
20309566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
20319566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
203253b44cf5SStefano Zampini     }
203353b44cf5SStefano Zampini     if (!irows || !icols) {
20349566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
20359566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
203653b44cf5SStefano Zampini       goto general_assembly;
203753b44cf5SStefano Zampini     }
20389566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
2039487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
20409566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
2041f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
2042f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
2043487b449aSStefano Zampini     } else {
2044487b449aSStefano Zampini       Mat C;
2045487b449aSStefano Zampini 
20469566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
20479566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
2048487b449aSStefano Zampini     }
20499566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
20509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
20519566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
20523ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20537c03b4e8SStefano Zampini   }
205453b44cf5SStefano Zampini general_assembly:
20559566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
20569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
20579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
20589566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
20599566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
20609566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
20619566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
20629566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
20639566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
2064f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
206576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
206676bd3646SJed Brown     PetscBool lb[4], bb[4];
206776bd3646SJed Brown 
2068b9ed4604SStefano Zampini     lb[0] = isseqdense;
2069b9ed4604SStefano Zampini     lb[1] = isseqaij;
2070b9ed4604SStefano Zampini     lb[2] = isseqbaij;
2071b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
2072462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
2073aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
207476bd3646SJed Brown   }
2075b7ce53b6SStefano Zampini 
2076487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
20779566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
20789566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
20799566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
20809566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
20819566063dSJacob Faibussowitsch     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
2082b7ce53b6SStefano Zampini   } else {
208353b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
2084487b449aSStefano Zampini 
2085b7ce53b6SStefano Zampini     /* some checks */
2086487b449aSStefano Zampini     MT = *M;
20879566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
20889566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
20899566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
209008401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
209108401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
209208401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
209308401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
209408401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
209508401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
20969566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
2097b7ce53b6SStefano Zampini   }
2098d9a9e74cSStefano Zampini 
20998546b261SStefano Zampini   if (isseqsbaij || isseqbaij) {
21009566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
21018546b261SStefano Zampini     isseqaij = PETSC_TRUE;
2102d9a9e74cSStefano Zampini   } else {
21039566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)matis->A));
2104d9a9e74cSStefano Zampini     local_mat = matis->A;
2105d9a9e74cSStefano Zampini   }
2106686e3a49SStefano Zampini 
2107b7ce53b6SStefano Zampini   /* Set values */
21089566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
2109b9ed4604SStefano Zampini   if (isseqdense) { /* special case for dense local matrices */
211065066ba5SStefano Zampini     PetscInt i, *dummy;
2111ecf5a873SStefano Zampini 
21129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
211365066ba5SStefano Zampini     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
21149566063dSJacob Faibussowitsch     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
21159566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
21169566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
21179566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
21189566063dSJacob Faibussowitsch     PetscCall(PetscFree(dummy));
2119686e3a49SStefano Zampini   } else if (isseqaij) {
21206afe12f5SStefano Zampini     const PetscInt *blocks;
21216afe12f5SStefano Zampini     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
2122686e3a49SStefano Zampini     PetscBool       done;
21231683a169SBarry Smith     PetscScalar    *sarray;
2124686e3a49SStefano Zampini 
21259566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
212628b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
21279566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
21289566063dSJacob Faibussowitsch     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
21296afe12f5SStefano Zampini     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
21306afe12f5SStefano Zampini       PetscInt sum;
21316afe12f5SStefano Zampini 
21326afe12f5SStefano Zampini       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
21336afe12f5SStefano Zampini       if (sum == nvtxs) {
21346afe12f5SStefano Zampini         PetscInt r;
21356afe12f5SStefano Zampini 
21366afe12f5SStefano Zampini         for (i = 0, r = 0; i < nb; i++) {
21376bdcaf15SBarry 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]);
21389566063dSJacob Faibussowitsch           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
21396afe12f5SStefano Zampini           r += blocks[i];
21406afe12f5SStefano Zampini         }
21416afe12f5SStefano Zampini       } else {
214248a46eb9SPierre 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));
21436afe12f5SStefano Zampini       }
21446afe12f5SStefano Zampini     } else {
21458e3a54c0SPierre 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));
21466afe12f5SStefano Zampini     }
21479566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
214828b400f6SJacob Faibussowitsch     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
21499566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2150686e3a49SStefano Zampini   } else { /* very basic values insertion for all other matrix types */
21514f58015eSStefano Zampini     for (PetscInt i = 0; i < local_rows; i++) {
2152686e3a49SStefano Zampini       PetscInt        j;
2153ecf5a873SStefano Zampini       const PetscInt *local_indices_cols;
2154686e3a49SStefano Zampini 
21559566063dSJacob Faibussowitsch       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
21569566063dSJacob Faibussowitsch       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
21579566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2158686e3a49SStefano Zampini     }
2159b7ce53b6SStefano Zampini   }
21609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
21614f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
21629566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
21631baa6e33SBarry Smith   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2164487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
21659566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2166487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2167487b449aSStefano Zampini     *M = MT;
2168b7ce53b6SStefano Zampini   }
21693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2170b7ce53b6SStefano Zampini }
2171b7ce53b6SStefano Zampini 
2172d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2173d71ae5a4SJacob Faibussowitsch {
2174f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2175c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2176ad6194a2SStefano Zampini   Mat      B, localmat;
2177ad6194a2SStefano Zampini 
2178ad6194a2SStefano Zampini   PetscFunctionBegin;
21799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
21809566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
21819566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
21829566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
21839566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
21849566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
21859566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
21869566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
21879566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
21884f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
21899566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
21909566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
21919566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
21929566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
21939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
21949566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
21959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2196ad6194a2SStefano Zampini   *newmat = B;
21973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2198ad6194a2SStefano Zampini }
2199ad6194a2SStefano Zampini 
2200d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2201d71ae5a4SJacob Faibussowitsch {
220269796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
220369796d55SStefano Zampini   PetscBool local_sym;
220469796d55SStefano Zampini 
220569796d55SStefano Zampini   PetscFunctionBegin;
22069566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
2207462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
220969796d55SStefano Zampini }
221069796d55SStefano Zampini 
2211d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2212d71ae5a4SJacob Faibussowitsch {
221369796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
221469796d55SStefano Zampini   PetscBool local_sym;
221569796d55SStefano Zampini 
221669796d55SStefano Zampini   PetscFunctionBegin;
2217e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2218e432b41dSStefano Zampini     *flg = PETSC_FALSE;
22193ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2220e432b41dSStefano Zampini   }
22219566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
2222462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
222469796d55SStefano Zampini }
222569796d55SStefano Zampini 
2226d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2227d71ae5a4SJacob Faibussowitsch {
222845471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
222945471136SStefano Zampini   PetscBool local_sym;
223045471136SStefano Zampini 
223145471136SStefano Zampini   PetscFunctionBegin;
2232e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
223345471136SStefano Zampini     *flg = PETSC_FALSE;
22343ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
223545471136SStefano Zampini   }
22369566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
2237462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
22383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
223945471136SStefano Zampini }
224045471136SStefano Zampini 
2241d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2242d71ae5a4SJacob Faibussowitsch {
2243b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2244b4319ba4SBarry Smith 
2245b4319ba4SBarry Smith   PetscFunctionBegin;
22469566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
22479566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
22489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
22499566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
22509566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
22519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
22529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
22539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
22549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
22559566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2256a8116848SStefano Zampini   if (b->sf != b->csf) {
22579566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
22589566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2259f03112d0SStefano Zampini   } else b->csf = NULL;
22609566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
22619566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
22629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
22639566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2264d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2265d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
22669566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
22679566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
22689566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
22699566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
22709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
22712e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
22729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
22739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
22749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
22759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
22769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
22779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
22789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
22799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
22809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
22819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
22829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
22839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
22849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
22859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
22864f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
22873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2288b4319ba4SBarry Smith }
2289b4319ba4SBarry Smith 
2290d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2291d71ae5a4SJacob Faibussowitsch {
2292b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2293b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2294b4319ba4SBarry Smith 
2295b4319ba4SBarry Smith   PetscFunctionBegin;
2296b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
22979566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
22989566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2299b4319ba4SBarry Smith 
2300b4319ba4SBarry Smith   /* multiply the local matrix */
23019566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2302b4319ba4SBarry Smith 
2303b4319ba4SBarry Smith   /* scatter product back into global memory */
23049566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
23059566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23069566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
23073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2308b4319ba4SBarry Smith }
2309b4319ba4SBarry Smith 
2310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2311d71ae5a4SJacob Faibussowitsch {
2312650997f4SStefano Zampini   Vec temp_vec;
23132e74eeadSLisandro Dalcin 
23142e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2315650997f4SStefano Zampini   if (v3 != v2) {
23169566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
23179566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2318650997f4SStefano Zampini   } else {
23199566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23209566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
23219566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23229566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2324650997f4SStefano Zampini   }
23253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23262e74eeadSLisandro Dalcin }
23272e74eeadSLisandro Dalcin 
2328d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2329d71ae5a4SJacob Faibussowitsch {
23302e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
23312e74eeadSLisandro Dalcin 
2332e176bc59SStefano Zampini   PetscFunctionBegin;
23332e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
23349566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23359566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
23362e74eeadSLisandro Dalcin 
23372e74eeadSLisandro Dalcin   /* multiply the local matrix */
23389566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
23392e74eeadSLisandro Dalcin 
23402e74eeadSLisandro Dalcin   /* scatter product back into global vector */
23419566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
23429566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23439566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
23443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23452e74eeadSLisandro Dalcin }
23462e74eeadSLisandro Dalcin 
2347d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2348d71ae5a4SJacob Faibussowitsch {
2349650997f4SStefano Zampini   Vec temp_vec;
23502e74eeadSLisandro Dalcin 
23512e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2352650997f4SStefano Zampini   if (v3 != v2) {
23539566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
23549566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2355650997f4SStefano Zampini   } else {
23569566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
23579566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
23589566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
23599566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
23609566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2361650997f4SStefano Zampini   }
23623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23632e74eeadSLisandro Dalcin }
23642e74eeadSLisandro Dalcin 
2365d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2366d71ae5a4SJacob Faibussowitsch {
2367b4319ba4SBarry Smith   Mat_IS                *a = (Mat_IS *)A->data;
2368b4319ba4SBarry Smith   PetscViewer            sviewer;
23695042aa92SStefano Zampini   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
23705042aa92SStefano Zampini   PetscViewerFormat      format;
23715042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2372b4319ba4SBarry Smith 
2373b4319ba4SBarry Smith   PetscFunctionBegin;
23749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
23755042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
23769566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
23775042aa92SStefano Zampini   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
23785042aa92SStefano Zampini   if (native) {
23795042aa92SStefano Zampini     rmap = A->rmap->mapping;
23805042aa92SStefano Zampini     cmap = A->cmap->mapping;
23815042aa92SStefano Zampini   } else {
23825042aa92SStefano Zampini     rmap = a->rmapping;
23835042aa92SStefano Zampini     cmap = a->cmapping;
2384ee2491ecSStefano Zampini   }
23855042aa92SStefano Zampini   if (isascii) {
23865042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
23875042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
23885042aa92SStefano Zampini   } else if (isbinary) {
23895042aa92SStefano Zampini     PetscInt    tr[6], nr, nc;
23905042aa92SStefano Zampini     char        lmattype[64] = {'\0'};
23915042aa92SStefano Zampini     PetscMPIInt size;
23925042aa92SStefano Zampini     PetscBool   skipHeader;
23935042aa92SStefano Zampini     IS          is;
23945042aa92SStefano Zampini 
23955042aa92SStefano Zampini     PetscCall(PetscViewerSetUp(viewer));
23965042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
23975042aa92SStefano Zampini     tr[0] = MAT_FILE_CLASSID;
23985042aa92SStefano Zampini     tr[1] = A->rmap->N;
23995042aa92SStefano Zampini     tr[2] = A->cmap->N;
24005042aa92SStefano Zampini     tr[3] = -size; /* AIJ stores nnz here */
24015042aa92SStefano Zampini     tr[4] = (PetscInt)(rmap == cmap);
24025042aa92SStefano Zampini     tr[5] = a->allow_repeated;
24035042aa92SStefano Zampini     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
24045042aa92SStefano Zampini 
24055042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
24065042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
24075042aa92SStefano Zampini 
24085042aa92SStefano Zampini     /* first dump l2g info (we need the header for proper loading on different number of processes) */
24095042aa92SStefano Zampini     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
24105042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
24115042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24125042aa92SStefano Zampini     if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24135042aa92SStefano Zampini 
24145042aa92SStefano Zampini     /* then the sizes of the local matrices */
24155042aa92SStefano Zampini     PetscCall(MatGetSize(a->A, &nr, &nc));
24165042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
24175042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
24185042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
24195042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
24205042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
24215042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
24225042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
24235042aa92SStefano Zampini   }
24245042aa92SStefano Zampini   if (format == PETSC_VIEWER_ASCII_MATLAB) {
24255042aa92SStefano Zampini     char        name[64];
24265042aa92SStefano Zampini     PetscMPIInt size, rank;
24275042aa92SStefano Zampini 
24285042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
24295042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
24305042aa92SStefano Zampini     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
24315042aa92SStefano Zampini     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
24325042aa92SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
24335042aa92SStefano Zampini   }
24345042aa92SStefano Zampini 
24355042aa92SStefano Zampini   /* Dump the local matrices */
24365042aa92SStefano Zampini   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
24375042aa92SStefano Zampini     PetscBool   isaij;
24385042aa92SStefano Zampini     PetscInt    nr, nc;
24395042aa92SStefano Zampini     Mat         lA, B;
24405042aa92SStefano Zampini     Mat_MPIAIJ *b;
24415042aa92SStefano Zampini 
24425042aa92SStefano Zampini     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
24435042aa92SStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
24445042aa92SStefano Zampini     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
24455042aa92SStefano Zampini     else {
24465042aa92SStefano Zampini       PetscCall(PetscObjectReference((PetscObject)a->A));
24475042aa92SStefano Zampini       lA = a->A;
24485042aa92SStefano Zampini     }
24495042aa92SStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
24505042aa92SStefano Zampini     PetscCall(MatSetType(B, MATMPIAIJ));
24515042aa92SStefano Zampini     PetscCall(MatGetSize(lA, &nr, &nc));
24525042aa92SStefano Zampini     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
24535042aa92SStefano Zampini     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
24545042aa92SStefano Zampini 
24555042aa92SStefano Zampini     b = (Mat_MPIAIJ *)B->data;
24565042aa92SStefano Zampini     PetscCall(MatDestroy(&b->A));
24575042aa92SStefano Zampini     b->A = lA;
24585042aa92SStefano Zampini 
24595042aa92SStefano Zampini     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
24605042aa92SStefano Zampini     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
24615042aa92SStefano Zampini     PetscCall(MatView(B, viewer));
24625042aa92SStefano Zampini     PetscCall(MatDestroy(&B));
24635042aa92SStefano Zampini   } else {
24649566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
24659566063dSJacob Faibussowitsch     PetscCall(MatView(a->A, sviewer));
24669566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
24675042aa92SStefano Zampini   }
24685042aa92SStefano Zampini 
24695042aa92SStefano Zampini   /* with ASCII, we dump the l2gmaps at the end */
24705042aa92SStefano Zampini   if (viewl2g) {
24715042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
24725042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
24735042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24745042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
24755042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24765042aa92SStefano Zampini     } else {
24775042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
24785042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
24795042aa92SStefano Zampini     }
24805042aa92SStefano Zampini   }
24815042aa92SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
24825042aa92SStefano Zampini }
24835042aa92SStefano Zampini 
24845042aa92SStefano Zampini static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
24855042aa92SStefano Zampini {
24865042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
24875042aa92SStefano Zampini   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
24885042aa92SStefano Zampini   PetscBool              isbinary, samel, allow, isbaij;
24895042aa92SStefano Zampini   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
24905042aa92SStefano Zampini   const PetscInt        *idx;
24915042aa92SStefano Zampini   PetscMPIInt            size;
24925042aa92SStefano Zampini   char                   lmattype[64];
24935042aa92SStefano Zampini   Mat                    dA, lA;
24945042aa92SStefano Zampini   IS                     is;
24955042aa92SStefano Zampini 
24965042aa92SStefano Zampini   PetscFunctionBegin;
24975042aa92SStefano Zampini   PetscCheckSameComm(A, 1, viewer, 2);
24985042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
24995042aa92SStefano Zampini   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
25005042aa92SStefano Zampini 
25015042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
25025042aa92SStefano Zampini   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
25035042aa92SStefano Zampini   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25045042aa92SStefano Zampini   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25055042aa92SStefano Zampini   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25065042aa92SStefano Zampini   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25075042aa92SStefano Zampini   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
25085042aa92SStefano Zampini   M     = tr[1];
25095042aa92SStefano Zampini   N     = tr[2];
25105042aa92SStefano Zampini   Asize = -tr[3];
25115042aa92SStefano Zampini   samel = (PetscBool)tr[4];
25125042aa92SStefano Zampini   allow = (PetscBool)tr[5];
25135042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
25145042aa92SStefano Zampini 
25155042aa92SStefano Zampini   /* if we are loading from a larger set of processes, allow repeated entries */
25165042aa92SStefano Zampini   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
25175042aa92SStefano Zampini   if (Asize > size) allow = PETSC_TRUE;
25185042aa92SStefano Zampini 
25195042aa92SStefano Zampini   /* set global sizes if not set already */
25205042aa92SStefano Zampini   if (A->rmap->N < 0) A->rmap->N = M;
25215042aa92SStefano Zampini   if (A->cmap->N < 0) A->cmap->N = N;
25225042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->rmap));
25235042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->cmap));
25245042aa92SStefano Zampini   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
25255042aa92SStefano Zampini   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
25265042aa92SStefano Zampini 
25275042aa92SStefano Zampini   /* load l2g maps */
25285042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
25295042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
25305042aa92SStefano Zampini   if (!samel) {
25315042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
25325042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
25335042aa92SStefano Zampini   } else {
25345042aa92SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)rmap));
25355042aa92SStefano Zampini     cmap = rmap;
25365042aa92SStefano Zampini   }
25375042aa92SStefano Zampini 
25385042aa92SStefano Zampini   /* load sizes of local matrices */
25395042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
25405042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
25415042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
25425042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
25435042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
25445042aa92SStefano Zampini   nr = 0;
25455042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
25465042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
25475042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
25485042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
25495042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
25505042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
25515042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
25525042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
25535042aa92SStefano Zampini   nc = 0;
25545042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
25555042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
25565042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
25575042aa92SStefano Zampini 
25585042aa92SStefano Zampini   /* now load the unassembled operator */
25595042aa92SStefano Zampini   PetscCall(MatCreate(comm, &dA));
25605042aa92SStefano Zampini   PetscCall(MatSetType(dA, MATMPIAIJ));
25615042aa92SStefano Zampini   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
25625042aa92SStefano Zampini   PetscCall(MatLoad(dA, viewer));
25635042aa92SStefano Zampini   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
25645042aa92SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)lA));
25655042aa92SStefano Zampini   PetscCall(MatDestroy(&dA));
25665042aa92SStefano Zampini 
25675042aa92SStefano Zampini   /* and convert to the desired format */
25685042aa92SStefano Zampini   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
25695042aa92SStefano Zampini   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
25705042aa92SStefano Zampini   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
25715042aa92SStefano Zampini 
25725042aa92SStefano Zampini   /* assemble the MATIS object */
25735042aa92SStefano Zampini   PetscCall(MatISSetAllowRepeated(A, allow));
25745042aa92SStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
25755042aa92SStefano Zampini   PetscCall(MatISSetLocalMat(A, lA));
25765042aa92SStefano Zampini   PetscCall(MatDestroy(&lA));
25775042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
25785042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
25795042aa92SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
25805042aa92SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
25813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2582b4319ba4SBarry Smith }
2583b4319ba4SBarry Smith 
2584d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2585d71ae5a4SJacob Faibussowitsch {
2586b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2587b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2588b89f26deSStefano Zampini   const PetscScalar *lv;
2589b89f26deSStefano Zampini   PetscInt           bs;
2590835f2295SStefano Zampini   PetscMPIInt        mbs;
2591b89f26deSStefano Zampini 
2592b89f26deSStefano Zampini   PetscFunctionBegin;
25939566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
25949566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
25959566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
259648a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2597835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(bs, &mbs));
2598835f2295SStefano Zampini   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
25999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
26009566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
26019566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
26029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2603b89f26deSStefano Zampini   if (values) *values = is->bdiag;
26043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2605b89f26deSStefano Zampini }
2606b89f26deSStefano Zampini 
2607d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2608d71ae5a4SJacob Faibussowitsch {
2609e176bc59SStefano Zampini   Vec             cglobal, rglobal;
26108546b261SStefano Zampini   IS              from;
26118546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2612b89f26deSStefano Zampini   PetscScalar     sum;
26138546b261SStefano Zampini   const PetscInt *garray;
26148546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2615e432b41dSStefano Zampini   VecType         rtype;
2616b4319ba4SBarry Smith 
2617b4319ba4SBarry Smith   PetscFunctionBegin;
26189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
26199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
26209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
26219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
26229566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
26239566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
26249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
26259566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
26269566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
26279566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
26289566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
26299566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
26309566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
26319566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
26329566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
26339566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
26349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
26359566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
26369566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
26379566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
26389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2639e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
26409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
26419566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
26429566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
26439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
26449566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
26458546b261SStefano Zampini   } else {
26469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
26478546b261SStefano Zampini     is->cctx = is->rctx;
26488546b261SStefano Zampini   }
26499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2650b89f26deSStefano Zampini 
26518546b261SStefano Zampini   /* interface counter vector (local) */
26529566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
26539566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
26549566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
26559566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26569566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
26579566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26589566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
26599566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
26609566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2661b89f26deSStefano Zampini 
2662b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
26639566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2664b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2665e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
26669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2667b0cc1f67SStefano Zampini 
2668b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
26699566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
26703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26718546b261SStefano Zampini }
26728546b261SStefano Zampini 
2673d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2674d71ae5a4SJacob Faibussowitsch {
26754f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2676e432b41dSStefano Zampini   IS                         is;
2677e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2678e432b41dSStefano Zampini   const PetscInt            *idxs;
2679e432b41dSStefano Zampini   PetscHSetI                 ht;
2680e432b41dSStefano Zampini   PetscInt                  *nidxs;
2681e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2682e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2683e432b41dSStefano Zampini 
2684e432b41dSStefano Zampini   PetscFunctionBegin;
26859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
26869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
26879566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
26889566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
26899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2690e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
26914f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
26929371c9d4SSatish Balay     if (idxs[i] < 0) {
26939371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
26949371c9d4SSatish Balay       continue;
26959371c9d4SSatish Balay     }
26964f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2697e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2698e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2699e432b41dSStefano Zampini   }
27009566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
2701462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2702e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2703e432b41dSStefano Zampini     *nmap = NULL;
2704e432b41dSStefano Zampini     *lmap = NULL;
27059566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
27069566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
27073ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2708e432b41dSStefano Zampini   }
2709e432b41dSStefano Zampini 
27104f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
27119566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
27129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
27139566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
27149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
27159566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2716e432b41dSStefano Zampini 
27174f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
27189566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
27199566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
27209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
27219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
27229566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
27239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
27243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2725e432b41dSStefano Zampini }
2726e432b41dSStefano Zampini 
2727d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2728d71ae5a4SJacob Faibussowitsch {
27298546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2730e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2731e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
27324f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
27338546b261SStefano Zampini 
27348546b261SStefano Zampini   PetscFunctionBegin;
2735fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2736fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2737e432b41dSStefano Zampini 
27389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
27399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
27409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
27419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
27429566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2743e432b41dSStefano Zampini 
2744fc989267SStefano Zampini   /* If NULL, local space matches global space */
2745fc989267SStefano Zampini   if (!rmapping) {
2746fc989267SStefano Zampini     IS is;
2747fc989267SStefano Zampini 
27489566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
27499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
275058b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
27519566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2752e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2753e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2754e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
27559566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2756e432b41dSStefano Zampini     if (rmapping == cmapping) {
27579566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2758e432b41dSStefano Zampini       is->cmapping = is->rmapping;
27599566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2760e432b41dSStefano Zampini       localcmapping = localrmapping;
2761fc989267SStefano Zampini     }
2762fc989267SStefano Zampini   }
2763fc989267SStefano Zampini   if (!cmapping) {
2764fc989267SStefano Zampini     IS is;
2765fc989267SStefano Zampini 
27669566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
27679566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
276858b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
27699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2770e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2771e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
27729566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2773e432b41dSStefano Zampini   }
2774e432b41dSStefano Zampini   if (!is->rmapping) {
27759566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2776e432b41dSStefano Zampini     is->rmapping = rmapping;
2777e432b41dSStefano Zampini   }
2778e432b41dSStefano Zampini   if (!is->cmapping) {
27799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2780e432b41dSStefano Zampini     is->cmapping = cmapping;
2781fc989267SStefano Zampini   }
2782fc989267SStefano Zampini 
2783fc989267SStefano Zampini   /* Clean up */
27844f58015eSStefano Zampini   is->lnnzstate = 0;
27854f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
27864f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
27879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2788872cf891SStefano Zampini   if (is->csf != is->sf) {
27899566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
27909566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2791f03112d0SStefano Zampini   } else is->csf = NULL;
27929566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
27939566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
27949566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
27953bbff08aSStefano Zampini 
2796fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2797fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
27989566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
27999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
28009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
28019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2802e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2803e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
28046625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
28056625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
28066625354bSStefano Zampini 
28079566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
28089566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
28099566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
28109566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
28119566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
28126625354bSStefano Zampini     }
2813462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2814e432b41dSStefano Zampini     if (same) {
28159566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
28169566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2817e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2818e432b41dSStefano Zampini     }
28196625354bSStefano Zampini   }
28209566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
28219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2822e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
28239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
28249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
28259566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
28269566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
28276625354bSStefano Zampini 
28286625354bSStefano Zampini   /* Create the local matrix A */
28299566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
28309566063dSJacob Faibussowitsch   PetscCall(MatSetType(is->A, is->lmattype));
28319566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
28329566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
28339566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
28349566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
28359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->rmap));
28369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(is->A->cmap));
28379566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
28389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
28399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2840b4319ba4SBarry Smith 
2841fc989267SStefano Zampini   /* setup scatters and local vectors for MatMult */
28429566063dSJacob Faibussowitsch   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2843fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
28443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2845fc989267SStefano Zampini }
2846fc989267SStefano Zampini 
2847d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2848d71ae5a4SJacob Faibussowitsch {
284929f134acSStefano Zampini   Mat_IS                *is = (Mat_IS *)A->data;
2850fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2851fc989267SStefano Zampini 
2852fc989267SStefano Zampini   PetscFunctionBegin;
285329f134acSStefano Zampini   if (!is->sf) {
28549566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
285529f134acSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
285629f134acSStefano Zampini   }
28573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2858b4319ba4SBarry Smith }
2859b4319ba4SBarry Smith 
2860d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2861d71ae5a4SJacob Faibussowitsch {
28622e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2863f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
28642e74eeadSLisandro Dalcin 
28652e74eeadSLisandro Dalcin   PetscFunctionBegin;
28669566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2867e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
28689566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28699566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2870e432b41dSStefano Zampini   } else {
28719566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2872e432b41dSStefano Zampini   }
28733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28742e74eeadSLisandro Dalcin }
28752e74eeadSLisandro Dalcin 
2876d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2877d71ae5a4SJacob Faibussowitsch {
287897563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2879f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
288097563a80SStefano Zampini 
288197563a80SStefano Zampini   PetscFunctionBegin;
28829566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2883e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
288484a95373SStefano Zampini     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28859566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2886e432b41dSStefano Zampini   } else {
288784a95373SStefano Zampini     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2888e432b41dSStefano Zampini   }
28893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
289097563a80SStefano Zampini }
289197563a80SStefano Zampini 
2892d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2893d71ae5a4SJacob Faibussowitsch {
2894b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2895b4319ba4SBarry Smith 
2896b4319ba4SBarry Smith   PetscFunctionBegin;
2897e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
28989566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2899872cf891SStefano Zampini   } else {
29009566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2901872cf891SStefano Zampini   }
29023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2903b4319ba4SBarry Smith }
2904b4319ba4SBarry Smith 
2905d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2906d71ae5a4SJacob Faibussowitsch {
2907f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2908f0006bf2SLisandro Dalcin 
2909f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2910e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
29119566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2912b4f971dfSStefano Zampini   } else {
29139566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2914b4f971dfSStefano Zampini   }
29153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2916f0006bf2SLisandro Dalcin }
2917f0006bf2SLisandro Dalcin 
2918d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2919d71ae5a4SJacob Faibussowitsch {
2920f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2921f0ae7da4SStefano Zampini 
2922f0ae7da4SStefano Zampini   PetscFunctionBegin;
2923f0ae7da4SStefano Zampini   if (!n) {
2924f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2925f0ae7da4SStefano Zampini   } else {
2926f0ae7da4SStefano Zampini     PetscInt i;
2927f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2928f0ae7da4SStefano Zampini 
2929f0ae7da4SStefano Zampini     if (columns) {
29309566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2931f0ae7da4SStefano Zampini     } else {
29329566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2933f0ae7da4SStefano Zampini     }
2934f0ae7da4SStefano Zampini     if (diag != 0.) {
2935f0ae7da4SStefano Zampini       const PetscScalar *array;
29369566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
293748a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
29389566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2939f0ae7da4SStefano Zampini     }
29409566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
29419566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2942f0ae7da4SStefano Zampini   }
29433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2944f0ae7da4SStefano Zampini }
2945f0ae7da4SStefano Zampini 
2946d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2947d71ae5a4SJacob Faibussowitsch {
29486e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
29496e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
29506e520ac8SStefano Zampini   PetscInt *lrows;
29512e74eeadSLisandro Dalcin 
29522e74eeadSLisandro Dalcin   PetscFunctionBegin;
2953cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2954f0ae7da4SStefano Zampini     PetscBool cong;
295526b0207aSStefano Zampini 
29569566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
295726b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
295808401ef6SPierre 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");
2959aed4548fSBarry 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");
2960aed4548fSBarry 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");
2961f0ae7da4SStefano Zampini   }
29626e520ac8SStefano Zampini   /* get locally owned rows */
29639566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2964dd8e379bSPierre Jolivet   /* fix right-hand side if needed */
29656e520ac8SStefano Zampini   if (x && b) {
29666e520ac8SStefano Zampini     const PetscScalar *xx;
29676e520ac8SStefano Zampini     PetscScalar       *bb;
29686e520ac8SStefano Zampini 
29699566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
29709566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
29716e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
29729566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
29739566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
29742e74eeadSLisandro Dalcin   }
29756e520ac8SStefano Zampini   /* get rows associated to the local matrices */
29769566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
29779566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
29789566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
29796e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
29809566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29819566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29829566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
29849371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
29859371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
29869566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
29879566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2988d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2989d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
29903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29912e74eeadSLisandro Dalcin }
29922e74eeadSLisandro Dalcin 
2993d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2994d71ae5a4SJacob Faibussowitsch {
2995b4319ba4SBarry Smith   PetscFunctionBegin;
29969566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
29973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2998f0ae7da4SStefano Zampini }
29992205254eSKarl Rupp 
3000d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
3001d71ae5a4SJacob Faibussowitsch {
3002f0ae7da4SStefano Zampini   PetscFunctionBegin;
30039566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
30043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3005b4319ba4SBarry Smith }
3006b4319ba4SBarry Smith 
3007d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
3008d71ae5a4SJacob Faibussowitsch {
3009b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
3010b4319ba4SBarry Smith 
3011b4319ba4SBarry Smith   PetscFunctionBegin;
30129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
30133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3014b4319ba4SBarry Smith }
3015b4319ba4SBarry Smith 
3016d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
3017d71ae5a4SJacob Faibussowitsch {
3018b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
3019d0dbe9f7SStefano Zampini   PetscBool lnnz;
3020b4319ba4SBarry Smith 
3021b4319ba4SBarry Smith   PetscFunctionBegin;
30229566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
3023872cf891SStefano Zampini   /* fix for local empty rows/cols */
3024872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
3025872cf891SStefano Zampini     Mat                    newlA;
3026f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
3027f03112d0SStefano Zampini     IS                     nzr, nzc;
3028f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
3029f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
3030872cf891SStefano Zampini 
30319566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
30329566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
303348a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
30349566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
303548a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
30369566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
30379566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
3038e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
3039f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
3040462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
3041f03112d0SStefano Zampini 
3042872cf891SStefano Zampini       /* extract valid submatrix */
30439566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
3044f03112d0SStefano Zampini     } else { /* local matrix fully populated */
3045f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
3046462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
30479566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
3048f03112d0SStefano Zampini       newlA = is->A;
3049f03112d0SStefano Zampini     }
3050e432b41dSStefano Zampini 
3051f03112d0SStefano Zampini     /* attach new global l2g map if needed */
3052f03112d0SStefano Zampini     if (newl2g) {
3053e432b41dSStefano Zampini       IS              zr, zc;
3054e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
3055e432b41dSStefano Zampini       PetscInt       *nidxs, i;
3056f03112d0SStefano Zampini 
30579566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
30589566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
30599566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
30609566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
30619566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
30629566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
30639566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
30649566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
30659566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
3066e432b41dSStefano Zampini 
30679566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
3068e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
30699566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
30709566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
3071e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
30729566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
3073e432b41dSStefano Zampini 
30749566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
30759566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
30769566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
30779566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
30789566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
30799566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
30809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
30819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
30829566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
30839566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
30849566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30859566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3086f03112d0SStefano Zampini     }
30879566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
30889566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
30899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
30909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
3091872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
3092f03112d0SStefano Zampini   }
3093d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
3094d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
3095462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
30964f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
30973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3098b4319ba4SBarry Smith }
3099b4319ba4SBarry Smith 
3100d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
3101d71ae5a4SJacob Faibussowitsch {
3102b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
3103b4319ba4SBarry Smith 
3104b4319ba4SBarry Smith   PetscFunctionBegin;
3105b4319ba4SBarry Smith   *local = is->A;
31063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3107b4319ba4SBarry Smith }
3108b4319ba4SBarry Smith 
3109d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
3110d71ae5a4SJacob Faibussowitsch {
31113b3b1effSJed Brown   PetscFunctionBegin;
31123b3b1effSJed Brown   *local = NULL;
31133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31143b3b1effSJed Brown }
31153b3b1effSJed Brown 
3116b4319ba4SBarry Smith /*@
311711a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
3118b4319ba4SBarry Smith 
31194f58015eSStefano Zampini   Not Collective.
31204f58015eSStefano Zampini 
3121b4319ba4SBarry Smith   Input Parameter:
3122b4319ba4SBarry Smith . mat - the matrix
3123b4319ba4SBarry Smith 
3124b4319ba4SBarry Smith   Output Parameter:
3125eb82efa4SStefano Zampini . local - the local matrix
3126b4319ba4SBarry Smith 
31274f58015eSStefano Zampini   Level: intermediate
3128b4319ba4SBarry Smith 
3129b4319ba4SBarry Smith   Notes:
3130b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
3131b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
313211a5261eSBarry Smith   of the `MatSetValues()` operation.
3133b4319ba4SBarry Smith 
313411a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
313596a6f129SJed Brown 
31361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
3137b4319ba4SBarry Smith @*/
3138d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
3139d71ae5a4SJacob Faibussowitsch {
3140b4319ba4SBarry Smith   PetscFunctionBegin;
31410700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31424f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3143cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
31443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3145b4319ba4SBarry Smith }
3146b4319ba4SBarry Smith 
31473b3b1effSJed Brown /*@
314811a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
31493b3b1effSJed Brown 
31504f58015eSStefano Zampini   Not Collective.
31514f58015eSStefano Zampini 
31522ef1f0ffSBarry Smith   Input Parameters:
31532ef1f0ffSBarry Smith + mat   - the matrix
31542ef1f0ffSBarry Smith - local - the local matrix
31553b3b1effSJed Brown 
31564f58015eSStefano Zampini   Level: intermediate
31573b3b1effSJed Brown 
31581cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
31593b3b1effSJed Brown @*/
3160d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
3161d71ae5a4SJacob Faibussowitsch {
31623b3b1effSJed Brown   PetscFunctionBegin;
31633b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
31644f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3165cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
31663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31673b3b1effSJed Brown }
31683b3b1effSJed Brown 
3169d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3170d71ae5a4SJacob Faibussowitsch {
31718546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
31728546b261SStefano Zampini 
31738546b261SStefano Zampini   PetscFunctionBegin;
31741baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
31759566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
31769566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
31773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31788546b261SStefano Zampini }
31798546b261SStefano Zampini 
31805d83a8b1SBarry Smith /*@
318111a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
31828546b261SStefano Zampini 
31834f58015eSStefano Zampini   Logically Collective.
31844f58015eSStefano Zampini 
3185d8d19677SJose E. Roman   Input Parameters:
3186a2b725a8SWilliam Gropp + mat   - the matrix
3187a2b725a8SWilliam Gropp - mtype - the local matrix type
31888546b261SStefano Zampini 
31894f58015eSStefano Zampini   Level: intermediate
31908546b261SStefano Zampini 
31911cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
31928546b261SStefano Zampini @*/
3193d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3194d71ae5a4SJacob Faibussowitsch {
31958546b261SStefano Zampini   PetscFunctionBegin;
31968546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3197cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
31983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31998546b261SStefano Zampini }
32008546b261SStefano Zampini 
3201d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3202d71ae5a4SJacob Faibussowitsch {
32033b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
32043b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
32058546b261SStefano Zampini   MatType   mtype, otype;
32068546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
32073b03a366Sstefano_zampini 
32083b03a366Sstefano_zampini   PetscFunctionBegin;
3209e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
32109566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
32119566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
32125042aa92SStefano 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);
32139566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
32149566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
32159566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
32164e4c7dbeSStefano Zampini   }
32179566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
32189566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
32193b03a366Sstefano_zampini   is->A = local;
32209566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
32219566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
322248a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
32234f58015eSStefano Zampini   is->lnnzstate = 0;
32243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32253b03a366Sstefano_zampini }
32263b03a366Sstefano_zampini 
32273b03a366Sstefano_zampini /*@
322811a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
32293b03a366Sstefano_zampini 
32304f58015eSStefano Zampini   Not Collective
32318546b261SStefano Zampini 
3232d8d19677SJose E. Roman   Input Parameters:
3233a2b725a8SWilliam Gropp + mat   - the matrix
3234a2b725a8SWilliam Gropp - local - the local matrix
32353b03a366Sstefano_zampini 
32364f58015eSStefano Zampini   Level: intermediate
323711a5261eSBarry Smith 
32381cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
32393b03a366Sstefano_zampini @*/
3240d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3241d71ae5a4SJacob Faibussowitsch {
32423b03a366Sstefano_zampini   PetscFunctionBegin;
32433b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3244b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3245cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
32463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32473b03a366Sstefano_zampini }
32483b03a366Sstefano_zampini 
3249d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3250d71ae5a4SJacob Faibussowitsch {
32516726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32526726f965SBarry Smith 
32536726f965SBarry Smith   PetscFunctionBegin;
32549566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
32553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32566726f965SBarry Smith }
32576726f965SBarry Smith 
3258d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3259d71ae5a4SJacob Faibussowitsch {
32602e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32612e74eeadSLisandro Dalcin 
32622e74eeadSLisandro Dalcin   PetscFunctionBegin;
32639566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
32643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32652e74eeadSLisandro Dalcin }
32662e74eeadSLisandro Dalcin 
3267d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3268d71ae5a4SJacob Faibussowitsch {
32692e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
32702e74eeadSLisandro Dalcin 
32712e74eeadSLisandro Dalcin   PetscFunctionBegin;
32722e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
32739566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
32742e74eeadSLisandro Dalcin 
32752e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
32769566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
32779566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32789566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32802e74eeadSLisandro Dalcin }
32812e74eeadSLisandro Dalcin 
3282d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3283d71ae5a4SJacob Faibussowitsch {
32846726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32856726f965SBarry Smith 
32866726f965SBarry Smith   PetscFunctionBegin;
32879566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
32883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32896726f965SBarry Smith }
32906726f965SBarry Smith 
3291d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3292d71ae5a4SJacob Faibussowitsch {
3293f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3294f26d0771SStefano Zampini   Mat_IS *x;
3295f26d0771SStefano Zampini 
3296f26d0771SStefano Zampini   PetscFunctionBegin;
329776bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
329876bd3646SJed Brown     PetscBool ismatis;
32999566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
330028b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
330176bd3646SJed Brown   }
3302f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
33039566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
33043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3305f26d0771SStefano Zampini }
3306f26d0771SStefano Zampini 
3307d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3308d71ae5a4SJacob Faibussowitsch {
3309f26d0771SStefano Zampini   Mat                    lA;
3310f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3311f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3312f26d0771SStefano Zampini   IS                     is;
3313f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3314f26d0771SStefano Zampini   PetscInt               nrg;
3315f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3316f26d0771SStefano Zampini 
3317f26d0771SStefano Zampini   PetscFunctionBegin;
33189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
33199566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
33209566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
33219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
332276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
332308401ef6SPierre 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);
332476bd3646SJed Brown   }
33259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3326f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3327f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3328f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
33299566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
33309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
33319566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
33329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
33339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3334f26d0771SStefano Zampini   /* compute new l2g map for columns */
3335e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3336f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3337f26d0771SStefano Zampini     PetscInt        ncg;
3338f26d0771SStefano Zampini     PetscInt        ncl;
3339f26d0771SStefano Zampini 
33409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
33419566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
33429566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
33439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
334476bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
334508401ef6SPierre 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);
334676bd3646SJed Brown     }
33479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3348f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3349f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3350f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
33519566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
33529566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
33539566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
33549566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
33559566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3356f26d0771SStefano Zampini   } else {
33579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3358f26d0771SStefano Zampini     cl2g = rl2g;
3359f26d0771SStefano Zampini   }
3360f26d0771SStefano Zampini   /* create the MATIS submatrix */
33619566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
33629566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
33639566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
33649566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3365b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3366f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
33679566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
33689566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
33699566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
33709566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*submat));
33719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
33729566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
33739566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
33749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3375e432b41dSStefano Zampini 
3376f26d0771SStefano Zampini   /* remove unsupported ops */
33779566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3378f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3379f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3380f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3381f26d0771SStefano Zampini   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3382f26d0771SStefano Zampini   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
33833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3384f26d0771SStefano Zampini }
3385f26d0771SStefano Zampini 
3386ce78bad3SBarry Smith static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject)
3387d71ae5a4SJacob Faibussowitsch {
3388872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
33898546b261SStefano Zampini   char      type[256];
33908546b261SStefano Zampini   PetscBool flg;
3391872cf891SStefano Zampini 
3392872cf891SStefano Zampini   PetscFunctionBegin;
3393d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
33944f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
33954f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
33964f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
33974f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
33984f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
33994f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
34004f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
34014f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
34024f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
34031baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
34041baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3405d0609cedSBarry Smith   PetscOptionsHeadEnd();
34063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3407872cf891SStefano Zampini }
3408872cf891SStefano Zampini 
3409284134d9SBarry Smith /*@
34104f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
34114f58015eSStefano Zampini 
34124f58015eSStefano Zampini   Collective.
3413284134d9SBarry Smith 
3414284134d9SBarry Smith   Input Parameters:
3415284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3416e176bc59SStefano Zampini . bs   - block size of the matrix
34172920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
34182920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
34192920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
34202920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3421e176bc59SStefano Zampini . rmap - local to global map for rows
3422e176bc59SStefano Zampini - cmap - local to global map for cols
3423284134d9SBarry Smith 
3424284134d9SBarry Smith   Output Parameter:
3425284134d9SBarry Smith . A - the resulting matrix
3426284134d9SBarry Smith 
34274f58015eSStefano Zampini   Level: intermediate
34288e6c10adSSatish Balay 
342995452b02SPatrick Sanan   Notes:
34302ef1f0ffSBarry 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
34314f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
343211a5261eSBarry Smith 
34332ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3434284134d9SBarry Smith 
34351cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3436284134d9SBarry Smith @*/
3437d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3438d71ae5a4SJacob Faibussowitsch {
3439284134d9SBarry Smith   PetscFunctionBegin;
34409566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
34419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
344248a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
34439566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
34449566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
34453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3446284134d9SBarry Smith }
3447284134d9SBarry Smith 
3448d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3449d71ae5a4SJacob Faibussowitsch {
34508b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3451e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
34528b9382cfSStefano Zampini 
34538b9382cfSStefano Zampini   PetscFunctionBegin;
34548b9382cfSStefano Zampini   *has = PETSC_FALSE;
34553ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3456d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
34579371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
34583ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
34599566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
34603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34618b9382cfSStefano Zampini }
34628b9382cfSStefano Zampini 
3463d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3464d71ae5a4SJacob Faibussowitsch {
3465e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3466e432b41dSStefano Zampini 
3467e432b41dSStefano Zampini   PetscFunctionBegin;
34689566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
34699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
34709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
34713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3472e432b41dSStefano Zampini }
3473e432b41dSStefano Zampini 
3474d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3475d71ae5a4SJacob Faibussowitsch {
3476e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3477e432b41dSStefano Zampini 
3478e432b41dSStefano Zampini   PetscFunctionBegin;
3479e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3480e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
34819566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3482e432b41dSStefano Zampini   } else {
34839566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3484e432b41dSStefano Zampini   }
34859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3486e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3488e432b41dSStefano Zampini }
3489e432b41dSStefano Zampini 
3490d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3491d71ae5a4SJacob Faibussowitsch {
3492e432b41dSStefano Zampini   Mat_IS  *a = (Mat_IS *)A->data;
3493835f2295SStefano Zampini   PetscInt ncoo_i;
3494e432b41dSStefano Zampini 
3495e432b41dSStefano Zampini   PetscFunctionBegin;
3496e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3497835f2295SStefano Zampini   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3498835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3499835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3500e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
35019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3502e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
35033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3504e432b41dSStefano Zampini }
3505e432b41dSStefano Zampini 
3506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3507d71ae5a4SJacob Faibussowitsch {
3508d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
35091690c2aeSBarry Smith   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
35101690c2aeSBarry Smith   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3511d0dbe9f7SStefano Zampini 
3512d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3513d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3514d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3515d0dbe9f7SStefano Zampini   if (a->assembledA) {
3516d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3517d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3518d0dbe9f7SStefano Zampini   }
3519d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3520d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3521d0dbe9f7SStefano Zampini     MatType     aAtype;
3522d0dbe9f7SStefano Zampini     PetscMPIInt size;
3523d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3524d0dbe9f7SStefano Zampini 
3525d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3526d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3527d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3528d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3529d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3530d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3531d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3532d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3533d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3534d0dbe9f7SStefano Zampini 
3535d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3536d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3537d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3538d0dbe9f7SStefano Zampini   }
3539d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3540d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3541d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
35423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3543d0dbe9f7SStefano Zampini }
3544d0dbe9f7SStefano Zampini 
3545d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3546d71ae5a4SJacob Faibussowitsch {
3547d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3548d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3549d0dbe9f7SStefano Zampini   *tA = NULL;
35503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3551d0dbe9f7SStefano Zampini }
3552d0dbe9f7SStefano Zampini 
3553d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3554d71ae5a4SJacob Faibussowitsch {
3555d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
35561690c2aeSBarry Smith   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3557d0dbe9f7SStefano Zampini 
3558d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3559d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3560d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3561d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3562d0dbe9f7SStefano Zampini     Mat     tA;
3563d0dbe9f7SStefano Zampini     MatType ltype;
3564d0dbe9f7SStefano Zampini 
3565d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3566d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3567d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3568d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3569d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3570d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3571d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3572d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3573d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3574d0dbe9f7SStefano Zampini   }
3575d0dbe9f7SStefano Zampini   *dA = a->dA;
35763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3577d0dbe9f7SStefano Zampini }
3578d0dbe9f7SStefano Zampini 
3579d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3580d71ae5a4SJacob Faibussowitsch {
3581d0dbe9f7SStefano Zampini   Mat tA;
3582d0dbe9f7SStefano Zampini 
3583d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3584d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3585d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3586d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3587d0dbe9f7SStefano Zampini #if 0
3588d0dbe9f7SStefano Zampini   {
3589d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3590d0dbe9f7SStefano Zampini     MatType   ltype;
3591d0dbe9f7SStefano Zampini     VecType   vtype;
3592d0dbe9f7SStefano Zampini     char      *flg;
3593d0dbe9f7SStefano Zampini 
3594d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3595d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3596d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3597d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3598d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3599d0dbe9f7SStefano Zampini     if (flg) {
3600d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3601d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3602d0dbe9f7SStefano Zampini 
3603d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3604d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3605d0dbe9f7SStefano Zampini       }
3606d0dbe9f7SStefano Zampini     }
3607d0dbe9f7SStefano Zampini   }
3608d0dbe9f7SStefano Zampini #endif
3609d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
36103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3611d0dbe9f7SStefano Zampini }
3612d0dbe9f7SStefano Zampini 
3613d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3614d71ae5a4SJacob Faibussowitsch {
3615d0dbe9f7SStefano Zampini   Mat tA;
3616d0dbe9f7SStefano Zampini 
3617d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3618d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3619d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3620d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
36213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3622d0dbe9f7SStefano Zampini }
3623d0dbe9f7SStefano Zampini 
3624e432b41dSStefano Zampini /*@
362511a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3626e432b41dSStefano Zampini 
3627e432b41dSStefano Zampini   Not Collective
3628e432b41dSStefano Zampini 
3629e432b41dSStefano Zampini   Input Parameter:
3630e432b41dSStefano Zampini . A - the matrix
3631e432b41dSStefano Zampini 
3632e432b41dSStefano Zampini   Output Parameters:
3633e432b41dSStefano Zampini + rmapping - row mapping
3634e432b41dSStefano Zampini - cmapping - column mapping
3635e432b41dSStefano Zampini 
36362ef1f0ffSBarry Smith   Level: advanced
36372ef1f0ffSBarry Smith 
363811a5261eSBarry Smith   Note:
363911a5261eSBarry 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.
3640e432b41dSStefano Zampini 
3641*bfe80ac4SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3642e432b41dSStefano Zampini @*/
3643d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3644d71ae5a4SJacob Faibussowitsch {
3645e432b41dSStefano Zampini   PetscFunctionBegin;
3646e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3647e432b41dSStefano Zampini   PetscValidType(A, 1);
36484f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
36494f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3650cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
36513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3652e432b41dSStefano Zampini }
3653e432b41dSStefano Zampini 
3654d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3655d71ae5a4SJacob Faibussowitsch {
3656e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3657e432b41dSStefano Zampini 
3658e432b41dSStefano Zampini   PetscFunctionBegin;
3659e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3660e432b41dSStefano Zampini   if (c) *c = a->cmapping;
36613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3662e432b41dSStefano Zampini }
3663e432b41dSStefano Zampini 
3664a50ef18cSStefano Zampini static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3665a50ef18cSStefano Zampini {
3666a50ef18cSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3667a50ef18cSStefano Zampini 
3668a50ef18cSStefano Zampini   PetscFunctionBegin;
3669a50ef18cSStefano Zampini   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3670a50ef18cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
3671a50ef18cSStefano Zampini }
3672a50ef18cSStefano Zampini 
3673b4319ba4SBarry Smith /*MC
36744f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
36754f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3676b4319ba4SBarry Smith 
3677b4319ba4SBarry Smith   Options Database Keys:
36784f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
36794f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
36804f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
36814f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
36822ef1f0ffSBarry Smith 
36834f58015eSStefano Zampini   Level: intermediate
3684b4319ba4SBarry Smith 
368595452b02SPatrick Sanan   Notes:
36862ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3687b4319ba4SBarry Smith 
368811a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3689b4319ba4SBarry Smith 
3690b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
36914f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3692b4319ba4SBarry Smith 
36931cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3694b4319ba4SBarry Smith M*/
3695d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3696d71ae5a4SJacob Faibussowitsch {
3697e432b41dSStefano Zampini   Mat_IS *a;
3698b4319ba4SBarry Smith 
3699b4319ba4SBarry Smith   PetscFunctionBegin;
37004dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
37019566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3702e432b41dSStefano Zampini   A->data = (void *)a;
3703b4319ba4SBarry Smith 
3704e176bc59SStefano Zampini   /* matrix ops */
37059566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3706b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
37072e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
37082e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
37092e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3710b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3711b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
37122e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
371398921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3714b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3715f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
37162e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3717f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3718b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3719b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3720b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
37215042aa92SStefano Zampini   A->ops->load                    = MatLoad_IS;
37226726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
37232e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
37242e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
37256726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
372669796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
372769796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
372845471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3729ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
37306bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
37312b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3732659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
37337dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3734f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
37353fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
37363fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3737d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
37387fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3739ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3740872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3741fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
37428b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3743d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3744d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3745d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3746a50ef18cSStefano Zampini   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3747b4319ba4SBarry Smith 
3748b7ce53b6SStefano Zampini   /* special MATIS functions */
37499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
37509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
37519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
37529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
37539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
37544f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
37559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
37569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
37579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
37589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
37599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
37609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
37619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
37629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
37639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
37649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
37659566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
37669566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
37679566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
37683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3769b4319ba4SBarry Smith }
3770