xref: /petsc/src/mat/impls/is/matis.c (revision 0d2733adeac6ae9c1e28e458cfd92735deb36bc4)
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));
796ac530a7eSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
797ac530a7eSPierre Jolivet   else *newmat = B;
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7996989cf23SStefano Zampini }
8006989cf23SStefano Zampini 
801d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
802d71ae5a4SJacob Faibussowitsch {
8035e3038f0Sstefano_zampini   Mat                  **nest, *snest, **rnest, lA, B;
8045e3038f0Sstefano_zampini   IS                    *iscol, *isrow, *islrow, *islcol;
8055e3038f0Sstefano_zampini   ISLocalToGlobalMapping rl2g, cl2g;
8065e3038f0Sstefano_zampini   MPI_Comm               comm;
8075b003df0Sstefano_zampini   PetscInt              *lr, *lc, *l2gidxs;
8085b003df0Sstefano_zampini   PetscInt               i, j, nr, nc, rbs, cbs;
8099e7b2b25Sstefano_zampini   PetscBool              convert, lreuse, *istrans;
8104f58015eSStefano Zampini   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
8115e3038f0Sstefano_zampini 
812ab4d48faSStefano Zampini   PetscFunctionBegin;
8139566063dSJacob Faibussowitsch   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
8145e3038f0Sstefano_zampini   lreuse = PETSC_FALSE;
8155e3038f0Sstefano_zampini   rnest  = NULL;
8165e3038f0Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
8175e3038f0Sstefano_zampini     PetscBool ismatis, isnest;
8185e3038f0Sstefano_zampini 
8199566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
820f4f49eeaSPierre Jolivet     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
8219566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
8229566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
8235e3038f0Sstefano_zampini     if (isnest) {
8249566063dSJacob Faibussowitsch       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
8255e3038f0Sstefano_zampini       lreuse = (PetscBool)(i == nr && j == nc);
8265e3038f0Sstefano_zampini       if (!lreuse) rnest = NULL;
8275e3038f0Sstefano_zampini     }
8285e3038f0Sstefano_zampini   }
8299566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
8309566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
8319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
8329566063dSJacob Faibussowitsch   PetscCall(MatNestGetISs(A, isrow, iscol));
8335e3038f0Sstefano_zampini   for (i = 0; i < nr; i++) {
8345e3038f0Sstefano_zampini     for (j = 0; j < nc; j++) {
8354f58015eSStefano Zampini       PetscBool ismatis, sallow;
8369e7b2b25Sstefano_zampini       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
8375e3038f0Sstefano_zampini 
8385e3038f0Sstefano_zampini       /* Null matrix pointers are allowed in MATNEST */
8395e3038f0Sstefano_zampini       if (!nest[i][j]) continue;
8405e3038f0Sstefano_zampini 
8415e3038f0Sstefano_zampini       /* Nested matrices should be of type MATIS */
842013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
8439e7b2b25Sstefano_zampini       if (istrans[ij]) {
8449e7b2b25Sstefano_zampini         Mat T, lT;
8459566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(nest[i][j], &T));
8469566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
84728b400f6SJacob 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);
8484f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(T, &sallow));
8499566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(T, &lT));
8509566063dSJacob Faibussowitsch         PetscCall(MatCreateTranspose(lT, &snest[ij]));
8519e7b2b25Sstefano_zampini       } else {
8529566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
85328b400f6SJacob 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);
8544f58015eSStefano Zampini         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
8559566063dSJacob Faibussowitsch         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
8569e7b2b25Sstefano_zampini       }
8574f58015eSStefano Zampini       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
8584f58015eSStefano Zampini       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
8595e3038f0Sstefano_zampini 
8605e3038f0Sstefano_zampini       /* Check compatibility of local sizes */
8619566063dSJacob Faibussowitsch       PetscCall(MatGetSize(snest[ij], &l1, &l2));
8629566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
8635e3038f0Sstefano_zampini       if (!l1 || !l2) continue;
864aed4548fSBarry 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);
865aed4548fSBarry 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);
8665e3038f0Sstefano_zampini       lr[i] = l1;
8675e3038f0Sstefano_zampini       lc[j] = l2;
8685e3038f0Sstefano_zampini 
869da81f932SPierre Jolivet       /* check compatibility for local matrix reusage */
8705e3038f0Sstefano_zampini       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
8715e3038f0Sstefano_zampini     }
8725e3038f0Sstefano_zampini   }
8735e3038f0Sstefano_zampini 
87476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
8755e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for rows */
8765e3038f0Sstefano_zampini     for (i = 0; i < nr; i++) {
8775e3038f0Sstefano_zampini       rl2g = NULL;
8785e3038f0Sstefano_zampini       for (j = 0; j < nc; j++) {
8795e3038f0Sstefano_zampini         PetscInt n1, n2;
8805e3038f0Sstefano_zampini 
8815e3038f0Sstefano_zampini         if (!nest[i][j]) continue;
8829e7b2b25Sstefano_zampini         if (istrans[i * nc + j]) {
8839e7b2b25Sstefano_zampini           Mat T;
8849e7b2b25Sstefano_zampini 
8859566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[i][j], &T));
8869566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
8879e7b2b25Sstefano_zampini         } else {
8889566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
8899e7b2b25Sstefano_zampini         }
8909566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
8915e3038f0Sstefano_zampini         if (!n1) continue;
8925e3038f0Sstefano_zampini         if (!rl2g) {
8935e3038f0Sstefano_zampini           rl2g = cl2g;
8945e3038f0Sstefano_zampini         } else {
8955e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
8965e3038f0Sstefano_zampini           PetscBool       same;
8975e3038f0Sstefano_zampini 
8989566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
89908401ef6SPierre 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);
9009566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9019566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9029566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9039566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9049566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
90528b400f6SJacob 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);
9065e3038f0Sstefano_zampini         }
9075e3038f0Sstefano_zampini       }
9085e3038f0Sstefano_zampini     }
9095e3038f0Sstefano_zampini     /* Check compatibility of l2g maps for columns */
9105e3038f0Sstefano_zampini     for (i = 0; i < nc; i++) {
9115e3038f0Sstefano_zampini       rl2g = NULL;
9125e3038f0Sstefano_zampini       for (j = 0; j < nr; j++) {
9135e3038f0Sstefano_zampini         PetscInt n1, n2;
9145e3038f0Sstefano_zampini 
9155e3038f0Sstefano_zampini         if (!nest[j][i]) continue;
9169e7b2b25Sstefano_zampini         if (istrans[j * nc + i]) {
9179e7b2b25Sstefano_zampini           Mat T;
9189e7b2b25Sstefano_zampini 
9199566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(nest[j][i], &T));
9209566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
9219e7b2b25Sstefano_zampini         } else {
9229566063dSJacob Faibussowitsch           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
9239e7b2b25Sstefano_zampini         }
9249566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
9255e3038f0Sstefano_zampini         if (!n1) continue;
9265e3038f0Sstefano_zampini         if (!rl2g) {
9275e3038f0Sstefano_zampini           rl2g = cl2g;
9285e3038f0Sstefano_zampini         } else {
9295e3038f0Sstefano_zampini           const PetscInt *idxs1, *idxs2;
9305e3038f0Sstefano_zampini           PetscBool       same;
9315e3038f0Sstefano_zampini 
9329566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
93308401ef6SPierre 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);
9349566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
9359566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
9369566063dSJacob Faibussowitsch           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
9379566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
9389566063dSJacob Faibussowitsch           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
93928b400f6SJacob 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);
9405e3038f0Sstefano_zampini         }
9415e3038f0Sstefano_zampini       }
9425e3038f0Sstefano_zampini     }
94376bd3646SJed Brown   }
9445e3038f0Sstefano_zampini 
9455e3038f0Sstefano_zampini   B = NULL;
9465e3038f0Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
9475b003df0Sstefano_zampini     PetscInt stl;
9485b003df0Sstefano_zampini 
9495e3038f0Sstefano_zampini     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
9505e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
9519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9525b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nr; i++) {
9535e3038f0Sstefano_zampini       Mat             usedmat;
9545e3038f0Sstefano_zampini       Mat_IS         *matis;
9555e3038f0Sstefano_zampini       const PetscInt *idxs;
9565e3038f0Sstefano_zampini 
9575e3038f0Sstefano_zampini       /* local IS for local NEST */
9589566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
9595e3038f0Sstefano_zampini 
9605e3038f0Sstefano_zampini       /* l2gmap */
9615e3038f0Sstefano_zampini       j       = 0;
9625e3038f0Sstefano_zampini       usedmat = nest[i][j];
9639e7b2b25Sstefano_zampini       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
96428b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
9659e7b2b25Sstefano_zampini 
9669e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9679e7b2b25Sstefano_zampini         Mat T;
9689566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
9699e7b2b25Sstefano_zampini         usedmat = T;
9709e7b2b25Sstefano_zampini       }
971f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
9729566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(isrow[i], &idxs));
9739e7b2b25Sstefano_zampini       if (istrans[i * nc + j]) {
9749566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9759566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9769e7b2b25Sstefano_zampini       } else {
9779566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9789566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
9799e7b2b25Sstefano_zampini       }
9809566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(isrow[i], &idxs));
9815e3038f0Sstefano_zampini       stl += lr[i];
9825e3038f0Sstefano_zampini     }
9839566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
9845e3038f0Sstefano_zampini 
9855e3038f0Sstefano_zampini     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
9865e3038f0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
9879566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(stl, &l2gidxs));
9885b003df0Sstefano_zampini     for (i = 0, stl = 0; i < nc; i++) {
9895e3038f0Sstefano_zampini       Mat             usedmat;
9905e3038f0Sstefano_zampini       Mat_IS         *matis;
9915e3038f0Sstefano_zampini       const PetscInt *idxs;
9925e3038f0Sstefano_zampini 
9935e3038f0Sstefano_zampini       /* local IS for local NEST */
9949566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
9955e3038f0Sstefano_zampini 
9965e3038f0Sstefano_zampini       /* l2gmap */
9975e3038f0Sstefano_zampini       j       = 0;
9985e3038f0Sstefano_zampini       usedmat = nest[j][i];
9999e7b2b25Sstefano_zampini       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
100028b400f6SJacob Faibussowitsch       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
10019e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10029e7b2b25Sstefano_zampini         Mat T;
10039566063dSJacob Faibussowitsch         PetscCall(MatTransposeGetMat(usedmat, &T));
10049e7b2b25Sstefano_zampini         usedmat = T;
10059e7b2b25Sstefano_zampini       }
1006f4f49eeaSPierre Jolivet       matis = (Mat_IS *)usedmat->data;
10079566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iscol[i], &idxs));
10089e7b2b25Sstefano_zampini       if (istrans[j * nc + i]) {
10099566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10109566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10119e7b2b25Sstefano_zampini       } else {
10129566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10139566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
10149e7b2b25Sstefano_zampini       }
10159566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iscol[i], &idxs));
10165e3038f0Sstefano_zampini       stl += lc[i];
10175e3038f0Sstefano_zampini     }
10189566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
10195e3038f0Sstefano_zampini 
10205e3038f0Sstefano_zampini     /* Create MATIS */
10219566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, &B));
10229566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
10239566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
10249566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, rbs, cbs));
10259566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATIS));
10269566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMatType(B, MATNEST));
10274f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
10288546b261SStefano Zampini     { /* hack : avoid setup of scatters */
1029f4f49eeaSPierre Jolivet       Mat_IS *matis     = (Mat_IS *)B->data;
1030*0d2733adSStefano Zampini       matis->islocalref = B;
10318546b261SStefano Zampini     }
10329566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
10339566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
10349566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
10359566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
10369566063dSJacob Faibussowitsch     PetscCall(MatNestSetVecType(lA, VECNEST));
10379e7b2b25Sstefano_zampini     for (i = 0; i < nr * nc; i++) {
103848a46eb9SPierre Jolivet       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
10399e7b2b25Sstefano_zampini     }
10409566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(B, lA));
10419566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&lA));
10428546b261SStefano Zampini     { /* hack : setup of scatters done here */
1043f4f49eeaSPierre Jolivet       Mat_IS *matis = (Mat_IS *)B->data;
10448546b261SStefano Zampini 
1045*0d2733adSStefano Zampini       matis->islocalref = NULL;
10469566063dSJacob Faibussowitsch       PetscCall(MatISSetUpScatters_Private(B));
10478546b261SStefano Zampini     }
10489566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
10499566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
10505e3038f0Sstefano_zampini     if (reuse == MAT_INPLACE_MATRIX) {
10519566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(A, &B));
10525e3038f0Sstefano_zampini     } else {
10535e3038f0Sstefano_zampini       *newmat = B;
10545e3038f0Sstefano_zampini     }
10555e3038f0Sstefano_zampini   } else {
10565e3038f0Sstefano_zampini     if (lreuse) {
10579566063dSJacob Faibussowitsch       PetscCall(MatISGetLocalMat(*newmat, &lA));
10585e3038f0Sstefano_zampini       for (i = 0; i < nr; i++) {
10595e3038f0Sstefano_zampini         for (j = 0; j < nc; j++) {
10605e3038f0Sstefano_zampini           if (snest[i * nc + j]) {
10619566063dSJacob Faibussowitsch             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
106248a46eb9SPierre Jolivet             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
10635e3038f0Sstefano_zampini           }
10645e3038f0Sstefano_zampini         }
10655e3038f0Sstefano_zampini       }
10665e3038f0Sstefano_zampini     } else {
10675b003df0Sstefano_zampini       PetscInt stl;
10685b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nr; i++) {
10699566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
10705b003df0Sstefano_zampini         stl += lr[i];
10715e3038f0Sstefano_zampini       }
10725b003df0Sstefano_zampini       for (i = 0, stl = 0; i < nc; i++) {
10739566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
10745b003df0Sstefano_zampini         stl += lc[i];
10755e3038f0Sstefano_zampini       }
10769566063dSJacob Faibussowitsch       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1077ab4d48faSStefano Zampini       for (i = 0; i < nr * nc; i++) {
107848a46eb9SPierre Jolivet         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1079ab4d48faSStefano Zampini       }
10809566063dSJacob Faibussowitsch       PetscCall(MatISSetLocalMat(*newmat, lA));
10819566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&lA));
10825e3038f0Sstefano_zampini     }
10839566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
10849566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
10855e3038f0Sstefano_zampini   }
10865e3038f0Sstefano_zampini 
10875b003df0Sstefano_zampini   /* Create local matrix in MATNEST format */
10885b003df0Sstefano_zampini   convert = PETSC_FALSE;
10894f58015eSStefano Zampini   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
10905b003df0Sstefano_zampini   if (convert) {
10915b003df0Sstefano_zampini     Mat              M;
10925b003df0Sstefano_zampini     MatISLocalFields lf;
10935b003df0Sstefano_zampini 
10949566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &lA));
10959566063dSJacob Faibussowitsch     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
10969566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, M));
10979566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&M));
10985b003df0Sstefano_zampini 
10995b003df0Sstefano_zampini     /* attach local fields to the matrix */
11009566063dSJacob Faibussowitsch     PetscCall(PetscNew(&lf));
11019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
11025b003df0Sstefano_zampini     for (i = 0; i < nr; i++) {
11035b003df0Sstefano_zampini       PetscInt n, st;
11045b003df0Sstefano_zampini 
11059566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islrow[i], &n));
11069566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
11079566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
11085b003df0Sstefano_zampini     }
11095b003df0Sstefano_zampini     for (i = 0; i < nc; i++) {
11105b003df0Sstefano_zampini       PetscInt n, st;
11115b003df0Sstefano_zampini 
11129566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islcol[i], &n));
11139566063dSJacob Faibussowitsch       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
11149566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
11155b003df0Sstefano_zampini     }
11165b003df0Sstefano_zampini     lf->nr = nr;
11175b003df0Sstefano_zampini     lf->nc = nc;
111803e76207SPierre Jolivet     PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private));
11195b003df0Sstefano_zampini   }
11205b003df0Sstefano_zampini 
11215e3038f0Sstefano_zampini   /* Free workspace */
112248a46eb9SPierre Jolivet   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
112348a46eb9SPierre Jolivet   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
11249566063dSJacob Faibussowitsch   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
11259566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lr, lc));
11263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11275e3038f0Sstefano_zampini }
11285e3038f0Sstefano_zampini 
1129d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1130d71ae5a4SJacob Faibussowitsch {
1131ad219c80Sstefano_zampini   Mat_IS            *matis = (Mat_IS *)A->data;
1132ad219c80Sstefano_zampini   Vec                ll, rr;
1133ad219c80Sstefano_zampini   const PetscScalar *Y, *X;
1134ad219c80Sstefano_zampini   PetscScalar       *x, *y;
1135ad219c80Sstefano_zampini 
1136ad219c80Sstefano_zampini   PetscFunctionBegin;
1137ad219c80Sstefano_zampini   if (l) {
1138ad219c80Sstefano_zampini     ll = matis->y;
11399566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(l, &Y));
11409566063dSJacob Faibussowitsch     PetscCall(VecGetArray(ll, &y));
11419566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1142ad219c80Sstefano_zampini   } else {
1143ad219c80Sstefano_zampini     ll = NULL;
1144ad219c80Sstefano_zampini   }
1145ad219c80Sstefano_zampini   if (r) {
1146ad219c80Sstefano_zampini     rr = matis->x;
11479566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(r, &X));
11489566063dSJacob Faibussowitsch     PetscCall(VecGetArray(rr, &x));
11499566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1150ad219c80Sstefano_zampini   } else {
1151ad219c80Sstefano_zampini     rr = NULL;
1152ad219c80Sstefano_zampini   }
1153ad219c80Sstefano_zampini   if (ll) {
11549566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
11559566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(l, &Y));
11569566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(ll, &y));
1157ad219c80Sstefano_zampini   }
1158ad219c80Sstefano_zampini   if (rr) {
11599566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
11609566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(r, &X));
11619566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(rr, &x));
1162ad219c80Sstefano_zampini   }
11639566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(matis->A, ll, rr));
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1165ad219c80Sstefano_zampini }
1166ad219c80Sstefano_zampini 
1167d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1168d71ae5a4SJacob Faibussowitsch {
11697fa8f2d3SStefano Zampini   Mat_IS        *matis = (Mat_IS *)A->data;
11707fa8f2d3SStefano Zampini   MatInfo        info;
11713966268fSBarry Smith   PetscLogDouble isend[6], irecv[6];
11727fa8f2d3SStefano Zampini   PetscInt       bs;
11737fa8f2d3SStefano Zampini 
11747fa8f2d3SStefano Zampini   PetscFunctionBegin;
11759566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(A, &bs));
1176a2ccb5f9Sstefano_zampini   if (matis->A->ops->getinfo) {
11779566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
11787fa8f2d3SStefano Zampini     isend[0] = info.nz_used;
11797fa8f2d3SStefano Zampini     isend[1] = info.nz_allocated;
11807fa8f2d3SStefano Zampini     isend[2] = info.nz_unneeded;
11817fa8f2d3SStefano Zampini     isend[3] = info.memory;
11827fa8f2d3SStefano Zampini     isend[4] = info.mallocs;
1183a2ccb5f9Sstefano_zampini   } else {
1184a2ccb5f9Sstefano_zampini     isend[0] = 0.;
1185a2ccb5f9Sstefano_zampini     isend[1] = 0.;
1186a2ccb5f9Sstefano_zampini     isend[2] = 0.;
1187a2ccb5f9Sstefano_zampini     isend[3] = 0.;
1188a2ccb5f9Sstefano_zampini     isend[4] = 0.;
1189a2ccb5f9Sstefano_zampini   }
1190314ce898Sstefano_zampini   isend[5] = matis->A->num_ass;
11917fa8f2d3SStefano Zampini   if (flag == MAT_LOCAL) {
11927fa8f2d3SStefano Zampini     ginfo->nz_used      = isend[0];
11937fa8f2d3SStefano Zampini     ginfo->nz_allocated = isend[1];
11947fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = isend[2];
11957fa8f2d3SStefano Zampini     ginfo->memory       = isend[3];
11967fa8f2d3SStefano Zampini     ginfo->mallocs      = isend[4];
1197314ce898Sstefano_zampini     ginfo->assemblies   = isend[5];
11987fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_MAX) {
1199462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
12007fa8f2d3SStefano Zampini 
12017fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12027fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12037fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12047fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12057fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
1206314ce898Sstefano_zampini     ginfo->assemblies   = irecv[5];
12077fa8f2d3SStefano Zampini   } else if (flag == MAT_GLOBAL_SUM) {
1208462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
12097fa8f2d3SStefano Zampini 
12107fa8f2d3SStefano Zampini     ginfo->nz_used      = irecv[0];
12117fa8f2d3SStefano Zampini     ginfo->nz_allocated = irecv[1];
12127fa8f2d3SStefano Zampini     ginfo->nz_unneeded  = irecv[2];
12137fa8f2d3SStefano Zampini     ginfo->memory       = irecv[3];
12147fa8f2d3SStefano Zampini     ginfo->mallocs      = irecv[4];
12157fa8f2d3SStefano Zampini     ginfo->assemblies   = A->num_ass;
12167fa8f2d3SStefano Zampini   }
12177fa8f2d3SStefano Zampini   ginfo->block_size        = bs;
12187fa8f2d3SStefano Zampini   ginfo->fill_ratio_given  = 0;
12197fa8f2d3SStefano Zampini   ginfo->fill_ratio_needed = 0;
12207fa8f2d3SStefano Zampini   ginfo->factor_mallocs    = 0;
12213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12225e3038f0Sstefano_zampini }
12235e3038f0Sstefano_zampini 
1224d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1225d71ae5a4SJacob Faibussowitsch {
1226d7f69cd0SStefano Zampini   Mat C, lC, lA;
1227d7f69cd0SStefano Zampini 
1228d7f69cd0SStefano Zampini   PetscFunctionBegin;
12297fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1230cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1231cf37664fSBarry Smith     ISLocalToGlobalMapping rl2g, cl2g;
12324f58015eSStefano Zampini     PetscBool              allow_repeated;
12334f58015eSStefano Zampini 
12349566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
12359566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
123658b7e2c1SStefano Zampini     PetscCall(MatSetBlockSizes(C, A->cmap->bs, A->rmap->bs));
12379566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, MATIS));
12384f58015eSStefano Zampini     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
12394f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
12409566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
12419566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1242e432b41dSStefano Zampini   } else C = *B;
1243d7f69cd0SStefano Zampini 
1244d7f69cd0SStefano Zampini   /* perform local transposition */
12459566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
12469566063dSJacob Faibussowitsch   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
12479566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
12489566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(C, lC));
12499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lC));
1250d7f69cd0SStefano Zampini 
1251cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1252d7f69cd0SStefano Zampini     *B = C;
1253d7f69cd0SStefano Zampini   } else {
12549566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
1255d7f69cd0SStefano Zampini   }
12569566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
12579566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
12583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1259d7f69cd0SStefano Zampini }
1260d7f69cd0SStefano Zampini 
1261d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1262d71ae5a4SJacob Faibussowitsch {
12633fd1c9e7SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12643fd1c9e7SStefano Zampini 
12653fd1c9e7SStefano Zampini   PetscFunctionBegin;
12664f58015eSStefano Zampini   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
12674b89b9cdSStefano Zampini   if (D) { /* MatShift_IS pass D = NULL */
12689566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12699566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
12703fd1c9e7SStefano Zampini   }
12719566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
12729566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
12733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12743fd1c9e7SStefano Zampini }
12753fd1c9e7SStefano Zampini 
1276d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1277d71ae5a4SJacob Faibussowitsch {
12784b89b9cdSStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
12793fd1c9e7SStefano Zampini 
12803fd1c9e7SStefano Zampini   PetscFunctionBegin;
12819566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, a));
12829566063dSJacob Faibussowitsch   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
12833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12843fd1c9e7SStefano Zampini }
12853fd1c9e7SStefano Zampini 
1286d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1287d71ae5a4SJacob Faibussowitsch {
1288f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1289f26d0771SStefano Zampini 
1290f26d0771SStefano Zampini   PetscFunctionBegin;
1291aed4548fSBarry 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);
12929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
12939566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
12949566063dSJacob Faibussowitsch   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
12953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1296f26d0771SStefano Zampini }
1297f26d0771SStefano Zampini 
1298d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1299d71ae5a4SJacob Faibussowitsch {
1300f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1301f26d0771SStefano Zampini 
1302f26d0771SStefano Zampini   PetscFunctionBegin;
1303aed4548fSBarry 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);
13049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
13059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
13069566063dSJacob Faibussowitsch   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
13073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1308f26d0771SStefano Zampini }
1309f26d0771SStefano Zampini 
1310*0d2733adSStefano Zampini static PetscErrorCode MatZeroRowsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
1311*0d2733adSStefano Zampini {
1312*0d2733adSStefano Zampini   PetscInt *rows_l;
1313*0d2733adSStefano Zampini   Mat_IS   *is = (Mat_IS *)A->data;
1314*0d2733adSStefano Zampini 
1315*0d2733adSStefano Zampini   PetscFunctionBegin;
1316*0d2733adSStefano Zampini   PetscCall(PetscMalloc1(n, &rows_l));
1317*0d2733adSStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l));
1318*0d2733adSStefano Zampini   PetscCall(MatZeroRowsLocal(is->islocalref, n, rows_l, diag, x, b));
1319*0d2733adSStefano Zampini   PetscCall(PetscFree(rows_l));
1320*0d2733adSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1321*0d2733adSStefano Zampini }
1322*0d2733adSStefano Zampini 
1323*0d2733adSStefano Zampini static PetscErrorCode MatZeroRowsColumnsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
1324*0d2733adSStefano Zampini {
1325*0d2733adSStefano Zampini   PetscInt *rows_l;
1326*0d2733adSStefano Zampini   Mat_IS   *is = (Mat_IS *)A->data;
1327*0d2733adSStefano Zampini 
1328*0d2733adSStefano Zampini   PetscFunctionBegin;
1329*0d2733adSStefano Zampini   PetscCall(PetscMalloc1(n, &rows_l));
1330*0d2733adSStefano Zampini   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l));
1331*0d2733adSStefano Zampini   PetscCall(MatZeroRowsColumnsLocal(is->islocalref, n, rows_l, diag, x, b));
1332*0d2733adSStefano Zampini   PetscCall(PetscFree(rows_l));
1333*0d2733adSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1334*0d2733adSStefano Zampini }
1335*0d2733adSStefano Zampini 
1336d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1337d71ae5a4SJacob Faibussowitsch {
1338a8116848SStefano Zampini   Mat             locmat, newlocmat;
1339a8116848SStefano Zampini   Mat_IS         *newmatis;
1340a8116848SStefano Zampini   const PetscInt *idxs;
1341a8116848SStefano Zampini   PetscInt        i, m, n;
1342a8116848SStefano Zampini 
1343a8116848SStefano Zampini   PetscFunctionBegin;
1344a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1345a8116848SStefano Zampini     PetscBool ismatis;
1346a8116848SStefano Zampini 
13479566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
134828b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1349a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
135028b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
135128b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1352a8116848SStefano Zampini   }
1353a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
135476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
135576bd3646SJed Brown     Vec                rtest, ltest;
135676bd3646SJed Brown     const PetscScalar *array;
135776bd3646SJed Brown 
13589566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13599566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13609566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
136148a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13629566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13639566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13649566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13659566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13669566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1367aed4548fSBarry 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]));
13689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13699566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13709566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13719566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
137248a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13739566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13749566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13759566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13769566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13779566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1378aed4548fSBarry 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]));
13799566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13809566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13829566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
138376bd3646SJed Brown   }
1384a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1385a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1386a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1387a8116848SStefano Zampini     IS                     is;
1388a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1389306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
139094342113SStefano Zampini     PetscBool              cong;
1391a8116848SStefano Zampini     MPI_Comm               comm;
1392a8116848SStefano Zampini 
13939566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13949566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13959566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13969566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1397306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1398306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13999566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
14009566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
14019566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
14029566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
14034f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
14049566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
14059566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1406a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
14079566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
14089566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
14099566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
14109566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1411a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14129566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
14139566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
14149566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14159566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
14169371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
14179371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
14189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
14199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
14203d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1421a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1422a8116848SStefano Zampini         lidxs[newloc]      = i;
1423a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1424a8116848SStefano Zampini       }
14259566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14279566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14289566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1429a8116848SStefano Zampini     /* local is to extract local submatrix */
1430a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14319566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14329566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
143394342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14349566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14359566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1436a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1437a8116848SStefano Zampini     } else {
1438a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1439a8116848SStefano Zampini 
1440a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14419566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14429566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14449566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1445a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14469566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14479566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14489566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14499566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14509371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14519371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14543d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1455a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1456a8116848SStefano Zampini           lidxs[newloc]      = i;
1457a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1458a8116848SStefano Zampini         }
14599566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14609566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14619566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14629566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1463a8116848SStefano Zampini       /* local is to extract local submatrix */
14649566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14659566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14669566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1467a8116848SStefano Zampini     }
14689566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1469a8116848SStefano Zampini   } else {
14709566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1471a8116848SStefano Zampini   }
14729566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1473a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14749566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1475a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14769566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14779566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1478a8116848SStefano Zampini   }
14799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1482a8116848SStefano Zampini }
1483a8116848SStefano Zampini 
1484d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1485d71ae5a4SJacob Faibussowitsch {
14862b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14872b404112SStefano Zampini   PetscBool ismatis;
14882b404112SStefano Zampini 
14892b404112SStefano Zampini   PetscFunctionBegin;
14909566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
149128b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14922b404112SStefano Zampini   b = (Mat_IS *)B->data;
14939566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14949566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14962b404112SStefano Zampini }
14972b404112SStefano Zampini 
1498d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1499d71ae5a4SJacob Faibussowitsch {
1500527b2640SStefano Zampini   Vec                v;
1501527b2640SStefano Zampini   const PetscScalar *array;
1502527b2640SStefano Zampini   PetscInt           i, n;
15036bd84002SStefano Zampini 
15046bd84002SStefano Zampini   PetscFunctionBegin;
1505527b2640SStefano Zampini   *missing = PETSC_FALSE;
15069566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
15079566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
15089566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
15099566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
15109371c9d4SSatish Balay   for (i = 0; i < n; i++)
15119371c9d4SSatish Balay     if (array[i] == 0.) break;
15129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
15139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1514527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1515527b2640SStefano Zampini   if (d) {
1516527b2640SStefano Zampini     *d = -1;
1517527b2640SStefano Zampini     if (*missing) {
1518527b2640SStefano Zampini       PetscInt rstart;
15199566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1520527b2640SStefano Zampini       *d = i + rstart;
1521527b2640SStefano Zampini     }
1522527b2640SStefano Zampini   }
15233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15246bd84002SStefano Zampini }
15256bd84002SStefano Zampini 
1526d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1527d71ae5a4SJacob Faibussowitsch {
1528f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
152928f4e0baSStefano Zampini   const PetscInt *gidxs;
15304f2d7cafSStefano Zampini   PetscInt        nleaves;
153128f4e0baSStefano Zampini 
153228f4e0baSStefano Zampini   PetscFunctionBegin;
15333ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15349566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15359566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15379566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1540e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15419566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15429566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15439566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15449566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15459566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1547a8116848SStefano Zampini   } else {
1548a8116848SStefano Zampini     matis->csf          = matis->sf;
1549a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1550a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1551a8116848SStefano Zampini   }
15523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155328f4e0baSStefano Zampini }
15542e1947a5SStefano Zampini 
1555eb82efa4SStefano Zampini /*@
15564f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15574f58015eSStefano Zampini 
15584f58015eSStefano Zampini   Not Collective
15594f58015eSStefano Zampini 
15604f58015eSStefano Zampini   Input Parameter:
15614f58015eSStefano Zampini . A - the matrix
15624f58015eSStefano Zampini 
15634f58015eSStefano Zampini   Output Parameter:
15644f58015eSStefano Zampini . flg - the boolean flag
15654f58015eSStefano Zampini 
15664f58015eSStefano Zampini   Level: intermediate
15674f58015eSStefano Zampini 
15684f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
15694f58015eSStefano Zampini @*/
15704f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
15714f58015eSStefano Zampini {
15724f58015eSStefano Zampini   PetscBool ismatis;
15734f58015eSStefano Zampini 
15744f58015eSStefano Zampini   PetscFunctionBegin;
15754f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15764f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
15774f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
15784f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
15794f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
15804f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15814f58015eSStefano Zampini }
15824f58015eSStefano Zampini 
15834f58015eSStefano Zampini /*@
15844f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
15854f58015eSStefano Zampini 
15864f58015eSStefano Zampini   Logically Collective
15874f58015eSStefano Zampini 
15884f58015eSStefano Zampini   Input Parameters:
15894f58015eSStefano Zampini + A   - the matrix
15904f58015eSStefano Zampini - flg - the boolean flag
15914f58015eSStefano Zampini 
15924f58015eSStefano Zampini   Level: intermediate
15934f58015eSStefano Zampini 
15944f58015eSStefano Zampini   Notes:
15954f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
15964f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
15974f58015eSStefano Zampini   if `flg` is different from the previously set value.
15984f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
15994f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
16004f58015eSStefano Zampini 
16014f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
16024f58015eSStefano Zampini @*/
16034f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
16044f58015eSStefano Zampini {
16054f58015eSStefano Zampini   PetscFunctionBegin;
16064f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
16074f58015eSStefano Zampini   PetscValidType(A, 1);
16084f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
16094f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
16104f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16114f58015eSStefano Zampini }
16124f58015eSStefano Zampini 
16134f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
16144f58015eSStefano Zampini {
16154f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
16164f58015eSStefano Zampini   Mat                    lA    = NULL;
16174f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
16184f58015eSStefano Zampini 
16194f58015eSStefano Zampini   PetscFunctionBegin;
16204f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
16214f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
16224f58015eSStefano Zampini     matis->allow_repeated = flg;
16234f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
16244f58015eSStefano Zampini   }
16254f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16264f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16274f58015eSStefano Zampini     lA = matis->A;
16284f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16294f58015eSStefano Zampini   }
16304f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16314f58015eSStefano Zampini   matis->allow_repeated = flg;
16324f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16334f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16344f58015eSStefano Zampini     Mat nA = matis->A;
16354f58015eSStefano Zampini 
16364f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16374f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16384f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16394f58015eSStefano Zampini     } else {
16404f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16414f58015eSStefano Zampini       MatProductType ptype;
16424f58015eSStefano Zampini 
16434f58015eSStefano Zampini       if (lrmap == lcmap) {
16444f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16454f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16464f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16474f58015eSStefano Zampini       } else {
16484f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16494f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16504f58015eSStefano Zampini         if (R && P) {
16514f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16524f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16534f58015eSStefano Zampini         } else if (R) {
16544f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16554f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16564f58015eSStefano Zampini         } else {
16574f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16584f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16594f58015eSStefano Zampini         }
16604f58015eSStefano Zampini       }
16614f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16624f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16634f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16644f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16654f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16664f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16674f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16684f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
16694f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
16704f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
16714f58015eSStefano Zampini     }
16724f58015eSStefano Zampini   }
16734f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
16744f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16754f58015eSStefano Zampini }
16764f58015eSStefano Zampini 
16774f58015eSStefano Zampini /*@
16782ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
167975d48cdbSStefano Zampini 
16804f58015eSStefano Zampini   Logically Collective
168175d48cdbSStefano Zampini 
168275d48cdbSStefano Zampini   Input Parameters:
168375d48cdbSStefano Zampini + A     - the matrix
168475d48cdbSStefano Zampini - store - the boolean flag
168575d48cdbSStefano Zampini 
168675d48cdbSStefano Zampini   Level: advanced
168775d48cdbSStefano Zampini 
16881cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
168975d48cdbSStefano Zampini @*/
1690d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1691d71ae5a4SJacob Faibussowitsch {
169275d48cdbSStefano Zampini   PetscFunctionBegin;
169375d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
169475d48cdbSStefano Zampini   PetscValidType(A, 1);
169575d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1696cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
16973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
169875d48cdbSStefano Zampini }
169975d48cdbSStefano Zampini 
1700d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1701d71ae5a4SJacob Faibussowitsch {
1702f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
170375d48cdbSStefano Zampini 
170475d48cdbSStefano Zampini   PetscFunctionBegin;
170575d48cdbSStefano Zampini   matis->storel2l = store;
170657508eceSPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
17073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
170875d48cdbSStefano Zampini }
170975d48cdbSStefano Zampini 
171075d48cdbSStefano Zampini /*@
1711f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1712f03112d0SStefano Zampini 
17134f58015eSStefano Zampini   Logically Collective
1714f03112d0SStefano Zampini 
1715f03112d0SStefano Zampini   Input Parameters:
1716f03112d0SStefano Zampini + A   - the matrix
1717f03112d0SStefano Zampini - fix - the boolean flag
1718f03112d0SStefano Zampini 
1719f03112d0SStefano Zampini   Level: advanced
1720f03112d0SStefano Zampini 
172111a5261eSBarry Smith   Note:
17222fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1723f03112d0SStefano Zampini 
17241cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1725f03112d0SStefano Zampini @*/
1726d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1727d71ae5a4SJacob Faibussowitsch {
1728f03112d0SStefano Zampini   PetscFunctionBegin;
1729f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1730f03112d0SStefano Zampini   PetscValidType(A, 1);
1731f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1732cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1734f03112d0SStefano Zampini }
1735f03112d0SStefano Zampini 
1736d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1737d71ae5a4SJacob Faibussowitsch {
1738f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1739f03112d0SStefano Zampini 
1740f03112d0SStefano Zampini   PetscFunctionBegin;
1741f03112d0SStefano Zampini   matis->locempty = fix;
17423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1743f03112d0SStefano Zampini }
1744f03112d0SStefano Zampini 
1745f03112d0SStefano Zampini /*@
174611a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1747a88811baSStefano Zampini 
1748d083f849SBarry Smith   Collective
1749a88811baSStefano Zampini 
1750a88811baSStefano Zampini   Input Parameters:
1751a88811baSStefano Zampini + B     - the matrix
1752a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1753a88811baSStefano Zampini            (same value is used for all local rows)
1754a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1755a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17562ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17572ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1758a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1759a88811baSStefano Zampini            the diagonal entry even if it is zero.
1760a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1761a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1762a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1763a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17642ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1765a88811baSStefano Zampini            structure. The size of this array is equal to the number
17662ef1f0ffSBarry Smith            of local rows, i.e `m`.
1767a88811baSStefano Zampini 
1768a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1769a88811baSStefano Zampini 
1770a88811baSStefano Zampini   Level: intermediate
1771a88811baSStefano Zampini 
177211a5261eSBarry Smith   Note:
177311a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
177411a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1775a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1776a88811baSStefano Zampini 
17771cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1778a88811baSStefano Zampini @*/
1779d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1780d71ae5a4SJacob Faibussowitsch {
17812e1947a5SStefano Zampini   PetscFunctionBegin;
17822e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
17832e1947a5SStefano Zampini   PetscValidType(B, 1);
1784cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
17853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17862e1947a5SStefano Zampini }
17872e1947a5SStefano Zampini 
1788523895eeSPierre Jolivet static PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1789d71ae5a4SJacob Faibussowitsch {
1790f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
179128f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
17922e1947a5SStefano Zampini 
17932e1947a5SStefano Zampini   PetscFunctionBegin;
17949566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
17959371c9d4SSatish Balay   if (!d_nnz)
17969371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
17979371c9d4SSatish Balay   else
17989371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
17994f2d7cafSStefano Zampini 
18009371c9d4SSatish Balay   if (!o_nnz)
18019371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
18029371c9d4SSatish Balay   else
18039371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
18044f2d7cafSStefano Zampini 
18059566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
18079566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
18089566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
18094f2d7cafSStefano Zampini 
18104f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
18119566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
18120f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
18139566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
18140f2f62c7SStefano Zampini #endif
18154f2d7cafSStefano Zampini 
1816fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1817fc989267SStefano Zampini     PetscInt b;
1818fc989267SStefano Zampini 
1819fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1820ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1821fc989267SStefano Zampini   }
18229566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18234f2d7cafSStefano Zampini 
182400a59248SStefano Zampini   nlocalcols /= bs;
182500a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18269566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18270f2f62c7SStefano Zampini 
18280f2f62c7SStefano Zampini   /* for other matrix types */
18299566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18312e1947a5SStefano Zampini }
1832b4319ba4SBarry Smith 
1833d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1834d71ae5a4SJacob Faibussowitsch {
1835f4f49eeaSPierre Jolivet   Mat_IS            *matis     = (Mat_IS *)mat->data;
1836ac7f1a8bSStefano Zampini   Mat                local_mat = NULL, MT;
183753b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1838b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1839b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1840f03112d0SStefano Zampini   PetscMPIInt        size;
18411683a169SBarry Smith   const PetscScalar *array;
1842b7ce53b6SStefano Zampini 
1843b7ce53b6SStefano Zampini   PetscFunctionBegin;
18449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
18454f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
18461670daf9Sstefano_zampini     Mat      B;
184753b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1848487b449aSStefano Zampini     PetscInt rbs, cbs;
18491670daf9Sstefano_zampini 
18509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18519566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
185253b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
185353b44cf5SStefano Zampini       IS              rows, cols;
185453b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
18554f58015eSStefano Zampini       PetscInt        i, nw;
18564f58015eSStefano Zampini       PetscBT         work;
185753b44cf5SStefano Zampini 
18589566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18599566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
186053b44cf5SStefano Zampini       nw = nw / rbs;
18614f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
18624f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
18639371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18644f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
186553b44cf5SStefano Zampini       if (i == nw) {
18669566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18679566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18689566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18699566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
187053b44cf5SStefano Zampini       }
18719566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18724f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
1873e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18749566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18759566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
187653b44cf5SStefano Zampini         nw = nw / cbs;
18774f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
18784f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
18799371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18804f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
188153b44cf5SStefano Zampini         if (i == nw) {
18829566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18839566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18849566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18859566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
188653b44cf5SStefano Zampini         }
18879566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
18884f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
188953b44cf5SStefano Zampini       } else if (irows) {
18909566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
189153b44cf5SStefano Zampini         icols = irows;
189253b44cf5SStefano Zampini       }
189353b44cf5SStefano Zampini     } else {
1894f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
1895f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
18969566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
18979566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
189853b44cf5SStefano Zampini     }
189953b44cf5SStefano Zampini     if (!irows || !icols) {
19009566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
19019566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
190253b44cf5SStefano Zampini       goto general_assembly;
190353b44cf5SStefano Zampini     }
19049566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1905487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
19069566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
1907f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
1908f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1909487b449aSStefano Zampini     } else {
1910487b449aSStefano Zampini       Mat C;
1911487b449aSStefano Zampini 
19129566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
19139566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1914487b449aSStefano Zampini     }
19159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
19169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
19179566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
19183ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19197c03b4e8SStefano Zampini   }
192053b44cf5SStefano Zampini general_assembly:
19219566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
19229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
19239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
19249566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
19259566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19269566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19279566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19289566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19299566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1930f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
193176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
193276bd3646SJed Brown     PetscBool lb[4], bb[4];
193376bd3646SJed Brown 
1934b9ed4604SStefano Zampini     lb[0] = isseqdense;
1935b9ed4604SStefano Zampini     lb[1] = isseqaij;
1936b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1937b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
1938462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1939aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
194076bd3646SJed Brown   }
1941b7ce53b6SStefano Zampini 
1942487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
1943ac7f1a8bSStefano Zampini     PetscCount ncoo;
1944ac7f1a8bSStefano Zampini     PetscInt  *coo_i, *coo_j;
1945ac7f1a8bSStefano Zampini 
19469566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19479566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19489566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19499566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
1950ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
1951ac7f1a8bSStefano Zampini       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1952ac7f1a8bSStefano Zampini     } else {
1953ac7f1a8bSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
1954ac7f1a8bSStefano Zampini       local_mat = matis->A;
1955ac7f1a8bSStefano Zampini     }
1956ac7f1a8bSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1957ac7f1a8bSStefano Zampini     if (isseqdense) {
1958ac7f1a8bSStefano Zampini       PetscInt nr, nc;
1959ac7f1a8bSStefano Zampini 
1960ac7f1a8bSStefano Zampini       PetscCall(MatGetSize(local_mat, &nr, &nc));
1961ac7f1a8bSStefano Zampini       ncoo = nr * nc;
1962ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1963ac7f1a8bSStefano Zampini       for (PetscInt j = 0; j < nc; j++) {
1964ac7f1a8bSStefano Zampini         for (PetscInt i = 0; i < nr; i++) {
1965ac7f1a8bSStefano Zampini           coo_i[j * nr + i] = i;
1966ac7f1a8bSStefano Zampini           coo_j[j * nr + i] = j;
1967ac7f1a8bSStefano Zampini         }
1968ac7f1a8bSStefano Zampini       }
1969ac7f1a8bSStefano Zampini     } else {
1970ac7f1a8bSStefano Zampini       const PetscInt *ii, *jj;
1971ac7f1a8bSStefano Zampini       PetscInt        nr;
1972ac7f1a8bSStefano Zampini       PetscBool       done;
1973ac7f1a8bSStefano Zampini 
1974ac7f1a8bSStefano Zampini       PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1975ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1976ac7f1a8bSStefano Zampini       ncoo = ii[nr];
1977ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1978ac7f1a8bSStefano Zampini       PetscCall(PetscArraycpy(coo_j, jj, ncoo));
1979ac7f1a8bSStefano Zampini       for (PetscInt i = 0; i < nr; i++) {
1980ac7f1a8bSStefano Zampini         for (PetscInt j = ii[i]; j < ii[i + 1]; j++) coo_i[j] = i;
1981ac7f1a8bSStefano Zampini       }
1982ac7f1a8bSStefano Zampini       PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1983ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1984ac7f1a8bSStefano Zampini     }
1985ac7f1a8bSStefano Zampini     PetscCall(MatSetPreallocationCOOLocal(MT, ncoo, coo_i, coo_j));
1986ac7f1a8bSStefano Zampini     PetscCall(PetscFree2(coo_i, coo_j));
1987b7ce53b6SStefano Zampini   } else {
198853b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1989487b449aSStefano Zampini 
1990b7ce53b6SStefano Zampini     /* some checks */
1991487b449aSStefano Zampini     MT = *M;
19929566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19939566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19949566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
199508401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
199608401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
199708401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
199808401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
199908401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
200008401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
20019566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
2002ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
20039566063dSJacob Faibussowitsch       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
2004d9a9e74cSStefano Zampini     } else {
20059566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)matis->A));
2006d9a9e74cSStefano Zampini       local_mat = matis->A;
2007d9a9e74cSStefano Zampini     }
2008ac7f1a8bSStefano Zampini   }
2009686e3a49SStefano Zampini 
2010b7ce53b6SStefano Zampini   /* Set values */
2011ac7f1a8bSStefano Zampini   if (isseqdense) {
20129566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
2013ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
20149566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
20156afe12f5SStefano Zampini   } else {
2016ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(local_mat, &array));
2017ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
2018ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(local_mat, &array));
2019b7ce53b6SStefano Zampini   }
20209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
20214f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
20229566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
2023487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
20249566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
2025487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2026487b449aSStefano Zampini     *M = MT;
2027b7ce53b6SStefano Zampini   }
20283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2029b7ce53b6SStefano Zampini }
2030b7ce53b6SStefano Zampini 
2031d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2032d71ae5a4SJacob Faibussowitsch {
2033f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2034c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2035ad6194a2SStefano Zampini   Mat      B, localmat;
2036ad6194a2SStefano Zampini 
2037ad6194a2SStefano Zampini   PetscFunctionBegin;
20389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20399566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20409566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20419566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20429566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20439566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20449566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20459566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20469566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20474f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
20489566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20499566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
20509566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
20519566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
20529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
20539566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
20549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2055ad6194a2SStefano Zampini   *newmat = B;
20563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2057ad6194a2SStefano Zampini }
2058ad6194a2SStefano Zampini 
2059d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2060d71ae5a4SJacob Faibussowitsch {
206169796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
206269796d55SStefano Zampini   PetscBool local_sym;
206369796d55SStefano Zampini 
206469796d55SStefano Zampini   PetscFunctionBegin;
20659566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
2066462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
206869796d55SStefano Zampini }
206969796d55SStefano Zampini 
2070d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2071d71ae5a4SJacob Faibussowitsch {
207269796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
207369796d55SStefano Zampini   PetscBool local_sym;
207469796d55SStefano Zampini 
207569796d55SStefano Zampini   PetscFunctionBegin;
2076e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2077e432b41dSStefano Zampini     *flg = PETSC_FALSE;
20783ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2079e432b41dSStefano Zampini   }
20809566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
2081462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
208369796d55SStefano Zampini }
208469796d55SStefano Zampini 
2085d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2086d71ae5a4SJacob Faibussowitsch {
208745471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
208845471136SStefano Zampini   PetscBool local_sym;
208945471136SStefano Zampini 
209045471136SStefano Zampini   PetscFunctionBegin;
2091e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
209245471136SStefano Zampini     *flg = PETSC_FALSE;
20933ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
209445471136SStefano Zampini   }
20959566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
2096462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
209845471136SStefano Zampini }
209945471136SStefano Zampini 
2100d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2101d71ae5a4SJacob Faibussowitsch {
2102b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2103b4319ba4SBarry Smith 
2104b4319ba4SBarry Smith   PetscFunctionBegin;
21059566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
21069566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
21079566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
21089566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
21099566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
21109566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
21119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
21129566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
21139566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
21149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2115a8116848SStefano Zampini   if (b->sf != b->csf) {
21169566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
21179566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2118f03112d0SStefano Zampini   } else b->csf = NULL;
21199566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
21209566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
21219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
21229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2123d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2124d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
21259566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21269566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
21454f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
21463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2147b4319ba4SBarry Smith }
2148b4319ba4SBarry Smith 
2149d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2150d71ae5a4SJacob Faibussowitsch {
2151b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2152b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2153b4319ba4SBarry Smith 
2154b4319ba4SBarry Smith   PetscFunctionBegin;
2155b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
21569566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
21579566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2158b4319ba4SBarry Smith 
2159b4319ba4SBarry Smith   /* multiply the local matrix */
21609566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2161b4319ba4SBarry Smith 
2162b4319ba4SBarry Smith   /* scatter product back into global memory */
21639566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
21649566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21659566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2167b4319ba4SBarry Smith }
2168b4319ba4SBarry Smith 
2169d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2170d71ae5a4SJacob Faibussowitsch {
2171650997f4SStefano Zampini   Vec temp_vec;
21722e74eeadSLisandro Dalcin 
21732e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2174650997f4SStefano Zampini   if (v3 != v2) {
21759566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
21769566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2177650997f4SStefano Zampini   } else {
21789566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
21799566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
21809566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
21819566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
21829566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2183650997f4SStefano Zampini   }
21843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21852e74eeadSLisandro Dalcin }
21862e74eeadSLisandro Dalcin 
2187d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2188d71ae5a4SJacob Faibussowitsch {
21892e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
21902e74eeadSLisandro Dalcin 
2191e176bc59SStefano Zampini   PetscFunctionBegin;
21922e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
21939566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
21949566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
21952e74eeadSLisandro Dalcin 
21962e74eeadSLisandro Dalcin   /* multiply the local matrix */
21979566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
21982e74eeadSLisandro Dalcin 
21992e74eeadSLisandro Dalcin   /* scatter product back into global vector */
22009566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
22019566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22029566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
22033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22042e74eeadSLisandro Dalcin }
22052e74eeadSLisandro Dalcin 
2206d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2207d71ae5a4SJacob Faibussowitsch {
2208650997f4SStefano Zampini   Vec temp_vec;
22092e74eeadSLisandro Dalcin 
22102e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2211650997f4SStefano Zampini   if (v3 != v2) {
22129566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
22139566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2214650997f4SStefano Zampini   } else {
22159566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
22169566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
22179566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
22189566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
22199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2220650997f4SStefano Zampini   }
22213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22222e74eeadSLisandro Dalcin }
22232e74eeadSLisandro Dalcin 
2224a3ef7f04SStefano Zampini static PetscErrorCode ISLocalToGlobalMappingView_Multi(ISLocalToGlobalMapping mapping, PetscInt lsize, PetscInt gsize, const PetscInt vblocks[], PetscViewer viewer)
2225a3ef7f04SStefano Zampini {
2226a3ef7f04SStefano Zampini   PetscInt        tr[3], n;
2227a3ef7f04SStefano Zampini   const PetscInt *indices;
2228a3ef7f04SStefano Zampini 
2229a3ef7f04SStefano Zampini   PetscFunctionBegin;
2230a3ef7f04SStefano Zampini   tr[0] = IS_LTOGM_FILE_CLASSID;
2231a3ef7f04SStefano Zampini   tr[1] = 1;
2232a3ef7f04SStefano Zampini   tr[2] = gsize;
2233a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT));
2234a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWriteAll(viewer, vblocks, lsize, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
2235a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetSize(mapping, &n));
2236a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &indices));
2237a3ef7f04SStefano Zampini   PetscCall(PetscViewerBinaryWriteAll(viewer, indices, n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
2238a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &indices));
2239a3ef7f04SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2240a3ef7f04SStefano Zampini }
2241a3ef7f04SStefano Zampini 
2242d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2243d71ae5a4SJacob Faibussowitsch {
2244b4319ba4SBarry Smith   Mat_IS                *a = (Mat_IS *)A->data;
2245b4319ba4SBarry Smith   PetscViewer            sviewer;
22465042aa92SStefano Zampini   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
22475042aa92SStefano Zampini   PetscViewerFormat      format;
22485042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2249b4319ba4SBarry Smith 
2250b4319ba4SBarry Smith   PetscFunctionBegin;
22519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
22525042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
22539566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
22545042aa92SStefano Zampini   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
22555042aa92SStefano Zampini   if (native) {
22565042aa92SStefano Zampini     rmap = A->rmap->mapping;
22575042aa92SStefano Zampini     cmap = A->cmap->mapping;
22585042aa92SStefano Zampini   } else {
22595042aa92SStefano Zampini     rmap = a->rmapping;
22605042aa92SStefano Zampini     cmap = a->cmapping;
2261ee2491ecSStefano Zampini   }
22625042aa92SStefano Zampini   if (isascii) {
22635042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
22645042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
22655042aa92SStefano Zampini   } else if (isbinary) {
2266a3ef7f04SStefano Zampini     PetscInt        tr[6], nr, nc, lsize = 0;
22675042aa92SStefano Zampini     char            lmattype[64] = {'\0'};
22685042aa92SStefano Zampini     PetscMPIInt     size;
2269a3ef7f04SStefano Zampini     PetscBool       skipHeader, vbs = PETSC_FALSE;
22705042aa92SStefano Zampini     IS              is;
2271a3ef7f04SStefano Zampini     const PetscInt *vblocks = NULL;
22725042aa92SStefano Zampini 
22735042aa92SStefano Zampini     PetscCall(PetscViewerSetUp(viewer));
2274a3ef7f04SStefano Zampini     PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_view_variableblocksizes", &vbs, NULL));
2275a3ef7f04SStefano Zampini     if (vbs) {
2276a3ef7f04SStefano Zampini       PetscCall(MatGetVariableBlockSizes(a->A, &lsize, &vblocks));
2277a3ef7f04SStefano Zampini       PetscCall(PetscMPIIntCast(lsize, &size));
2278a3ef7f04SStefano Zampini       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &size, 1, MPI_INT, MPI_SUM, PetscObjectComm((PetscObject)viewer)));
2279a3ef7f04SStefano Zampini     } else {
22805042aa92SStefano Zampini       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2281a3ef7f04SStefano Zampini     }
22825042aa92SStefano Zampini     tr[0] = MAT_FILE_CLASSID;
22835042aa92SStefano Zampini     tr[1] = A->rmap->N;
22845042aa92SStefano Zampini     tr[2] = A->cmap->N;
22855042aa92SStefano Zampini     tr[3] = -size; /* AIJ stores nnz here */
22865042aa92SStefano Zampini     tr[4] = (PetscInt)(rmap == cmap);
22875042aa92SStefano Zampini     tr[5] = a->allow_repeated;
22885042aa92SStefano Zampini     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
22895042aa92SStefano Zampini 
22905042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
22915042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
22925042aa92SStefano Zampini 
22935042aa92SStefano Zampini     /* first dump l2g info (we need the header for proper loading on different number of processes) */
22945042aa92SStefano Zampini     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
22955042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
2296a3ef7f04SStefano Zampini     if (vbs) {
2297a3ef7f04SStefano Zampini       PetscCall(ISLocalToGlobalMappingView_Multi(rmap, lsize, size, vblocks, viewer));
2298a3ef7f04SStefano Zampini       if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView_Multi(cmap, lsize, size, vblocks, viewer));
2299a3ef7f04SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), lsize, vblocks, PETSC_USE_POINTER, &is));
2300a3ef7f04SStefano Zampini       PetscCall(ISView(is, viewer));
2301a3ef7f04SStefano Zampini       PetscCall(ISView(is, viewer));
2302a3ef7f04SStefano Zampini       PetscCall(ISDestroy(&is));
2303a3ef7f04SStefano Zampini     } else {
23045042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23055042aa92SStefano Zampini       if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23065042aa92SStefano Zampini 
23075042aa92SStefano Zampini       /* then the sizes of the local matrices */
23085042aa92SStefano Zampini       PetscCall(MatGetSize(a->A, &nr, &nc));
23095042aa92SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
23105042aa92SStefano Zampini       PetscCall(ISView(is, viewer));
23115042aa92SStefano Zampini       PetscCall(ISDestroy(&is));
23125042aa92SStefano Zampini       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
23135042aa92SStefano Zampini       PetscCall(ISView(is, viewer));
23145042aa92SStefano Zampini       PetscCall(ISDestroy(&is));
2315a3ef7f04SStefano Zampini     }
23165042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
23175042aa92SStefano Zampini   }
23185042aa92SStefano Zampini   if (format == PETSC_VIEWER_ASCII_MATLAB) {
23195042aa92SStefano Zampini     char        name[64];
23205042aa92SStefano Zampini     PetscMPIInt size, rank;
23215042aa92SStefano Zampini 
23225042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
23235042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
23245042aa92SStefano Zampini     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
23255042aa92SStefano Zampini     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
23265042aa92SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
23275042aa92SStefano Zampini   }
23285042aa92SStefano Zampini 
23295042aa92SStefano Zampini   /* Dump the local matrices */
23305042aa92SStefano Zampini   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
23315042aa92SStefano Zampini     PetscBool   isaij;
23325042aa92SStefano Zampini     PetscInt    nr, nc;
23335042aa92SStefano Zampini     Mat         lA, B;
23345042aa92SStefano Zampini     Mat_MPIAIJ *b;
23355042aa92SStefano Zampini 
23365042aa92SStefano Zampini     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
23375042aa92SStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
23385042aa92SStefano Zampini     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
23395042aa92SStefano Zampini     else {
23405042aa92SStefano Zampini       PetscCall(PetscObjectReference((PetscObject)a->A));
23415042aa92SStefano Zampini       lA = a->A;
23425042aa92SStefano Zampini     }
23435042aa92SStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
23445042aa92SStefano Zampini     PetscCall(MatSetType(B, MATMPIAIJ));
23455042aa92SStefano Zampini     PetscCall(MatGetSize(lA, &nr, &nc));
23465042aa92SStefano Zampini     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
23475042aa92SStefano Zampini     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
23485042aa92SStefano Zampini 
23495042aa92SStefano Zampini     b = (Mat_MPIAIJ *)B->data;
23505042aa92SStefano Zampini     PetscCall(MatDestroy(&b->A));
23515042aa92SStefano Zampini     b->A = lA;
23525042aa92SStefano Zampini 
23535042aa92SStefano Zampini     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
23545042aa92SStefano Zampini     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
23555042aa92SStefano Zampini     PetscCall(MatView(B, viewer));
23565042aa92SStefano Zampini     PetscCall(MatDestroy(&B));
23575042aa92SStefano Zampini   } else {
23589566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23599566063dSJacob Faibussowitsch     PetscCall(MatView(a->A, sviewer));
23609566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23615042aa92SStefano Zampini   }
23625042aa92SStefano Zampini 
23635042aa92SStefano Zampini   /* with ASCII, we dump the l2gmaps at the end */
23645042aa92SStefano Zampini   if (viewl2g) {
23655042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
23665042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
23675042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23685042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
23695042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23705042aa92SStefano Zampini     } else {
23715042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23725042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23735042aa92SStefano Zampini     }
23745042aa92SStefano Zampini   }
23755042aa92SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
23765042aa92SStefano Zampini }
23775042aa92SStefano Zampini 
2378a3ef7f04SStefano Zampini static PetscErrorCode ISLocalToGlobalMappingHasRepeatedLocal_Private(ISLocalToGlobalMapping map, PetscBool *has)
2379a3ef7f04SStefano Zampini {
2380a3ef7f04SStefano Zampini   const PetscInt *idxs;
2381a3ef7f04SStefano Zampini   PetscHSetI      ht;
2382a3ef7f04SStefano Zampini   PetscInt        n, bs;
2383a3ef7f04SStefano Zampini 
2384a3ef7f04SStefano Zampini   PetscFunctionBegin;
2385a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
2386a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
2387a3ef7f04SStefano Zampini   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
2388a3ef7f04SStefano Zampini   PetscCall(PetscHSetICreate(&ht));
2389a3ef7f04SStefano Zampini   *has = PETSC_FALSE;
2390a3ef7f04SStefano Zampini   for (PetscInt i = 0; i < n / bs; i++) {
2391a3ef7f04SStefano Zampini     PetscBool missing = PETSC_TRUE;
2392a3ef7f04SStefano Zampini     if (idxs[i] < 0) continue;
2393a3ef7f04SStefano Zampini     PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2394a3ef7f04SStefano Zampini     if (!missing) {
2395a3ef7f04SStefano Zampini       *has = PETSC_TRUE;
2396a3ef7f04SStefano Zampini       break;
2397a3ef7f04SStefano Zampini     }
2398a3ef7f04SStefano Zampini   }
2399a3ef7f04SStefano Zampini   PetscCall(PetscHSetIDestroy(&ht));
2400a3ef7f04SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2401a3ef7f04SStefano Zampini }
2402a3ef7f04SStefano Zampini 
24035042aa92SStefano Zampini static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
24045042aa92SStefano Zampini {
24055042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
24065042aa92SStefano Zampini   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
24075042aa92SStefano Zampini   PetscBool              isbinary, samel, allow, isbaij;
24085042aa92SStefano Zampini   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
24095042aa92SStefano Zampini   const PetscInt        *idx;
24105042aa92SStefano Zampini   PetscMPIInt            size;
24115042aa92SStefano Zampini   char                   lmattype[64];
24125042aa92SStefano Zampini   Mat                    dA, lA;
24135042aa92SStefano Zampini   IS                     is;
24145042aa92SStefano Zampini 
24155042aa92SStefano Zampini   PetscFunctionBegin;
24165042aa92SStefano Zampini   PetscCheckSameComm(A, 1, viewer, 2);
24175042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
24185042aa92SStefano Zampini   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
24195042aa92SStefano Zampini 
24205042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
24215042aa92SStefano Zampini   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
24225042aa92SStefano Zampini   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24235042aa92SStefano Zampini   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24245042aa92SStefano Zampini   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24255042aa92SStefano Zampini   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24265042aa92SStefano Zampini   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
24275042aa92SStefano Zampini   M     = tr[1];
24285042aa92SStefano Zampini   N     = tr[2];
24295042aa92SStefano Zampini   Asize = -tr[3];
24305042aa92SStefano Zampini   samel = (PetscBool)tr[4];
24315042aa92SStefano Zampini   allow = (PetscBool)tr[5];
24325042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
24335042aa92SStefano Zampini 
24345042aa92SStefano Zampini   /* if we are loading from a larger set of processes, allow repeated entries */
24355042aa92SStefano Zampini   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
24365042aa92SStefano Zampini   if (Asize > size) allow = PETSC_TRUE;
24375042aa92SStefano Zampini 
24385042aa92SStefano Zampini   /* set global sizes if not set already */
24395042aa92SStefano Zampini   if (A->rmap->N < 0) A->rmap->N = M;
24405042aa92SStefano Zampini   if (A->cmap->N < 0) A->cmap->N = N;
24415042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->rmap));
24425042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->cmap));
24435042aa92SStefano Zampini   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
24445042aa92SStefano Zampini   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
24455042aa92SStefano Zampini 
24465042aa92SStefano Zampini   /* load l2g maps */
24475042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
24485042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
24495042aa92SStefano Zampini   if (!samel) {
24505042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
24515042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
24525042aa92SStefano Zampini   } else {
24535042aa92SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)rmap));
24545042aa92SStefano Zampini     cmap = rmap;
24555042aa92SStefano Zampini   }
24565042aa92SStefano Zampini 
24575042aa92SStefano Zampini   /* load sizes of local matrices */
24585042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
24595042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
24605042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
24615042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
24625042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
24635042aa92SStefano Zampini   nr = 0;
24645042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
24655042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
24665042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
24675042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
24685042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
24695042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
24705042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
24715042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
24725042aa92SStefano Zampini   nc = 0;
24735042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
24745042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
24755042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
24765042aa92SStefano Zampini 
24775042aa92SStefano Zampini   /* now load the unassembled operator */
24785042aa92SStefano Zampini   PetscCall(MatCreate(comm, &dA));
24795042aa92SStefano Zampini   PetscCall(MatSetType(dA, MATMPIAIJ));
24805042aa92SStefano Zampini   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
24815042aa92SStefano Zampini   PetscCall(MatLoad(dA, viewer));
24825042aa92SStefano Zampini   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
24835042aa92SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)lA));
24845042aa92SStefano Zampini   PetscCall(MatDestroy(&dA));
24855042aa92SStefano Zampini 
24865042aa92SStefano Zampini   /* and convert to the desired format */
24875042aa92SStefano Zampini   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
24885042aa92SStefano Zampini   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
24895042aa92SStefano Zampini   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
24905042aa92SStefano Zampini 
2491a3ef7f04SStefano Zampini   /* check if we actually have repeated entries */
2492a3ef7f04SStefano Zampini   if (allow) {
2493a3ef7f04SStefano Zampini     PetscBool rhas, chas, hasrepeated;
2494a3ef7f04SStefano Zampini 
2495a3ef7f04SStefano Zampini     PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(rmap, &rhas));
2496a3ef7f04SStefano Zampini     if (rmap != cmap) PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(cmap, &chas));
2497a3ef7f04SStefano Zampini     else chas = rhas;
2498a3ef7f04SStefano Zampini     hasrepeated = (PetscBool)(rhas || chas);
2499a3ef7f04SStefano Zampini     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &hasrepeated, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2500a3ef7f04SStefano Zampini     if (!hasrepeated) allow = PETSC_FALSE;
2501a3ef7f04SStefano Zampini   }
2502a3ef7f04SStefano Zampini 
25035042aa92SStefano Zampini   /* assemble the MATIS object */
25045042aa92SStefano Zampini   PetscCall(MatISSetAllowRepeated(A, allow));
25055042aa92SStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
25065042aa92SStefano Zampini   PetscCall(MatISSetLocalMat(A, lA));
25075042aa92SStefano Zampini   PetscCall(MatDestroy(&lA));
25085042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
25095042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
25105042aa92SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
25115042aa92SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
25123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2513b4319ba4SBarry Smith }
2514b4319ba4SBarry Smith 
2515d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2516d71ae5a4SJacob Faibussowitsch {
2517b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2518b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2519b89f26deSStefano Zampini   const PetscScalar *lv;
2520b89f26deSStefano Zampini   PetscInt           bs;
2521835f2295SStefano Zampini   PetscMPIInt        mbs;
2522b89f26deSStefano Zampini 
2523b89f26deSStefano Zampini   PetscFunctionBegin;
25249566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
25259566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
25269566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
252748a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2528835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(bs, &mbs));
2529835f2295SStefano Zampini   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
25309566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
25319566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
25329566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
25339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2534b89f26deSStefano Zampini   if (values) *values = is->bdiag;
25353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2536b89f26deSStefano Zampini }
2537b89f26deSStefano Zampini 
2538d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2539d71ae5a4SJacob Faibussowitsch {
2540e176bc59SStefano Zampini   Vec             cglobal, rglobal;
25418546b261SStefano Zampini   IS              from;
25428546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2543b89f26deSStefano Zampini   PetscScalar     sum;
25448546b261SStefano Zampini   const PetscInt *garray;
25458546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2546e432b41dSStefano Zampini   VecType         rtype;
2547b4319ba4SBarry Smith 
2548b4319ba4SBarry Smith   PetscFunctionBegin;
25499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
25509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
25519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
25529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
25539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
25549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
25559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
25569566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
25579566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
25589566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
25599566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
25609566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
25619566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
25629566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
25639566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
25649566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
25659566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
25669566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
25679566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
25689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
25699566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2570e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
25719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
25729566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
25739566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
25749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
25759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
25768546b261SStefano Zampini   } else {
25779566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
25788546b261SStefano Zampini     is->cctx = is->rctx;
25798546b261SStefano Zampini   }
25809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2581b89f26deSStefano Zampini 
25828546b261SStefano Zampini   /* interface counter vector (local) */
25839566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
25849566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
25859566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
25869566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
25879566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
25889566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
25899566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
25909566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
25919566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2592b89f26deSStefano Zampini 
2593b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
25949566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2595b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2596e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
25979566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2598b0cc1f67SStefano Zampini 
2599b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
26009566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
26013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26028546b261SStefano Zampini }
26038546b261SStefano Zampini 
2604d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2605d71ae5a4SJacob Faibussowitsch {
26064f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2607e432b41dSStefano Zampini   IS                         is;
2608e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2609e432b41dSStefano Zampini   const PetscInt            *idxs;
2610e432b41dSStefano Zampini   PetscHSetI                 ht;
2611e432b41dSStefano Zampini   PetscInt                  *nidxs;
2612e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2613e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2614e432b41dSStefano Zampini 
2615e432b41dSStefano Zampini   PetscFunctionBegin;
26169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
26179566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
26189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
26199566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
26209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2621e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
26224f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
26239371c9d4SSatish Balay     if (idxs[i] < 0) {
26249371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
26259371c9d4SSatish Balay       continue;
26269371c9d4SSatish Balay     }
26274f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2628e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2629e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2630e432b41dSStefano Zampini   }
26319566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
2632462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2633e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2634e432b41dSStefano Zampini     *nmap = NULL;
2635e432b41dSStefano Zampini     *lmap = NULL;
26369566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
26379566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
26383ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2639e432b41dSStefano Zampini   }
2640e432b41dSStefano Zampini 
26414f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
26429566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
26439566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
26449566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
26459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
26469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2647e432b41dSStefano Zampini 
26484f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
26499566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
26509566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
26519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
26529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
26539566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
26549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
26553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2656e432b41dSStefano Zampini }
2657e432b41dSStefano Zampini 
2658d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2659d71ae5a4SJacob Faibussowitsch {
26608546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2661e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2662e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
26634f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
26648546b261SStefano Zampini 
26658546b261SStefano Zampini   PetscFunctionBegin;
2666fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2667fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2668e432b41dSStefano Zampini 
26699566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
26709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
26719566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
26729566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
26739566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2674e432b41dSStefano Zampini 
2675fc989267SStefano Zampini   /* If NULL, local space matches global space */
2676fc989267SStefano Zampini   if (!rmapping) {
2677fc989267SStefano Zampini     IS is;
2678fc989267SStefano Zampini 
26799566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
26809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
268158b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
26829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2683e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2684e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2685e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
26869566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2687e432b41dSStefano Zampini     if (rmapping == cmapping) {
26889566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2689e432b41dSStefano Zampini       is->cmapping = is->rmapping;
26909566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2691e432b41dSStefano Zampini       localcmapping = localrmapping;
2692fc989267SStefano Zampini     }
2693fc989267SStefano Zampini   }
2694fc989267SStefano Zampini   if (!cmapping) {
2695fc989267SStefano Zampini     IS is;
2696fc989267SStefano Zampini 
26979566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
26989566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
269958b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
27009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2701e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2702e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
27039566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2704e432b41dSStefano Zampini   }
2705e432b41dSStefano Zampini   if (!is->rmapping) {
27069566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2707e432b41dSStefano Zampini     is->rmapping = rmapping;
2708e432b41dSStefano Zampini   }
2709e432b41dSStefano Zampini   if (!is->cmapping) {
27109566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2711e432b41dSStefano Zampini     is->cmapping = cmapping;
2712fc989267SStefano Zampini   }
2713fc989267SStefano Zampini 
2714fc989267SStefano Zampini   /* Clean up */
27154f58015eSStefano Zampini   is->lnnzstate = 0;
27164f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
27174f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
27189566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2719872cf891SStefano Zampini   if (is->csf != is->sf) {
27209566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
27219566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2722f03112d0SStefano Zampini   } else is->csf = NULL;
27239566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
27249566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
27259566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
27263bbff08aSStefano Zampini 
2727fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2728fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
27299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
27309566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
27319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
27329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2733e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2734e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
27356625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
27366625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
27376625354bSStefano Zampini 
27389566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
27399566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
27409566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
27419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
27429566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
27436625354bSStefano Zampini     }
2744462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2745e432b41dSStefano Zampini     if (same) {
27469566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
27479566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2748e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2749e432b41dSStefano Zampini     }
27506625354bSStefano Zampini   }
27519566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
27529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2753e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
27549566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
27559566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
27569566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
27579566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
27586625354bSStefano Zampini 
275939b6f3f9SStefano Zampini   if (!is->islocalref) {
27606625354bSStefano Zampini     /* Create the local matrix A */
27619566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
27629566063dSJacob Faibussowitsch     PetscCall(MatSetType(is->A, is->lmattype));
27639566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
27649566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
27659566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(is->A, "is_"));
27669566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
27679566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->rmap));
27689566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->cmap));
27699566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
27709566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
27719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2772fc989267SStefano Zampini     /* setup scatters and local vectors for MatMult */
277339b6f3f9SStefano Zampini     PetscCall(MatISSetUpScatters_Private(A));
277439b6f3f9SStefano Zampini   }
2775fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
27763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2777fc989267SStefano Zampini }
2778fc989267SStefano Zampini 
2779d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2780d71ae5a4SJacob Faibussowitsch {
278129f134acSStefano Zampini   Mat_IS                *is = (Mat_IS *)A->data;
2782fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2783fc989267SStefano Zampini 
2784fc989267SStefano Zampini   PetscFunctionBegin;
278529f134acSStefano Zampini   if (!is->sf) {
27869566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
278729f134acSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
278829f134acSStefano Zampini   }
27893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2790b4319ba4SBarry Smith }
2791b4319ba4SBarry Smith 
2792d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2793d71ae5a4SJacob Faibussowitsch {
27942e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2795f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
27962e74eeadSLisandro Dalcin 
27972e74eeadSLisandro Dalcin   PetscFunctionBegin;
27989566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2799e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
28009566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28019566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2802e432b41dSStefano Zampini   } else {
28039566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2804e432b41dSStefano Zampini   }
28053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28062e74eeadSLisandro Dalcin }
28072e74eeadSLisandro Dalcin 
2808d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2809d71ae5a4SJacob Faibussowitsch {
281097563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2811f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
281297563a80SStefano Zampini 
281397563a80SStefano Zampini   PetscFunctionBegin;
28149566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2815e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
281684a95373SStefano Zampini     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
28179566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2818e432b41dSStefano Zampini   } else {
281984a95373SStefano Zampini     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2820e432b41dSStefano Zampini   }
28213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
282297563a80SStefano Zampini }
282397563a80SStefano Zampini 
2824d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2825d71ae5a4SJacob Faibussowitsch {
2826b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2827b4319ba4SBarry Smith 
2828b4319ba4SBarry Smith   PetscFunctionBegin;
2829e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
28309566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2831872cf891SStefano Zampini   } else {
28329566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2833872cf891SStefano Zampini   }
28343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2835b4319ba4SBarry Smith }
2836b4319ba4SBarry Smith 
2837d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2838d71ae5a4SJacob Faibussowitsch {
2839f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2840f0006bf2SLisandro Dalcin 
2841f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2842e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
28439566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2844b4f971dfSStefano Zampini   } else {
28459566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2846b4f971dfSStefano Zampini   }
28473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2848f0006bf2SLisandro Dalcin }
2849f0006bf2SLisandro Dalcin 
2850d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2851d71ae5a4SJacob Faibussowitsch {
2852f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2853f0ae7da4SStefano Zampini 
2854f0ae7da4SStefano Zampini   PetscFunctionBegin;
2855*0d2733adSStefano Zampini   if (!n) PetscFunctionReturn(PETSC_SUCCESS);
2856f0ae7da4SStefano Zampini   is->pure_neumann = PETSC_FALSE;
2857f0ae7da4SStefano Zampini 
2858f0ae7da4SStefano Zampini   if (columns) {
28599566063dSJacob Faibussowitsch     PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2860f0ae7da4SStefano Zampini   } else {
28619566063dSJacob Faibussowitsch     PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2862f0ae7da4SStefano Zampini   }
2863f0ae7da4SStefano Zampini   if (diag != 0.) {
2864f0ae7da4SStefano Zampini     const PetscScalar *array;
2865*0d2733adSStefano Zampini 
28669566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(is->counter, &array));
2867*0d2733adSStefano Zampini     for (PetscInt i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
28689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(is->counter, &array));
28699566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
28709566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2871f0ae7da4SStefano Zampini   }
28723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2873f0ae7da4SStefano Zampini }
2874f0ae7da4SStefano Zampini 
2875d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2876d71ae5a4SJacob Faibussowitsch {
28776e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
2878*0d2733adSStefano Zampini   PetscInt  nr, nl, len;
2879*0d2733adSStefano Zampini   PetscInt *lrows = NULL;
28802e74eeadSLisandro Dalcin 
28812e74eeadSLisandro Dalcin   PetscFunctionBegin;
2882cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2883f0ae7da4SStefano Zampini     PetscBool cong;
288426b0207aSStefano Zampini 
28859566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
288626b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
288708401ef6SPierre 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");
2888aed4548fSBarry 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");
2889aed4548fSBarry 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");
2890f0ae7da4SStefano Zampini   }
2891*0d2733adSStefano Zampini   PetscCall(MatGetSize(matis->A, &nl, NULL));
28926e520ac8SStefano Zampini   /* get locally owned rows */
28939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2894dd8e379bSPierre Jolivet   /* fix right-hand side if needed */
28956e520ac8SStefano Zampini   if (x && b) {
28966e520ac8SStefano Zampini     const PetscScalar *xx;
28976e520ac8SStefano Zampini     PetscScalar       *bb;
28986e520ac8SStefano Zampini 
28999566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
29009566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
2901*0d2733adSStefano Zampini     for (PetscInt i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
29029566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
29039566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
29042e74eeadSLisandro Dalcin   }
29056e520ac8SStefano Zampini   /* get rows associated to the local matrices */
29069566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
29079566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
2908*0d2733adSStefano Zampini   for (PetscInt i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
29099566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29109566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29119566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
29129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
2913*0d2733adSStefano Zampini   nr = 0;
2914*0d2733adSStefano Zampini   for (PetscInt i = 0; i < nl; i++)
29159371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
29169566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
29179566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
29183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29192e74eeadSLisandro Dalcin }
29202e74eeadSLisandro Dalcin 
2921d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2922d71ae5a4SJacob Faibussowitsch {
2923b4319ba4SBarry Smith   PetscFunctionBegin;
29249566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
29253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2926f0ae7da4SStefano Zampini }
29272205254eSKarl Rupp 
2928d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2929d71ae5a4SJacob Faibussowitsch {
2930f0ae7da4SStefano Zampini   PetscFunctionBegin;
29319566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
29323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2933b4319ba4SBarry Smith }
2934b4319ba4SBarry Smith 
2935d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2936d71ae5a4SJacob Faibussowitsch {
2937b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2938b4319ba4SBarry Smith 
2939b4319ba4SBarry Smith   PetscFunctionBegin;
29409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
29413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2942b4319ba4SBarry Smith }
2943b4319ba4SBarry Smith 
2944d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2945d71ae5a4SJacob Faibussowitsch {
2946b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2947d0dbe9f7SStefano Zampini   PetscBool lnnz;
2948b4319ba4SBarry Smith 
2949b4319ba4SBarry Smith   PetscFunctionBegin;
29509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2951872cf891SStefano Zampini   /* fix for local empty rows/cols */
2952872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2953872cf891SStefano Zampini     Mat                    newlA;
2954f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2955f03112d0SStefano Zampini     IS                     nzr, nzc;
2956f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2957f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2958872cf891SStefano Zampini 
29599566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
29609566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
296148a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
29629566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
296348a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
29649566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
29659566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2966e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2967f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
2968462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2969f03112d0SStefano Zampini 
2970872cf891SStefano Zampini       /* extract valid submatrix */
29719566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2972f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2973f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
2974462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
29759566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2976f03112d0SStefano Zampini       newlA = is->A;
2977f03112d0SStefano Zampini     }
2978e432b41dSStefano Zampini 
2979f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2980f03112d0SStefano Zampini     if (newl2g) {
2981e432b41dSStefano Zampini       IS              zr, zc;
2982e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2983e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2984f03112d0SStefano Zampini 
29859566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
29869566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
29879566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
29889566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
29899566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
29909566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
29919566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
29929566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
29939566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2994e432b41dSStefano Zampini 
29959566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2996e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
29979566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
29989566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2999e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
30009566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
3001e432b41dSStefano Zampini 
30029566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
30039566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
30049566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
30059566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
30069566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
30079566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
30089566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
30099566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
30109566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
30119566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
30129566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
30139566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3014f03112d0SStefano Zampini     }
30159566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
30169566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
30179566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
30189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
3019872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
3020f03112d0SStefano Zampini   }
3021d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
3022d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
3023462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
30244f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
30253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3026b4319ba4SBarry Smith }
3027b4319ba4SBarry Smith 
3028d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
3029d71ae5a4SJacob Faibussowitsch {
3030b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
3031b4319ba4SBarry Smith 
3032b4319ba4SBarry Smith   PetscFunctionBegin;
3033b4319ba4SBarry Smith   *local = is->A;
30343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3035b4319ba4SBarry Smith }
3036b4319ba4SBarry Smith 
3037d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
3038d71ae5a4SJacob Faibussowitsch {
30393b3b1effSJed Brown   PetscFunctionBegin;
30403b3b1effSJed Brown   *local = NULL;
30413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30423b3b1effSJed Brown }
30433b3b1effSJed Brown 
3044b4319ba4SBarry Smith /*@
304511a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
3046b4319ba4SBarry Smith 
30474f58015eSStefano Zampini   Not Collective.
30484f58015eSStefano Zampini 
3049b4319ba4SBarry Smith   Input Parameter:
3050b4319ba4SBarry Smith . mat - the matrix
3051b4319ba4SBarry Smith 
3052b4319ba4SBarry Smith   Output Parameter:
3053eb82efa4SStefano Zampini . local - the local matrix
3054b4319ba4SBarry Smith 
30554f58015eSStefano Zampini   Level: intermediate
3056b4319ba4SBarry Smith 
3057b4319ba4SBarry Smith   Notes:
3058b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
3059b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
306011a5261eSBarry Smith   of the `MatSetValues()` operation.
3061b4319ba4SBarry Smith 
306211a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
306396a6f129SJed Brown 
30641cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
3065b4319ba4SBarry Smith @*/
3066d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
3067d71ae5a4SJacob Faibussowitsch {
3068b4319ba4SBarry Smith   PetscFunctionBegin;
30690700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
30704f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3071cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
30723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3073b4319ba4SBarry Smith }
3074b4319ba4SBarry Smith 
30753b3b1effSJed Brown /*@
307611a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
30773b3b1effSJed Brown 
30784f58015eSStefano Zampini   Not Collective.
30794f58015eSStefano Zampini 
30802ef1f0ffSBarry Smith   Input Parameters:
30812ef1f0ffSBarry Smith + mat   - the matrix
30822ef1f0ffSBarry Smith - local - the local matrix
30833b3b1effSJed Brown 
30844f58015eSStefano Zampini   Level: intermediate
30853b3b1effSJed Brown 
30861cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
30873b3b1effSJed Brown @*/
3088d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
3089d71ae5a4SJacob Faibussowitsch {
30903b3b1effSJed Brown   PetscFunctionBegin;
30913b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
30924f572ea9SToby Isaac   PetscAssertPointer(local, 2);
3093cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
30943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30953b3b1effSJed Brown }
30963b3b1effSJed Brown 
3097d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3098d71ae5a4SJacob Faibussowitsch {
30998546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
31008546b261SStefano Zampini 
31018546b261SStefano Zampini   PetscFunctionBegin;
31021baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
31039566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
31049566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
31053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31068546b261SStefano Zampini }
31078546b261SStefano Zampini 
31085d83a8b1SBarry Smith /*@
310911a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
31108546b261SStefano Zampini 
31114f58015eSStefano Zampini   Logically Collective.
31124f58015eSStefano Zampini 
3113d8d19677SJose E. Roman   Input Parameters:
3114a2b725a8SWilliam Gropp + mat   - the matrix
3115a2b725a8SWilliam Gropp - mtype - the local matrix type
31168546b261SStefano Zampini 
31174f58015eSStefano Zampini   Level: intermediate
31188546b261SStefano Zampini 
31191cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
31208546b261SStefano Zampini @*/
3121d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3122d71ae5a4SJacob Faibussowitsch {
31238546b261SStefano Zampini   PetscFunctionBegin;
31248546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3125cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
31263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31278546b261SStefano Zampini }
31288546b261SStefano Zampini 
3129d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3130d71ae5a4SJacob Faibussowitsch {
31313b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
31323b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
31338546b261SStefano Zampini   MatType   mtype, otype;
31348546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
31353b03a366Sstefano_zampini 
31363b03a366Sstefano_zampini   PetscFunctionBegin;
3137e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
31389566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
31399566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
31405042aa92SStefano 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);
31419566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
31429566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
31439566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
31444e4c7dbeSStefano Zampini   }
31459566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
31469566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
31473b03a366Sstefano_zampini   is->A = local;
31489566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
31499566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
315048a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
31514f58015eSStefano Zampini   is->lnnzstate = 0;
31523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31533b03a366Sstefano_zampini }
31543b03a366Sstefano_zampini 
31553b03a366Sstefano_zampini /*@
315611a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
31573b03a366Sstefano_zampini 
31584f58015eSStefano Zampini   Not Collective
31598546b261SStefano Zampini 
3160d8d19677SJose E. Roman   Input Parameters:
3161a2b725a8SWilliam Gropp + mat   - the matrix
3162a2b725a8SWilliam Gropp - local - the local matrix
31633b03a366Sstefano_zampini 
31644f58015eSStefano Zampini   Level: intermediate
316511a5261eSBarry Smith 
31661cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
31673b03a366Sstefano_zampini @*/
3168d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3169d71ae5a4SJacob Faibussowitsch {
31703b03a366Sstefano_zampini   PetscFunctionBegin;
31713b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3172b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3173cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
31743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31753b03a366Sstefano_zampini }
31763b03a366Sstefano_zampini 
3177d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3178d71ae5a4SJacob Faibussowitsch {
31796726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
31806726f965SBarry Smith 
31816726f965SBarry Smith   PetscFunctionBegin;
31829566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
31833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31846726f965SBarry Smith }
31856726f965SBarry Smith 
3186d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3187d71ae5a4SJacob Faibussowitsch {
31882e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
31892e74eeadSLisandro Dalcin 
31902e74eeadSLisandro Dalcin   PetscFunctionBegin;
31919566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
31923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31932e74eeadSLisandro Dalcin }
31942e74eeadSLisandro Dalcin 
3195d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3196d71ae5a4SJacob Faibussowitsch {
31972e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
31982e74eeadSLisandro Dalcin 
31992e74eeadSLisandro Dalcin   PetscFunctionBegin;
32002e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
32019566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
32022e74eeadSLisandro Dalcin 
32032e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
32049566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
32059566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32069566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
32073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32082e74eeadSLisandro Dalcin }
32092e74eeadSLisandro Dalcin 
3210d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3211d71ae5a4SJacob Faibussowitsch {
32126726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
32136726f965SBarry Smith 
32146726f965SBarry Smith   PetscFunctionBegin;
32159566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
32163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32176726f965SBarry Smith }
32186726f965SBarry Smith 
3219d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3220d71ae5a4SJacob Faibussowitsch {
3221f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3222f26d0771SStefano Zampini   Mat_IS *x;
3223f26d0771SStefano Zampini 
3224f26d0771SStefano Zampini   PetscFunctionBegin;
322576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
322676bd3646SJed Brown     PetscBool ismatis;
32279566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
322828b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
322976bd3646SJed Brown   }
3230f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
32319566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
32323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3233f26d0771SStefano Zampini }
3234f26d0771SStefano Zampini 
3235d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3236d71ae5a4SJacob Faibussowitsch {
3237f26d0771SStefano Zampini   Mat                    lA;
3238f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3239f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3240f26d0771SStefano Zampini   IS                     is;
3241f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3242f26d0771SStefano Zampini   PetscInt               nrg;
3243f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3244f26d0771SStefano Zampini 
3245f26d0771SStefano Zampini   PetscFunctionBegin;
32469566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
32479566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
32489566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
32499566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
325076bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3251e87b5d96SPierre 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 than maximum possible %" PetscInt_FMT, i, rl[i], nrg);
325276bd3646SJed Brown   }
32539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3254f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3255f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3256f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
32579566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
32589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
32599566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
32609566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
32619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3262f26d0771SStefano Zampini   /* compute new l2g map for columns */
3263e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3264f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3265f26d0771SStefano Zampini     PetscInt        ncg;
3266f26d0771SStefano Zampini     PetscInt        ncl;
3267f26d0771SStefano Zampini 
32689566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
32699566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
32709566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
32719566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
327276bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
3273e87b5d96SPierre 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 than maximum possible %" PetscInt_FMT, i, cl[i], ncg);
327476bd3646SJed Brown     }
32759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3276f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3277f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3278f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
32799566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
32809566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
32819566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
32829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
32839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3284f26d0771SStefano Zampini   } else {
32859566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3286f26d0771SStefano Zampini     cl2g = rl2g;
3287f26d0771SStefano Zampini   }
3288*0d2733adSStefano Zampini 
3289f26d0771SStefano Zampini   /* create the MATIS submatrix */
32909566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
32919566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
32929566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
32939566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3294b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3295*0d2733adSStefano Zampini   matis->islocalref = A;
32969566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
32979566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
32989566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
32999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
33009566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3301e432b41dSStefano Zampini 
3302f26d0771SStefano Zampini   /* remove unsupported ops */
33039566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3304f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3305f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3306f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3307*0d2733adSStefano Zampini   (*submat)->ops->zerorowslocal         = MatZeroRowsLocal_SubMat_IS;
3308*0d2733adSStefano Zampini   (*submat)->ops->zerorowscolumnslocal  = MatZeroRowsColumnsLocal_SubMat_IS;
330939b6f3f9SStefano Zampini   (*submat)->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_IS;
33103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3311f26d0771SStefano Zampini }
3312f26d0771SStefano Zampini 
3313ce78bad3SBarry Smith static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject)
3314d71ae5a4SJacob Faibussowitsch {
3315872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
33168546b261SStefano Zampini   char      type[256];
33178546b261SStefano Zampini   PetscBool flg;
3318872cf891SStefano Zampini 
3319872cf891SStefano Zampini   PetscFunctionBegin;
3320d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
33214f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
33224f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
33234f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
33244f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
33254f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
33264f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
33274f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
33284f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
33294f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
33301baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
33311baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3332d0609cedSBarry Smith   PetscOptionsHeadEnd();
33333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3334872cf891SStefano Zampini }
3335872cf891SStefano Zampini 
3336284134d9SBarry Smith /*@
33374f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
33384f58015eSStefano Zampini 
33394f58015eSStefano Zampini   Collective.
3340284134d9SBarry Smith 
3341284134d9SBarry Smith   Input Parameters:
3342284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3343e176bc59SStefano Zampini . bs   - block size of the matrix
33442920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
33452920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
33462920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
33472920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3348e176bc59SStefano Zampini . rmap - local to global map for rows
3349e176bc59SStefano Zampini - cmap - local to global map for cols
3350284134d9SBarry Smith 
3351284134d9SBarry Smith   Output Parameter:
3352284134d9SBarry Smith . A - the resulting matrix
3353284134d9SBarry Smith 
33544f58015eSStefano Zampini   Level: intermediate
33558e6c10adSSatish Balay 
335695452b02SPatrick Sanan   Notes:
33572ef1f0ffSBarry 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
33584f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
335911a5261eSBarry Smith 
33602ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3361284134d9SBarry Smith 
33621cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3363284134d9SBarry Smith @*/
3364d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3365d71ae5a4SJacob Faibussowitsch {
3366284134d9SBarry Smith   PetscFunctionBegin;
33679566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
33689566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
336948a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
33709566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
33719566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
33723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3373284134d9SBarry Smith }
3374284134d9SBarry Smith 
3375d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3376d71ae5a4SJacob Faibussowitsch {
33778b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3378e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
33798b9382cfSStefano Zampini 
33808b9382cfSStefano Zampini   PetscFunctionBegin;
33818b9382cfSStefano Zampini   *has = PETSC_FALSE;
33823ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3383d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
33849371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
33853ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
33869566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
33873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33888b9382cfSStefano Zampini }
33898b9382cfSStefano Zampini 
3390d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3391d71ae5a4SJacob Faibussowitsch {
3392e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3393e432b41dSStefano Zampini 
3394e432b41dSStefano Zampini   PetscFunctionBegin;
33959566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
33969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
33979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
33983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3399e432b41dSStefano Zampini }
3400e432b41dSStefano Zampini 
3401d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3402d71ae5a4SJacob Faibussowitsch {
3403e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3404e432b41dSStefano Zampini 
3405e432b41dSStefano Zampini   PetscFunctionBegin;
3406e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3407e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
34089566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3409e432b41dSStefano Zampini   } else {
34109566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3411e432b41dSStefano Zampini   }
34129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3413e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3415e432b41dSStefano Zampini }
3416e432b41dSStefano Zampini 
3417d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3418d71ae5a4SJacob Faibussowitsch {
3419e432b41dSStefano Zampini   Mat_IS  *a = (Mat_IS *)A->data;
3420835f2295SStefano Zampini   PetscInt ncoo_i;
3421e432b41dSStefano Zampini 
3422e432b41dSStefano Zampini   PetscFunctionBegin;
3423e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3424835f2295SStefano Zampini   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3425835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3426835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3427e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
34289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3429e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
34303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3431e432b41dSStefano Zampini }
3432e432b41dSStefano Zampini 
3433d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3434d71ae5a4SJacob Faibussowitsch {
3435d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
34361690c2aeSBarry Smith   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
34371690c2aeSBarry Smith   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3438d0dbe9f7SStefano Zampini 
3439d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3440d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3441d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3442d0dbe9f7SStefano Zampini   if (a->assembledA) {
3443d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3444d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3445d0dbe9f7SStefano Zampini   }
3446d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3447d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3448d0dbe9f7SStefano Zampini     MatType     aAtype;
3449d0dbe9f7SStefano Zampini     PetscMPIInt size;
3450d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3451d0dbe9f7SStefano Zampini 
3452d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3453d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3454d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3455d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3456d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3457d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3458d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3459d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3460d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3461d0dbe9f7SStefano Zampini 
3462d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3463d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3464d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3465d0dbe9f7SStefano Zampini   }
3466d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3467d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3468d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
34693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3470d0dbe9f7SStefano Zampini }
3471d0dbe9f7SStefano Zampini 
3472d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3473d71ae5a4SJacob Faibussowitsch {
3474d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3475d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3476d0dbe9f7SStefano Zampini   *tA = NULL;
34773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3478d0dbe9f7SStefano Zampini }
3479d0dbe9f7SStefano Zampini 
3480d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3481d71ae5a4SJacob Faibussowitsch {
3482d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
34831690c2aeSBarry Smith   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3484d0dbe9f7SStefano Zampini 
3485d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3486d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3487d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3488d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3489d0dbe9f7SStefano Zampini     Mat     tA;
3490d0dbe9f7SStefano Zampini     MatType ltype;
3491d0dbe9f7SStefano Zampini 
3492d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3493d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3494d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3495d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3496d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3497d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3498d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3499d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3500d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3501d0dbe9f7SStefano Zampini   }
3502d0dbe9f7SStefano Zampini   *dA = a->dA;
35033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3504d0dbe9f7SStefano Zampini }
3505d0dbe9f7SStefano Zampini 
3506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3507d71ae5a4SJacob Faibussowitsch {
3508d0dbe9f7SStefano Zampini   Mat tA;
3509d0dbe9f7SStefano Zampini 
3510d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3511d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3512d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3513d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3514d0dbe9f7SStefano Zampini #if 0
3515d0dbe9f7SStefano Zampini   {
3516d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3517d0dbe9f7SStefano Zampini     MatType   ltype;
3518d0dbe9f7SStefano Zampini     VecType   vtype;
3519d0dbe9f7SStefano Zampini     char      *flg;
3520d0dbe9f7SStefano Zampini 
3521d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3522d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3523d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3524d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3525d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3526d0dbe9f7SStefano Zampini     if (flg) {
3527d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3528d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3529d0dbe9f7SStefano Zampini 
3530d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3531d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3532d0dbe9f7SStefano Zampini       }
3533d0dbe9f7SStefano Zampini     }
3534d0dbe9f7SStefano Zampini   }
3535d0dbe9f7SStefano Zampini #endif
3536d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
35373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3538d0dbe9f7SStefano Zampini }
3539d0dbe9f7SStefano Zampini 
3540d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3541d71ae5a4SJacob Faibussowitsch {
3542d0dbe9f7SStefano Zampini   Mat tA;
3543d0dbe9f7SStefano Zampini 
3544d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3545d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3546d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3547d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
35483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3549d0dbe9f7SStefano Zampini }
3550d0dbe9f7SStefano Zampini 
3551e432b41dSStefano Zampini /*@
355211a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3553e432b41dSStefano Zampini 
3554e432b41dSStefano Zampini   Not Collective
3555e432b41dSStefano Zampini 
3556e432b41dSStefano Zampini   Input Parameter:
3557e432b41dSStefano Zampini . A - the matrix
3558e432b41dSStefano Zampini 
3559e432b41dSStefano Zampini   Output Parameters:
3560e432b41dSStefano Zampini + rmapping - row mapping
3561e432b41dSStefano Zampini - cmapping - column mapping
3562e432b41dSStefano Zampini 
35632ef1f0ffSBarry Smith   Level: advanced
35642ef1f0ffSBarry Smith 
356511a5261eSBarry Smith   Note:
356611a5261eSBarry 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.
3567e432b41dSStefano Zampini 
3568bfe80ac4SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3569e432b41dSStefano Zampini @*/
3570d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3571d71ae5a4SJacob Faibussowitsch {
3572e432b41dSStefano Zampini   PetscFunctionBegin;
3573e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3574e432b41dSStefano Zampini   PetscValidType(A, 1);
35754f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
35764f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3577cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
35783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3579e432b41dSStefano Zampini }
3580e432b41dSStefano Zampini 
3581d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3582d71ae5a4SJacob Faibussowitsch {
3583e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3584e432b41dSStefano Zampini 
3585e432b41dSStefano Zampini   PetscFunctionBegin;
3586e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3587e432b41dSStefano Zampini   if (c) *c = a->cmapping;
35883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3589e432b41dSStefano Zampini }
3590e432b41dSStefano Zampini 
3591a50ef18cSStefano Zampini static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3592a50ef18cSStefano Zampini {
3593a50ef18cSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3594a50ef18cSStefano Zampini 
3595a50ef18cSStefano Zampini   PetscFunctionBegin;
3596a50ef18cSStefano Zampini   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3597a50ef18cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
3598a50ef18cSStefano Zampini }
3599a50ef18cSStefano Zampini 
3600b4319ba4SBarry Smith /*MC
36014f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
36024f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3603b4319ba4SBarry Smith 
3604b4319ba4SBarry Smith   Options Database Keys:
36054f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
36064f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
36074f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
36084f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
36092ef1f0ffSBarry Smith 
36104f58015eSStefano Zampini   Level: intermediate
3611b4319ba4SBarry Smith 
361295452b02SPatrick Sanan   Notes:
36132ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3614b4319ba4SBarry Smith 
361511a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3616b4319ba4SBarry Smith 
3617b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
36184f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3619b4319ba4SBarry Smith 
36201cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3621b4319ba4SBarry Smith M*/
3622d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3623d71ae5a4SJacob Faibussowitsch {
3624e432b41dSStefano Zampini   Mat_IS *a;
3625b4319ba4SBarry Smith 
3626b4319ba4SBarry Smith   PetscFunctionBegin;
36274dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
36289566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3629e432b41dSStefano Zampini   A->data = (void *)a;
3630b4319ba4SBarry Smith 
3631e176bc59SStefano Zampini   /* matrix ops */
36329566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3633b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
36342e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
36352e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
36362e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3637b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3638b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
36392e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
364098921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3641b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3642f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
36432e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3644f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3645b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3646b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3647b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
36485042aa92SStefano Zampini   A->ops->load                    = MatLoad_IS;
36496726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
36502e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
36512e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
36526726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
365369796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
365469796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
365545471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3656ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
36576bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
36582b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3659659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
36607dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3661f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
36623fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
36633fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3664d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
36657fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3666ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3667872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3668fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
36698b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3670d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3671d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3672d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3673a50ef18cSStefano Zampini   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3674b4319ba4SBarry Smith 
3675b7ce53b6SStefano Zampini   /* special MATIS functions */
36769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
36779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
36789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
36799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
36809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
36814f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
36829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
36839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
36849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
36859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
36869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
36879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
36889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
36899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
36909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
36919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
36929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
36939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
36949566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
36953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3696b4319ba4SBarry Smith }
3697