xref: /petsc/src/mat/impls/is/matis.c (revision ac7f1a8b79ea0e2b8b86ec6656890d6a06746de2)
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;
10308546b261SStefano Zampini       matis->islocalref = PETSC_TRUE;
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 
10458546b261SStefano Zampini       matis->islocalref = PETSC_FALSE;
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 
1310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1311d71ae5a4SJacob Faibussowitsch {
1312a8116848SStefano Zampini   Mat             locmat, newlocmat;
1313a8116848SStefano Zampini   Mat_IS         *newmatis;
1314a8116848SStefano Zampini   const PetscInt *idxs;
1315a8116848SStefano Zampini   PetscInt        i, m, n;
1316a8116848SStefano Zampini 
1317a8116848SStefano Zampini   PetscFunctionBegin;
1318a8116848SStefano Zampini   if (scall == MAT_REUSE_MATRIX) {
1319a8116848SStefano Zampini     PetscBool ismatis;
1320a8116848SStefano Zampini 
13219566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
132228b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1323a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
132428b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
132528b400f6SJacob Faibussowitsch     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1326a8116848SStefano Zampini   }
1327a8116848SStefano Zampini   /* irow and icol may not have duplicate entries */
132876bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
132976bd3646SJed Brown     Vec                rtest, ltest;
133076bd3646SJed Brown     const PetscScalar *array;
133176bd3646SJed Brown 
13329566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
13339566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &n));
13349566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
133548a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
13369566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(rtest));
13379566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(rtest));
13389566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rtest, &n));
13399566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
13409566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(rtest, &array));
1341aed4548fSBarry 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]));
13429566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(rtest, &array));
13439566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13449566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13459566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(icol, &idxs));
134648a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
13479566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(ltest));
13489566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(ltest));
13499566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ltest, &n));
13509566063dSJacob Faibussowitsch     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
13519566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(ltest, &array));
1352aed4548fSBarry 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]));
13539566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(ltest, &array));
13549566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(icol, &idxs));
13559566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&rtest));
13569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ltest));
135776bd3646SJed Brown   }
1358a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
1359a8116848SStefano Zampini     Mat_IS                *matis = (Mat_IS *)mat->data;
1360a8116848SStefano Zampini     ISLocalToGlobalMapping rl2g;
1361a8116848SStefano Zampini     IS                     is;
1362a8116848SStefano Zampini     PetscInt              *lidxs, *lgidxs, *newgidxs;
1363306cf5c7SStefano Zampini     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
136494342113SStefano Zampini     PetscBool              cong;
1365a8116848SStefano Zampini     MPI_Comm               comm;
1366a8116848SStefano Zampini 
13679566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
13689566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
13699566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(irow, &irbs));
13709566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(icol, &icbs));
1371306cf5c7SStefano Zampini     rbs = arbs == irbs ? irbs : 1;
1372306cf5c7SStefano Zampini     cbs = acbs == icbs ? icbs : 1;
13739566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(irow, &m));
13749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(icol, &n));
13759566063dSJacob Faibussowitsch     PetscCall(MatCreate(comm, newmat));
13769566063dSJacob Faibussowitsch     PetscCall(MatSetType(*newmat, MATIS));
13774f58015eSStefano Zampini     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
13789566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
13799566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1380a8116848SStefano Zampini     /* communicate irow to their owners in the layout */
13819566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(irow, &idxs));
13829566063dSJacob Faibussowitsch     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
13839566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(irow, &idxs));
13849566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1385a8116848SStefano Zampini     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
13869566063dSJacob Faibussowitsch     PetscCall(PetscFree(lidxs));
13879566063dSJacob Faibussowitsch     PetscCall(PetscFree(lgidxs));
13889566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13899566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
13909371c9d4SSatish Balay     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
13919371c9d4SSatish Balay       if (matis->sf_leafdata[i]) newloc++;
13929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &newgidxs));
13939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newloc, &lidxs));
13943d996552SStefano Zampini     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1395a8116848SStefano Zampini       if (matis->sf_leafdata[i]) {
1396a8116848SStefano Zampini         lidxs[newloc]      = i;
1397a8116848SStefano Zampini         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1398a8116848SStefano Zampini       }
13999566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14009566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
14019566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
14029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
1403a8116848SStefano Zampini     /* local is to extract local submatrix */
1404a8116848SStefano Zampini     newmatis = (Mat_IS *)(*newmat)->data;
14059566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
14069566063dSJacob Faibussowitsch     PetscCall(MatHasCongruentLayouts(mat, &cong));
140794342113SStefano Zampini     if (cong && irow == icol && matis->csf == matis->sf) {
14089566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
14099566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1410a8116848SStefano Zampini       newmatis->getsub_cis = newmatis->getsub_ris;
1411a8116848SStefano Zampini     } else {
1412a8116848SStefano Zampini       ISLocalToGlobalMapping cl2g;
1413a8116848SStefano Zampini 
1414a8116848SStefano Zampini       /* communicate icol to their owners in the layout */
14159566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(icol, &idxs));
14169566063dSJacob Faibussowitsch       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
14179566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(icol, &idxs));
14189566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1419a8116848SStefano Zampini       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
14209566063dSJacob Faibussowitsch       PetscCall(PetscFree(lidxs));
14219566063dSJacob Faibussowitsch       PetscCall(PetscFree(lgidxs));
14229566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
14249371c9d4SSatish Balay       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
14259371c9d4SSatish Balay         if (matis->csf_leafdata[i]) newloc++;
14269566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &newgidxs));
14279566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(newloc, &lidxs));
14283d996552SStefano Zampini       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1429a8116848SStefano Zampini         if (matis->csf_leafdata[i]) {
1430a8116848SStefano Zampini           lidxs[newloc]      = i;
1431a8116848SStefano Zampini           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1432a8116848SStefano Zampini         }
14339566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
14349566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
14359566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
14369566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1437a8116848SStefano Zampini       /* local is to extract local submatrix */
14389566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
14399566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
14409566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1441a8116848SStefano Zampini     }
14429566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1443a8116848SStefano Zampini   } else {
14449566063dSJacob Faibussowitsch     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1445a8116848SStefano Zampini   }
14469566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(mat, &locmat));
1447a8116848SStefano Zampini   newmatis = (Mat_IS *)(*newmat)->data;
14489566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1449a8116848SStefano Zampini   if (scall == MAT_INITIAL_MATRIX) {
14509566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
14519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlocmat));
1452a8116848SStefano Zampini   }
14539566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
14549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
14553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1456a8116848SStefano Zampini }
1457a8116848SStefano Zampini 
1458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1459d71ae5a4SJacob Faibussowitsch {
14602b404112SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data, *b;
14612b404112SStefano Zampini   PetscBool ismatis;
14622b404112SStefano Zampini 
14632b404112SStefano Zampini   PetscFunctionBegin;
14649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
146528b400f6SJacob Faibussowitsch   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
14662b404112SStefano Zampini   b = (Mat_IS *)B->data;
14679566063dSJacob Faibussowitsch   PetscCall(MatCopy(a->A, b->A, str));
14689566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)B));
14693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14702b404112SStefano Zampini }
14712b404112SStefano Zampini 
1472d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1473d71ae5a4SJacob Faibussowitsch {
1474527b2640SStefano Zampini   Vec                v;
1475527b2640SStefano Zampini   const PetscScalar *array;
1476527b2640SStefano Zampini   PetscInt           i, n;
14776bd84002SStefano Zampini 
14786bd84002SStefano Zampini   PetscFunctionBegin;
1479527b2640SStefano Zampini   *missing = PETSC_FALSE;
14809566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, NULL, &v));
14819566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(A, v));
14829566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(v, &n));
14839566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(v, &array));
14849371c9d4SSatish Balay   for (i = 0; i < n; i++)
14859371c9d4SSatish Balay     if (array[i] == 0.) break;
14869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(v, &array));
14879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&v));
1488527b2640SStefano Zampini   if (i != n) *missing = PETSC_TRUE;
1489527b2640SStefano Zampini   if (d) {
1490527b2640SStefano Zampini     *d = -1;
1491527b2640SStefano Zampini     if (*missing) {
1492527b2640SStefano Zampini       PetscInt rstart;
14939566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1494527b2640SStefano Zampini       *d = i + rstart;
1495527b2640SStefano Zampini     }
1496527b2640SStefano Zampini   }
14973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14986bd84002SStefano Zampini }
14996bd84002SStefano Zampini 
1500d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpSF_IS(Mat B)
1501d71ae5a4SJacob Faibussowitsch {
1502f4f49eeaSPierre Jolivet   Mat_IS         *matis = (Mat_IS *)B->data;
150328f4e0baSStefano Zampini   const PetscInt *gidxs;
15044f2d7cafSStefano Zampini   PetscInt        nleaves;
150528f4e0baSStefano Zampini 
150628f4e0baSStefano Zampini   PetscFunctionBegin;
15073ba16761SJacob Faibussowitsch   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
15089566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
15099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
15109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
15119566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
15139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1514e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
15159566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
15169566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
15179566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
15189566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
15199566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
15209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1521a8116848SStefano Zampini   } else {
1522a8116848SStefano Zampini     matis->csf          = matis->sf;
1523a8116848SStefano Zampini     matis->csf_leafdata = matis->sf_leafdata;
1524a8116848SStefano Zampini     matis->csf_rootdata = matis->sf_rootdata;
1525a8116848SStefano Zampini   }
15263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152728f4e0baSStefano Zampini }
15282e1947a5SStefano Zampini 
1529eb82efa4SStefano Zampini /*@
15304f58015eSStefano Zampini   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
15314f58015eSStefano Zampini 
15324f58015eSStefano Zampini   Not Collective
15334f58015eSStefano Zampini 
15344f58015eSStefano Zampini   Input Parameter:
15354f58015eSStefano Zampini . A - the matrix
15364f58015eSStefano Zampini 
15374f58015eSStefano Zampini   Output Parameter:
15384f58015eSStefano Zampini . flg - the boolean flag
15394f58015eSStefano Zampini 
15404f58015eSStefano Zampini   Level: intermediate
15414f58015eSStefano Zampini 
15424f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
15434f58015eSStefano Zampini @*/
15444f58015eSStefano Zampini PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
15454f58015eSStefano Zampini {
15464f58015eSStefano Zampini   PetscBool ismatis;
15474f58015eSStefano Zampini 
15484f58015eSStefano Zampini   PetscFunctionBegin;
15494f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15504f58015eSStefano Zampini   PetscAssertPointer(flg, 2);
15514f58015eSStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
15524f58015eSStefano Zampini   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
15534f58015eSStefano Zampini   *flg = ((Mat_IS *)A->data)->allow_repeated;
15544f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15554f58015eSStefano Zampini }
15564f58015eSStefano Zampini 
15574f58015eSStefano Zampini /*@
15584f58015eSStefano Zampini   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
15594f58015eSStefano Zampini 
15604f58015eSStefano Zampini   Logically Collective
15614f58015eSStefano Zampini 
15624f58015eSStefano Zampini   Input Parameters:
15634f58015eSStefano Zampini + A   - the matrix
15644f58015eSStefano Zampini - flg - the boolean flag
15654f58015eSStefano Zampini 
15664f58015eSStefano Zampini   Level: intermediate
15674f58015eSStefano Zampini 
15684f58015eSStefano Zampini   Notes:
15694f58015eSStefano Zampini   The default value is `PETSC_FALSE`.
15704f58015eSStefano Zampini   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
15714f58015eSStefano Zampini   if `flg` is different from the previously set value.
15724f58015eSStefano Zampini   Specifically, when `flg` is true it will just recreate the local matrices, while if
15734f58015eSStefano Zampini   `flg` is false will assemble the local matrices summing up repeated entries.
15744f58015eSStefano Zampini 
15754f58015eSStefano Zampini .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
15764f58015eSStefano Zampini @*/
15774f58015eSStefano Zampini PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
15784f58015eSStefano Zampini {
15794f58015eSStefano Zampini   PetscFunctionBegin;
15804f58015eSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
15814f58015eSStefano Zampini   PetscValidType(A, 1);
15824f58015eSStefano Zampini   PetscValidLogicalCollectiveBool(A, flg, 2);
15834f58015eSStefano Zampini   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
15844f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
15854f58015eSStefano Zampini }
15864f58015eSStefano Zampini 
15874f58015eSStefano Zampini static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
15884f58015eSStefano Zampini {
15894f58015eSStefano Zampini   Mat_IS                *matis = (Mat_IS *)A->data;
15904f58015eSStefano Zampini   Mat                    lA    = NULL;
15914f58015eSStefano Zampini   ISLocalToGlobalMapping lrmap, lcmap;
15924f58015eSStefano Zampini 
15934f58015eSStefano Zampini   PetscFunctionBegin;
15944f58015eSStefano Zampini   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
15954f58015eSStefano Zampini   if (!matis->A) { /* matrix has not been preallocated yet */
15964f58015eSStefano Zampini     matis->allow_repeated = flg;
15974f58015eSStefano Zampini     PetscFunctionReturn(PETSC_SUCCESS);
15984f58015eSStefano Zampini   }
15994f58015eSStefano Zampini   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
16004f58015eSStefano Zampini   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
16014f58015eSStefano Zampini     lA = matis->A;
16024f58015eSStefano Zampini     PetscCall(PetscObjectReference((PetscObject)lA));
16034f58015eSStefano Zampini   }
16044f58015eSStefano Zampini   /* In case flg is True, we only recreate the local matrix */
16054f58015eSStefano Zampini   matis->allow_repeated = flg;
16064f58015eSStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
16074f58015eSStefano Zampini   if (lA) { /* assemble previous local matrix if needed */
16084f58015eSStefano Zampini     Mat nA = matis->A;
16094f58015eSStefano Zampini 
16104f58015eSStefano Zampini     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
16114f58015eSStefano Zampini     if (!lrmap && !lcmap) {
16124f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, lA));
16134f58015eSStefano Zampini     } else {
16144f58015eSStefano Zampini       Mat            P = NULL, R = NULL;
16154f58015eSStefano Zampini       MatProductType ptype;
16164f58015eSStefano Zampini 
16174f58015eSStefano Zampini       if (lrmap == lcmap) {
16184f58015eSStefano Zampini         ptype = MATPRODUCT_PtAP;
16194f58015eSStefano Zampini         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16204f58015eSStefano Zampini         PetscCall(MatProductCreate(lA, P, NULL, &nA));
16214f58015eSStefano Zampini       } else {
16224f58015eSStefano Zampini         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
16234f58015eSStefano Zampini         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
16244f58015eSStefano Zampini         if (R && P) {
16254f58015eSStefano Zampini           ptype = MATPRODUCT_ABC;
16264f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, P, &nA));
16274f58015eSStefano Zampini         } else if (R) {
16284f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16294f58015eSStefano Zampini           PetscCall(MatProductCreate(R, lA, NULL, &nA));
16304f58015eSStefano Zampini         } else {
16314f58015eSStefano Zampini           ptype = MATPRODUCT_AB;
16324f58015eSStefano Zampini           PetscCall(MatProductCreate(lA, P, NULL, &nA));
16334f58015eSStefano Zampini         }
16344f58015eSStefano Zampini       }
16354f58015eSStefano Zampini       PetscCall(MatProductSetType(nA, ptype));
16364f58015eSStefano Zampini       PetscCall(MatProductSetFromOptions(nA));
16374f58015eSStefano Zampini       PetscCall(MatProductSymbolic(nA));
16384f58015eSStefano Zampini       PetscCall(MatProductNumeric(nA));
16394f58015eSStefano Zampini       PetscCall(MatProductClear(nA));
16404f58015eSStefano Zampini       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
16414f58015eSStefano Zampini       PetscCall(MatISSetLocalMat(A, nA));
16424f58015eSStefano Zampini       PetscCall(MatDestroy(&nA));
16434f58015eSStefano Zampini       PetscCall(MatDestroy(&P));
16444f58015eSStefano Zampini       PetscCall(MatDestroy(&R));
16454f58015eSStefano Zampini     }
16464f58015eSStefano Zampini   }
16474f58015eSStefano Zampini   PetscCall(MatDestroy(&lA));
16484f58015eSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
16494f58015eSStefano Zampini }
16504f58015eSStefano Zampini 
16514f58015eSStefano Zampini /*@
16522ef1f0ffSBarry Smith   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
165375d48cdbSStefano Zampini 
16544f58015eSStefano Zampini   Logically Collective
165575d48cdbSStefano Zampini 
165675d48cdbSStefano Zampini   Input Parameters:
165775d48cdbSStefano Zampini + A     - the matrix
165875d48cdbSStefano Zampini - store - the boolean flag
165975d48cdbSStefano Zampini 
166075d48cdbSStefano Zampini   Level: advanced
166175d48cdbSStefano Zampini 
16621cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
166375d48cdbSStefano Zampini @*/
1664d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1665d71ae5a4SJacob Faibussowitsch {
166675d48cdbSStefano Zampini   PetscFunctionBegin;
166775d48cdbSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
166875d48cdbSStefano Zampini   PetscValidType(A, 1);
166975d48cdbSStefano Zampini   PetscValidLogicalCollectiveBool(A, store, 2);
1670cac4c232SBarry Smith   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
16713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
167275d48cdbSStefano Zampini }
167375d48cdbSStefano Zampini 
1674d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1675d71ae5a4SJacob Faibussowitsch {
1676f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
167775d48cdbSStefano Zampini 
167875d48cdbSStefano Zampini   PetscFunctionBegin;
167975d48cdbSStefano Zampini   matis->storel2l = store;
168057508eceSPierre Jolivet   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
16813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
168275d48cdbSStefano Zampini }
168375d48cdbSStefano Zampini 
168475d48cdbSStefano Zampini /*@
1685f03112d0SStefano Zampini   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1686f03112d0SStefano Zampini 
16874f58015eSStefano Zampini   Logically Collective
1688f03112d0SStefano Zampini 
1689f03112d0SStefano Zampini   Input Parameters:
1690f03112d0SStefano Zampini + A   - the matrix
1691f03112d0SStefano Zampini - fix - the boolean flag
1692f03112d0SStefano Zampini 
1693f03112d0SStefano Zampini   Level: advanced
1694f03112d0SStefano Zampini 
169511a5261eSBarry Smith   Note:
16962fe279fdSBarry Smith   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1697f03112d0SStefano Zampini 
16981cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1699f03112d0SStefano Zampini @*/
1700d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1701d71ae5a4SJacob Faibussowitsch {
1702f03112d0SStefano Zampini   PetscFunctionBegin;
1703f03112d0SStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1704f03112d0SStefano Zampini   PetscValidType(A, 1);
1705f03112d0SStefano Zampini   PetscValidLogicalCollectiveBool(A, fix, 2);
1706cac4c232SBarry Smith   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
17073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1708f03112d0SStefano Zampini }
1709f03112d0SStefano Zampini 
1710d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1711d71ae5a4SJacob Faibussowitsch {
1712f4f49eeaSPierre Jolivet   Mat_IS *matis = (Mat_IS *)A->data;
1713f03112d0SStefano Zampini 
1714f03112d0SStefano Zampini   PetscFunctionBegin;
1715f03112d0SStefano Zampini   matis->locempty = fix;
17163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1717f03112d0SStefano Zampini }
1718f03112d0SStefano Zampini 
1719f03112d0SStefano Zampini /*@
172011a5261eSBarry Smith   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1721a88811baSStefano Zampini 
1722d083f849SBarry Smith   Collective
1723a88811baSStefano Zampini 
1724a88811baSStefano Zampini   Input Parameters:
1725a88811baSStefano Zampini + B     - the matrix
1726a88811baSStefano Zampini . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1727a88811baSStefano Zampini            (same value is used for all local rows)
1728a88811baSStefano Zampini . d_nnz - array containing the number of nonzeros in the various rows of the
1729a88811baSStefano Zampini            DIAGONAL portion of the local submatrix (possibly different for each row)
17302ef1f0ffSBarry Smith            or `NULL`, if `d_nz` is used to specify the nonzero structure.
17312ef1f0ffSBarry Smith            The size of this array is equal to the number of local rows, i.e `m`.
1732a88811baSStefano Zampini            For matrices that will be factored, you must leave room for (and set)
1733a88811baSStefano Zampini            the diagonal entry even if it is zero.
1734a88811baSStefano Zampini . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1735a88811baSStefano Zampini            submatrix (same value is used for all local rows).
1736a88811baSStefano Zampini - o_nnz - array containing the number of nonzeros in the various rows of the
1737a88811baSStefano Zampini            OFF-DIAGONAL portion of the local submatrix (possibly different for
17382ef1f0ffSBarry Smith            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1739a88811baSStefano Zampini            structure. The size of this array is equal to the number
17402ef1f0ffSBarry Smith            of local rows, i.e `m`.
1741a88811baSStefano Zampini 
1742a88811baSStefano Zampini    If the *_nnz parameter is given then the *_nz parameter is ignored
1743a88811baSStefano Zampini 
1744a88811baSStefano Zampini   Level: intermediate
1745a88811baSStefano Zampini 
174611a5261eSBarry Smith   Note:
174711a5261eSBarry Smith   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
174811a5261eSBarry Smith   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1749a88811baSStefano Zampini   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1750a88811baSStefano Zampini 
17511cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1752a88811baSStefano Zampini @*/
1753d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1754d71ae5a4SJacob Faibussowitsch {
17552e1947a5SStefano Zampini   PetscFunctionBegin;
17562e1947a5SStefano Zampini   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
17572e1947a5SStefano Zampini   PetscValidType(B, 1);
1758cac4c232SBarry Smith   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
17593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17602e1947a5SStefano Zampini }
17612e1947a5SStefano Zampini 
1762523895eeSPierre Jolivet static PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1763d71ae5a4SJacob Faibussowitsch {
1764f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)B->data;
176528f4e0baSStefano Zampini   PetscInt bs, i, nlocalcols;
17662e1947a5SStefano Zampini 
17672e1947a5SStefano Zampini   PetscFunctionBegin;
17689566063dSJacob Faibussowitsch   PetscCall(MatSetUp(B));
17699371c9d4SSatish Balay   if (!d_nnz)
17709371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
17719371c9d4SSatish Balay   else
17729371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
17734f2d7cafSStefano Zampini 
17749371c9d4SSatish Balay   if (!o_nnz)
17759371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
17769371c9d4SSatish Balay   else
17779371c9d4SSatish Balay     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
17784f2d7cafSStefano Zampini 
17799566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17809566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
17819566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(matis->A, &bs));
17829566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
17834f2d7cafSStefano Zampini 
17844f2d7cafSStefano Zampini   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
17859566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
17860f2f62c7SStefano Zampini #if defined(PETSC_HAVE_HYPRE)
17879566063dSJacob Faibussowitsch   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
17880f2f62c7SStefano Zampini #endif
17894f2d7cafSStefano Zampini 
1790fc989267SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1791fc989267SStefano Zampini     PetscInt b;
1792fc989267SStefano Zampini 
1793fc989267SStefano Zampini     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1794ad540459SPierre Jolivet     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1795fc989267SStefano Zampini   }
17969566063dSJacob Faibussowitsch   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
17974f2d7cafSStefano Zampini 
179800a59248SStefano Zampini   nlocalcols /= bs;
179900a59248SStefano Zampini   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
18009566063dSJacob Faibussowitsch   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
18010f2f62c7SStefano Zampini 
18020f2f62c7SStefano Zampini   /* for other matrix types */
18039566063dSJacob Faibussowitsch   PetscCall(MatSetUp(matis->A));
18043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18052e1947a5SStefano Zampini }
1806b4319ba4SBarry Smith 
1807d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1808d71ae5a4SJacob Faibussowitsch {
1809f4f49eeaSPierre Jolivet   Mat_IS            *matis     = (Mat_IS *)mat->data;
1810*ac7f1a8bSStefano Zampini   Mat                local_mat = NULL, MT;
181153b44cf5SStefano Zampini   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1812b7ce53b6SStefano Zampini   PetscInt           local_rows, local_cols;
1813b9ed4604SStefano Zampini   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1814f03112d0SStefano Zampini   PetscMPIInt        size;
18151683a169SBarry Smith   const PetscScalar *array;
1816b7ce53b6SStefano Zampini 
1817b7ce53b6SStefano Zampini   PetscFunctionBegin;
18189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
18194f58015eSStefano Zampini   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
18201670daf9Sstefano_zampini     Mat      B;
182153b44cf5SStefano Zampini     IS       irows = NULL, icols = NULL;
1822487b449aSStefano Zampini     PetscInt rbs, cbs;
18231670daf9Sstefano_zampini 
18249566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
182653b44cf5SStefano Zampini     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
182753b44cf5SStefano Zampini       IS              rows, cols;
182853b44cf5SStefano Zampini       const PetscInt *ridxs, *cidxs;
18294f58015eSStefano Zampini       PetscInt        i, nw;
18304f58015eSStefano Zampini       PetscBT         work;
183153b44cf5SStefano Zampini 
18329566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
18339566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
183453b44cf5SStefano Zampini       nw = nw / rbs;
18354f58015eSStefano Zampini       PetscCall(PetscBTCreate(nw, &work));
18364f58015eSStefano Zampini       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
18379371c9d4SSatish Balay       for (i = 0; i < nw; i++)
18384f58015eSStefano Zampini         if (!PetscBTLookup(work, i)) break;
183953b44cf5SStefano Zampini       if (i == nw) {
18409566063dSJacob Faibussowitsch         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
18419566063dSJacob Faibussowitsch         PetscCall(ISSetPermutation(rows));
18429566063dSJacob Faibussowitsch         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
18439566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rows));
184453b44cf5SStefano Zampini       }
18459566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
18464f58015eSStefano Zampini       PetscCall(PetscBTDestroy(&work));
1847e432b41dSStefano Zampini       if (irows && matis->rmapping != matis->cmapping) {
18489566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
18499566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
185053b44cf5SStefano Zampini         nw = nw / cbs;
18514f58015eSStefano Zampini         PetscCall(PetscBTCreate(nw, &work));
18524f58015eSStefano Zampini         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
18539371c9d4SSatish Balay         for (i = 0; i < nw; i++)
18544f58015eSStefano Zampini           if (!PetscBTLookup(work, i)) break;
185553b44cf5SStefano Zampini         if (i == nw) {
18569566063dSJacob Faibussowitsch           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
18579566063dSJacob Faibussowitsch           PetscCall(ISSetPermutation(cols));
18589566063dSJacob Faibussowitsch           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
18599566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&cols));
186053b44cf5SStefano Zampini         }
18619566063dSJacob Faibussowitsch         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
18624f58015eSStefano Zampini         PetscCall(PetscBTDestroy(&work));
186353b44cf5SStefano Zampini       } else if (irows) {
18649566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)irows));
186553b44cf5SStefano Zampini         icols = irows;
186653b44cf5SStefano Zampini       }
186753b44cf5SStefano Zampini     } else {
1868f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
1869f4f49eeaSPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
18709566063dSJacob Faibussowitsch       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
18719566063dSJacob Faibussowitsch       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
187253b44cf5SStefano Zampini     }
187353b44cf5SStefano Zampini     if (!irows || !icols) {
18749566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&icols));
18759566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&irows));
187653b44cf5SStefano Zampini       goto general_assembly;
187753b44cf5SStefano Zampini     }
18789566063dSJacob Faibussowitsch     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1879487b449aSStefano Zampini     if (reuse != MAT_INPLACE_MATRIX) {
18809566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
1881f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
1882f4f49eeaSPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1883487b449aSStefano Zampini     } else {
1884487b449aSStefano Zampini       Mat C;
1885487b449aSStefano Zampini 
18869566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
18879566063dSJacob Faibussowitsch       PetscCall(MatHeaderReplace(mat, &C));
1888487b449aSStefano Zampini     }
18899566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&B));
18909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&icols));
18919566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&irows));
18923ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
18937c03b4e8SStefano Zampini   }
189453b44cf5SStefano Zampini general_assembly:
18959566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &rows, &cols));
18969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
18979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
18989566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
18999566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
19009566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
19019566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
19029566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
19039566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1904f4f49eeaSPierre Jolivet   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
190576bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
190676bd3646SJed Brown     PetscBool lb[4], bb[4];
190776bd3646SJed Brown 
1908b9ed4604SStefano Zampini     lb[0] = isseqdense;
1909b9ed4604SStefano Zampini     lb[1] = isseqaij;
1910b9ed4604SStefano Zampini     lb[2] = isseqbaij;
1911b9ed4604SStefano Zampini     lb[3] = isseqsbaij;
1912462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1913aed4548fSBarry Smith     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
191476bd3646SJed Brown   }
1915b7ce53b6SStefano Zampini 
1916487b449aSStefano Zampini   if (reuse != MAT_REUSE_MATRIX) {
1917*ac7f1a8bSStefano Zampini     PetscCount ncoo;
1918*ac7f1a8bSStefano Zampini     PetscInt  *coo_i, *coo_j;
1919*ac7f1a8bSStefano Zampini 
19209566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
19219566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
19229566063dSJacob Faibussowitsch     PetscCall(MatSetType(MT, mtype));
19239566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
1924*ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
1925*ac7f1a8bSStefano Zampini       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1926*ac7f1a8bSStefano Zampini     } else {
1927*ac7f1a8bSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)matis->A));
1928*ac7f1a8bSStefano Zampini       local_mat = matis->A;
1929*ac7f1a8bSStefano Zampini     }
1930*ac7f1a8bSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1931*ac7f1a8bSStefano Zampini     if (isseqdense) {
1932*ac7f1a8bSStefano Zampini       PetscInt nr, nc;
1933*ac7f1a8bSStefano Zampini 
1934*ac7f1a8bSStefano Zampini       PetscCall(MatGetSize(local_mat, &nr, &nc));
1935*ac7f1a8bSStefano Zampini       ncoo = nr * nc;
1936*ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1937*ac7f1a8bSStefano Zampini       for (PetscInt j = 0; j < nc; j++) {
1938*ac7f1a8bSStefano Zampini         for (PetscInt i = 0; i < nr; i++) {
1939*ac7f1a8bSStefano Zampini           coo_i[j * nr + i] = i;
1940*ac7f1a8bSStefano Zampini           coo_j[j * nr + i] = j;
1941*ac7f1a8bSStefano Zampini         }
1942*ac7f1a8bSStefano Zampini       }
1943*ac7f1a8bSStefano Zampini     } else {
1944*ac7f1a8bSStefano Zampini       const PetscInt *ii, *jj;
1945*ac7f1a8bSStefano Zampini       PetscInt        nr;
1946*ac7f1a8bSStefano Zampini       PetscBool       done;
1947*ac7f1a8bSStefano Zampini 
1948*ac7f1a8bSStefano Zampini       PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1949*ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1950*ac7f1a8bSStefano Zampini       ncoo = ii[nr];
1951*ac7f1a8bSStefano Zampini       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1952*ac7f1a8bSStefano Zampini       PetscCall(PetscArraycpy(coo_j, jj, ncoo));
1953*ac7f1a8bSStefano Zampini       for (PetscInt i = 0; i < nr; i++) {
1954*ac7f1a8bSStefano Zampini         for (PetscInt j = ii[i]; j < ii[i + 1]; j++) coo_i[j] = i;
1955*ac7f1a8bSStefano Zampini       }
1956*ac7f1a8bSStefano Zampini       PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1957*ac7f1a8bSStefano Zampini       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1958*ac7f1a8bSStefano Zampini     }
1959*ac7f1a8bSStefano Zampini     PetscCall(MatSetPreallocationCOOLocal(MT, ncoo, coo_i, coo_j));
1960*ac7f1a8bSStefano Zampini     PetscCall(PetscFree2(coo_i, coo_j));
1961b7ce53b6SStefano Zampini   } else {
196253b44cf5SStefano Zampini     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1963487b449aSStefano Zampini 
1964b7ce53b6SStefano Zampini     /* some checks */
1965487b449aSStefano Zampini     MT = *M;
19669566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
19679566063dSJacob Faibussowitsch     PetscCall(MatGetSize(MT, &mrows, &mcols));
19689566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
196908401ef6SPierre Jolivet     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
197008401ef6SPierre Jolivet     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
197108401ef6SPierre Jolivet     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
197208401ef6SPierre Jolivet     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
197308401ef6SPierre Jolivet     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
197408401ef6SPierre Jolivet     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
19759566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(MT));
1976*ac7f1a8bSStefano Zampini     if (!isseqaij && !isseqdense) {
19779566063dSJacob Faibussowitsch       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1978d9a9e74cSStefano Zampini     } else {
19799566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)matis->A));
1980d9a9e74cSStefano Zampini       local_mat = matis->A;
1981d9a9e74cSStefano Zampini     }
1982*ac7f1a8bSStefano Zampini   }
1983686e3a49SStefano Zampini 
1984b7ce53b6SStefano Zampini   /* Set values */
1985*ac7f1a8bSStefano Zampini   if (isseqdense) {
19869566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArrayRead(local_mat, &array));
1987*ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
19889566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
19896afe12f5SStefano Zampini   } else {
1990*ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJGetArrayRead(local_mat, &array));
1991*ac7f1a8bSStefano Zampini     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
1992*ac7f1a8bSStefano Zampini     PetscCall(MatSeqAIJRestoreArrayRead(local_mat, &array));
1993b7ce53b6SStefano Zampini   }
19949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&local_mat));
19954f58015eSStefano Zampini   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
19969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
1997487b449aSStefano Zampini   if (reuse == MAT_INPLACE_MATRIX) {
19989566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(mat, &MT));
1999487b449aSStefano Zampini   } else if (reuse == MAT_INITIAL_MATRIX) {
2000487b449aSStefano Zampini     *M = MT;
2001b7ce53b6SStefano Zampini   }
20023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2003b7ce53b6SStefano Zampini }
2004b7ce53b6SStefano Zampini 
2005d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2006d71ae5a4SJacob Faibussowitsch {
2007f4f49eeaSPierre Jolivet   Mat_IS  *matis = (Mat_IS *)mat->data;
2008c9225affSStefano Zampini   PetscInt rbs, cbs, m, n, M, N;
2009ad6194a2SStefano Zampini   Mat      B, localmat;
2010ad6194a2SStefano Zampini 
2011ad6194a2SStefano Zampini   PetscFunctionBegin;
20129566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
20139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
20149566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &M, &N));
20159566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &m, &n));
20169566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
20179566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(B, m, n, M, N));
20189566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
20199566063dSJacob Faibussowitsch   PetscCall(MatSetType(B, MATIS));
20209566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
20214f58015eSStefano Zampini   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
20229566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
20239566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(matis->A, op, &localmat));
20249566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
20259566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(B, localmat));
20269566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&localmat));
20279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
20289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2029ad6194a2SStefano Zampini   *newmat = B;
20303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2031ad6194a2SStefano Zampini }
2032ad6194a2SStefano Zampini 
2033d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2034d71ae5a4SJacob Faibussowitsch {
203569796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
203669796d55SStefano Zampini   PetscBool local_sym;
203769796d55SStefano Zampini 
203869796d55SStefano Zampini   PetscFunctionBegin;
20399566063dSJacob Faibussowitsch   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
2040462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
204269796d55SStefano Zampini }
204369796d55SStefano Zampini 
2044d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2045d71ae5a4SJacob Faibussowitsch {
204669796d55SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
204769796d55SStefano Zampini   PetscBool local_sym;
204869796d55SStefano Zampini 
204969796d55SStefano Zampini   PetscFunctionBegin;
2050e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
2051e432b41dSStefano Zampini     *flg = PETSC_FALSE;
20523ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2053e432b41dSStefano Zampini   }
20549566063dSJacob Faibussowitsch   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
2055462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
205769796d55SStefano Zampini }
205869796d55SStefano Zampini 
2059d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2060d71ae5a4SJacob Faibussowitsch {
206145471136SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
206245471136SStefano Zampini   PetscBool local_sym;
206345471136SStefano Zampini 
206445471136SStefano Zampini   PetscFunctionBegin;
2065e432b41dSStefano Zampini   if (matis->rmapping != matis->cmapping) {
206645471136SStefano Zampini     *flg = PETSC_FALSE;
20673ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
206845471136SStefano Zampini   }
20699566063dSJacob Faibussowitsch   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
2070462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
20713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207245471136SStefano Zampini }
207345471136SStefano Zampini 
2074d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_IS(Mat A)
2075d71ae5a4SJacob Faibussowitsch {
2076b4319ba4SBarry Smith   Mat_IS *b = (Mat_IS *)A->data;
2077b4319ba4SBarry Smith 
2078b4319ba4SBarry Smith   PetscFunctionBegin;
20799566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->bdiag));
20809566063dSJacob Faibussowitsch   PetscCall(PetscFree(b->lmattype));
20819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&b->A));
20829566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->cctx));
20839566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&b->rctx));
20849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->x));
20859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->y));
20869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&b->counter));
20879566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_ris));
20889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&b->getsub_cis));
2089a8116848SStefano Zampini   if (b->sf != b->csf) {
20909566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&b->csf));
20919566063dSJacob Faibussowitsch     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2092f03112d0SStefano Zampini   } else b->csf = NULL;
20939566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&b->sf));
20949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
20959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
20969566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2097d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->dA));
2098d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(&b->assembledA));
20999566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
21009566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
21019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
21029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
21039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
21042e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
21059566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
21069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
21079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
21089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
21099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
21109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
21119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
21129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
21139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
21149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
21159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
21169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
21179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
21189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
21194f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
21203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2121b4319ba4SBarry Smith }
2122b4319ba4SBarry Smith 
2123d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2124d71ae5a4SJacob Faibussowitsch {
2125b4319ba4SBarry Smith   Mat_IS     *is   = (Mat_IS *)A->data;
2126b4319ba4SBarry Smith   PetscScalar zero = 0.0;
2127b4319ba4SBarry Smith 
2128b4319ba4SBarry Smith   PetscFunctionBegin;
2129b4319ba4SBarry Smith   /*  scatter the global vector x into the local work vector */
21309566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
21319566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2132b4319ba4SBarry Smith 
2133b4319ba4SBarry Smith   /* multiply the local matrix */
21349566063dSJacob Faibussowitsch   PetscCall(MatMult(is->A, is->x, is->y));
2135b4319ba4SBarry Smith 
2136b4319ba4SBarry Smith   /* scatter product back into global memory */
21379566063dSJacob Faibussowitsch   PetscCall(VecSet(y, zero));
21389566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21399566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
21403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2141b4319ba4SBarry Smith }
2142b4319ba4SBarry Smith 
2143d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2144d71ae5a4SJacob Faibussowitsch {
2145650997f4SStefano Zampini   Vec temp_vec;
21462e74eeadSLisandro Dalcin 
21472e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2148650997f4SStefano Zampini   if (v3 != v2) {
21499566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, v3));
21509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2151650997f4SStefano Zampini   } else {
21529566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
21539566063dSJacob Faibussowitsch     PetscCall(MatMult(A, v1, temp_vec));
21549566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
21559566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
21569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2157650997f4SStefano Zampini   }
21583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21592e74eeadSLisandro Dalcin }
21602e74eeadSLisandro Dalcin 
2161d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2162d71ae5a4SJacob Faibussowitsch {
21632e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
21642e74eeadSLisandro Dalcin 
2165e176bc59SStefano Zampini   PetscFunctionBegin;
21662e74eeadSLisandro Dalcin   /*  scatter the global vector x into the local work vector */
21679566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
21689566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
21692e74eeadSLisandro Dalcin 
21702e74eeadSLisandro Dalcin   /* multiply the local matrix */
21719566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(is->A, is->y, is->x));
21722e74eeadSLisandro Dalcin 
21732e74eeadSLisandro Dalcin   /* scatter product back into global vector */
21749566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 0));
21759566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
21769566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
21773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21782e74eeadSLisandro Dalcin }
21792e74eeadSLisandro Dalcin 
2180d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2181d71ae5a4SJacob Faibussowitsch {
2182650997f4SStefano Zampini   Vec temp_vec;
21832e74eeadSLisandro Dalcin 
21842e74eeadSLisandro Dalcin   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2185650997f4SStefano Zampini   if (v3 != v2) {
21869566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, v3));
21879566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v3, 1.0, v2));
2188650997f4SStefano Zampini   } else {
21899566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(v2, &temp_vec));
21909566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, v1, temp_vec));
21919566063dSJacob Faibussowitsch     PetscCall(VecAXPY(temp_vec, 1.0, v2));
21929566063dSJacob Faibussowitsch     PetscCall(VecCopy(temp_vec, v3));
21939566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&temp_vec));
2194650997f4SStefano Zampini   }
21953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21962e74eeadSLisandro Dalcin }
21972e74eeadSLisandro Dalcin 
2198d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2199d71ae5a4SJacob Faibussowitsch {
2200b4319ba4SBarry Smith   Mat_IS                *a = (Mat_IS *)A->data;
2201b4319ba4SBarry Smith   PetscViewer            sviewer;
22025042aa92SStefano Zampini   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
22035042aa92SStefano Zampini   PetscViewerFormat      format;
22045042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2205b4319ba4SBarry Smith 
2206b4319ba4SBarry Smith   PetscFunctionBegin;
22079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
22085042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
22099566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
22105042aa92SStefano Zampini   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
22115042aa92SStefano Zampini   if (native) {
22125042aa92SStefano Zampini     rmap = A->rmap->mapping;
22135042aa92SStefano Zampini     cmap = A->cmap->mapping;
22145042aa92SStefano Zampini   } else {
22155042aa92SStefano Zampini     rmap = a->rmapping;
22165042aa92SStefano Zampini     cmap = a->cmapping;
2217ee2491ecSStefano Zampini   }
22185042aa92SStefano Zampini   if (isascii) {
22195042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
22205042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
22215042aa92SStefano Zampini   } else if (isbinary) {
22225042aa92SStefano Zampini     PetscInt    tr[6], nr, nc;
22235042aa92SStefano Zampini     char        lmattype[64] = {'\0'};
22245042aa92SStefano Zampini     PetscMPIInt size;
22255042aa92SStefano Zampini     PetscBool   skipHeader;
22265042aa92SStefano Zampini     IS          is;
22275042aa92SStefano Zampini 
22285042aa92SStefano Zampini     PetscCall(PetscViewerSetUp(viewer));
22295042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
22305042aa92SStefano Zampini     tr[0] = MAT_FILE_CLASSID;
22315042aa92SStefano Zampini     tr[1] = A->rmap->N;
22325042aa92SStefano Zampini     tr[2] = A->cmap->N;
22335042aa92SStefano Zampini     tr[3] = -size; /* AIJ stores nnz here */
22345042aa92SStefano Zampini     tr[4] = (PetscInt)(rmap == cmap);
22355042aa92SStefano Zampini     tr[5] = a->allow_repeated;
22365042aa92SStefano Zampini     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
22375042aa92SStefano Zampini 
22385042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
22395042aa92SStefano Zampini     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
22405042aa92SStefano Zampini 
22415042aa92SStefano Zampini     /* first dump l2g info (we need the header for proper loading on different number of processes) */
22425042aa92SStefano Zampini     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
22435042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
22445042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
22455042aa92SStefano Zampini     if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
22465042aa92SStefano Zampini 
22475042aa92SStefano Zampini     /* then the sizes of the local matrices */
22485042aa92SStefano Zampini     PetscCall(MatGetSize(a->A, &nr, &nc));
22495042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
22505042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
22515042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
22525042aa92SStefano Zampini     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
22535042aa92SStefano Zampini     PetscCall(ISView(is, viewer));
22545042aa92SStefano Zampini     PetscCall(ISDestroy(&is));
22555042aa92SStefano Zampini     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
22565042aa92SStefano Zampini   }
22575042aa92SStefano Zampini   if (format == PETSC_VIEWER_ASCII_MATLAB) {
22585042aa92SStefano Zampini     char        name[64];
22595042aa92SStefano Zampini     PetscMPIInt size, rank;
22605042aa92SStefano Zampini 
22615042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
22625042aa92SStefano Zampini     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
22635042aa92SStefano Zampini     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
22645042aa92SStefano Zampini     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
22655042aa92SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
22665042aa92SStefano Zampini   }
22675042aa92SStefano Zampini 
22685042aa92SStefano Zampini   /* Dump the local matrices */
22695042aa92SStefano Zampini   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
22705042aa92SStefano Zampini     PetscBool   isaij;
22715042aa92SStefano Zampini     PetscInt    nr, nc;
22725042aa92SStefano Zampini     Mat         lA, B;
22735042aa92SStefano Zampini     Mat_MPIAIJ *b;
22745042aa92SStefano Zampini 
22755042aa92SStefano Zampini     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
22765042aa92SStefano Zampini     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
22775042aa92SStefano Zampini     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
22785042aa92SStefano Zampini     else {
22795042aa92SStefano Zampini       PetscCall(PetscObjectReference((PetscObject)a->A));
22805042aa92SStefano Zampini       lA = a->A;
22815042aa92SStefano Zampini     }
22825042aa92SStefano Zampini     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
22835042aa92SStefano Zampini     PetscCall(MatSetType(B, MATMPIAIJ));
22845042aa92SStefano Zampini     PetscCall(MatGetSize(lA, &nr, &nc));
22855042aa92SStefano Zampini     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
22865042aa92SStefano Zampini     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
22875042aa92SStefano Zampini 
22885042aa92SStefano Zampini     b = (Mat_MPIAIJ *)B->data;
22895042aa92SStefano Zampini     PetscCall(MatDestroy(&b->A));
22905042aa92SStefano Zampini     b->A = lA;
22915042aa92SStefano Zampini 
22925042aa92SStefano Zampini     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
22935042aa92SStefano Zampini     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
22945042aa92SStefano Zampini     PetscCall(MatView(B, viewer));
22955042aa92SStefano Zampini     PetscCall(MatDestroy(&B));
22965042aa92SStefano Zampini   } else {
22979566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
22989566063dSJacob Faibussowitsch     PetscCall(MatView(a->A, sviewer));
22999566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
23005042aa92SStefano Zampini   }
23015042aa92SStefano Zampini 
23025042aa92SStefano Zampini   /* with ASCII, we dump the l2gmaps at the end */
23035042aa92SStefano Zampini   if (viewl2g) {
23045042aa92SStefano Zampini     if (format == PETSC_VIEWER_ASCII_MATLAB) {
23055042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
23065042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23075042aa92SStefano Zampini       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
23085042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23095042aa92SStefano Zampini     } else {
23105042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
23115042aa92SStefano Zampini       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
23125042aa92SStefano Zampini     }
23135042aa92SStefano Zampini   }
23145042aa92SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
23155042aa92SStefano Zampini }
23165042aa92SStefano Zampini 
23175042aa92SStefano Zampini static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
23185042aa92SStefano Zampini {
23195042aa92SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
23205042aa92SStefano Zampini   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
23215042aa92SStefano Zampini   PetscBool              isbinary, samel, allow, isbaij;
23225042aa92SStefano Zampini   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
23235042aa92SStefano Zampini   const PetscInt        *idx;
23245042aa92SStefano Zampini   PetscMPIInt            size;
23255042aa92SStefano Zampini   char                   lmattype[64];
23265042aa92SStefano Zampini   Mat                    dA, lA;
23275042aa92SStefano Zampini   IS                     is;
23285042aa92SStefano Zampini 
23295042aa92SStefano Zampini   PetscFunctionBegin;
23305042aa92SStefano Zampini   PetscCheckSameComm(A, 1, viewer, 2);
23315042aa92SStefano Zampini   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
23325042aa92SStefano Zampini   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
23335042aa92SStefano Zampini 
23345042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
23355042aa92SStefano Zampini   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
23365042aa92SStefano Zampini   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
23375042aa92SStefano Zampini   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
23385042aa92SStefano Zampini   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
23395042aa92SStefano Zampini   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
23405042aa92SStefano Zampini   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
23415042aa92SStefano Zampini   M     = tr[1];
23425042aa92SStefano Zampini   N     = tr[2];
23435042aa92SStefano Zampini   Asize = -tr[3];
23445042aa92SStefano Zampini   samel = (PetscBool)tr[4];
23455042aa92SStefano Zampini   allow = (PetscBool)tr[5];
23465042aa92SStefano Zampini   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
23475042aa92SStefano Zampini 
23485042aa92SStefano Zampini   /* if we are loading from a larger set of processes, allow repeated entries */
23495042aa92SStefano Zampini   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
23505042aa92SStefano Zampini   if (Asize > size) allow = PETSC_TRUE;
23515042aa92SStefano Zampini 
23525042aa92SStefano Zampini   /* set global sizes if not set already */
23535042aa92SStefano Zampini   if (A->rmap->N < 0) A->rmap->N = M;
23545042aa92SStefano Zampini   if (A->cmap->N < 0) A->cmap->N = N;
23555042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->rmap));
23565042aa92SStefano Zampini   PetscCall(PetscLayoutSetUp(A->cmap));
23575042aa92SStefano Zampini   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
23585042aa92SStefano Zampini   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
23595042aa92SStefano Zampini 
23605042aa92SStefano Zampini   /* load l2g maps */
23615042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
23625042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
23635042aa92SStefano Zampini   if (!samel) {
23645042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
23655042aa92SStefano Zampini     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
23665042aa92SStefano Zampini   } else {
23675042aa92SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)rmap));
23685042aa92SStefano Zampini     cmap = rmap;
23695042aa92SStefano Zampini   }
23705042aa92SStefano Zampini 
23715042aa92SStefano Zampini   /* load sizes of local matrices */
23725042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
23735042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
23745042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
23755042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
23765042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
23775042aa92SStefano Zampini   nr = 0;
23785042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
23795042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
23805042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
23815042aa92SStefano Zampini   PetscCall(ISCreate(comm, &is));
23825042aa92SStefano Zampini   PetscCall(ISSetType(is, ISGENERAL));
23835042aa92SStefano Zampini   PetscCall(ISLoad(is, viewer));
23845042aa92SStefano Zampini   PetscCall(ISGetLocalSize(is, &isn));
23855042aa92SStefano Zampini   PetscCall(ISGetIndices(is, &idx));
23865042aa92SStefano Zampini   nc = 0;
23875042aa92SStefano Zampini   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
23885042aa92SStefano Zampini   PetscCall(ISRestoreIndices(is, &idx));
23895042aa92SStefano Zampini   PetscCall(ISDestroy(&is));
23905042aa92SStefano Zampini 
23915042aa92SStefano Zampini   /* now load the unassembled operator */
23925042aa92SStefano Zampini   PetscCall(MatCreate(comm, &dA));
23935042aa92SStefano Zampini   PetscCall(MatSetType(dA, MATMPIAIJ));
23945042aa92SStefano Zampini   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
23955042aa92SStefano Zampini   PetscCall(MatLoad(dA, viewer));
23965042aa92SStefano Zampini   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
23975042aa92SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)lA));
23985042aa92SStefano Zampini   PetscCall(MatDestroy(&dA));
23995042aa92SStefano Zampini 
24005042aa92SStefano Zampini   /* and convert to the desired format */
24015042aa92SStefano Zampini   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
24025042aa92SStefano Zampini   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
24035042aa92SStefano Zampini   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
24045042aa92SStefano Zampini 
24055042aa92SStefano Zampini   /* assemble the MATIS object */
24065042aa92SStefano Zampini   PetscCall(MatISSetAllowRepeated(A, allow));
24075042aa92SStefano Zampini   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
24085042aa92SStefano Zampini   PetscCall(MatISSetLocalMat(A, lA));
24095042aa92SStefano Zampini   PetscCall(MatDestroy(&lA));
24105042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
24115042aa92SStefano Zampini   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
24125042aa92SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
24135042aa92SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
24143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2415b4319ba4SBarry Smith }
2416b4319ba4SBarry Smith 
2417d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2418d71ae5a4SJacob Faibussowitsch {
2419b89f26deSStefano Zampini   Mat_IS            *is = (Mat_IS *)mat->data;
2420b89f26deSStefano Zampini   MPI_Datatype       nodeType;
2421b89f26deSStefano Zampini   const PetscScalar *lv;
2422b89f26deSStefano Zampini   PetscInt           bs;
2423835f2295SStefano Zampini   PetscMPIInt        mbs;
2424b89f26deSStefano Zampini 
2425b89f26deSStefano Zampini   PetscFunctionBegin;
24269566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &bs));
24279566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSize(is->A, bs));
24289566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
242948a46eb9SPierre Jolivet   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2430835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(bs, &mbs));
2431835f2295SStefano Zampini   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
24329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24339566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
24349566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
24359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
2436b89f26deSStefano Zampini   if (values) *values = is->bdiag;
24373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2438b89f26deSStefano Zampini }
2439b89f26deSStefano Zampini 
2440d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2441d71ae5a4SJacob Faibussowitsch {
2442e176bc59SStefano Zampini   Vec             cglobal, rglobal;
24438546b261SStefano Zampini   IS              from;
24448546b261SStefano Zampini   Mat_IS         *is = (Mat_IS *)A->data;
2445b89f26deSStefano Zampini   PetscScalar     sum;
24468546b261SStefano Zampini   const PetscInt *garray;
24478546b261SStefano Zampini   PetscInt        nr, rbs, nc, cbs;
2448e432b41dSStefano Zampini   VecType         rtype;
2449b4319ba4SBarry Smith 
2450b4319ba4SBarry Smith   PetscFunctionBegin;
24519566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
24529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
24539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
24549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
24559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->x));
24569566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->y));
24579566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&is->counter));
24589566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->rctx));
24599566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&is->cctx));
24609566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
24619566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
24629566063dSJacob Faibussowitsch   PetscCall(VecGetRootType_Private(is->y, &rtype));
24639566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->defaultvectype));
24649566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
24659566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
24669566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
24679566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
24689566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
24699566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
24709566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
24719566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&from));
2472e432b41dSStefano Zampini   if (is->rmapping != is->cmapping) {
24739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
24749566063dSJacob Faibussowitsch     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
24759566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
24769566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
24779566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&from));
24788546b261SStefano Zampini   } else {
24799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)is->rctx));
24808546b261SStefano Zampini     is->cctx = is->rctx;
24818546b261SStefano Zampini   }
24829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cglobal));
2483b89f26deSStefano Zampini 
24848546b261SStefano Zampini   /* interface counter vector (local) */
24859566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(is->y, &is->counter));
24869566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
24879566063dSJacob Faibussowitsch   PetscCall(VecSet(is->y, 1.));
24889566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
24899566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
24909566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
24919566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
24929566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
24939566063dSJacob Faibussowitsch   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2494b89f26deSStefano Zampini 
2495b89f26deSStefano Zampini   /* special functions for block-diagonal matrices */
24969566063dSJacob Faibussowitsch   PetscCall(VecSum(rglobal, &sum));
2497b89f26deSStefano Zampini   A->ops->invertblockdiagonal = NULL;
2498e432b41dSStefano Zampini   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
24999566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&rglobal));
2500b0cc1f67SStefano Zampini 
2501b0cc1f67SStefano Zampini   /* setup SF for general purpose shared indices based communications */
25029566063dSJacob Faibussowitsch   PetscCall(MatISSetUpSF_IS(A));
25033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25048546b261SStefano Zampini }
25058546b261SStefano Zampini 
2506d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2507d71ae5a4SJacob Faibussowitsch {
25084f58015eSStefano Zampini   Mat_IS                    *matis = (Mat_IS *)A->data;
2509e432b41dSStefano Zampini   IS                         is;
2510e432b41dSStefano Zampini   ISLocalToGlobalMappingType l2gtype;
2511e432b41dSStefano Zampini   const PetscInt            *idxs;
2512e432b41dSStefano Zampini   PetscHSetI                 ht;
2513e432b41dSStefano Zampini   PetscInt                  *nidxs;
2514e432b41dSStefano Zampini   PetscInt                   i, n, bs, c;
2515e432b41dSStefano Zampini   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2516e432b41dSStefano Zampini 
2517e432b41dSStefano Zampini   PetscFunctionBegin;
25189566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
25199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
25209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
25219566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
25229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n / bs, &nidxs));
2523e432b41dSStefano Zampini   for (i = 0, c = 0; i < n / bs; i++) {
25244f58015eSStefano Zampini     PetscBool missing = PETSC_TRUE;
25259371c9d4SSatish Balay     if (idxs[i] < 0) {
25269371c9d4SSatish Balay       flg[0] = PETSC_TRUE;
25279371c9d4SSatish Balay       continue;
25289371c9d4SSatish Balay     }
25294f58015eSStefano Zampini     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2530e432b41dSStefano Zampini     if (!missing) flg[1] = PETSC_TRUE;
2531e432b41dSStefano Zampini     else nidxs[c++] = idxs[i];
2532e432b41dSStefano Zampini   }
25339566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
2534462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2535e432b41dSStefano Zampini   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2536e432b41dSStefano Zampini     *nmap = NULL;
2537e432b41dSStefano Zampini     *lmap = NULL;
25389566063dSJacob Faibussowitsch     PetscCall(PetscFree(nidxs));
25399566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
25403ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2541e432b41dSStefano Zampini   }
2542e432b41dSStefano Zampini 
25434f58015eSStefano Zampini   /* New l2g map without negative indices (and repeated indices if not allowed) */
25449566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
25459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
25469566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
25479566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
25489566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2549e432b41dSStefano Zampini 
25504f58015eSStefano Zampini   /* New local l2g map for repeated indices if not allowed */
25519566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
25529566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
25539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
25549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
25559566063dSJacob Faibussowitsch   PetscCall(PetscFree(nidxs));
25569566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
25573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2558e432b41dSStefano Zampini }
2559e432b41dSStefano Zampini 
2560d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2561d71ae5a4SJacob Faibussowitsch {
25628546b261SStefano Zampini   Mat_IS                *is            = (Mat_IS *)A->data;
2563e432b41dSStefano Zampini   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2564e432b41dSStefano Zampini   PetscInt               nr, rbs, nc, cbs;
25654f58015eSStefano Zampini   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
25668546b261SStefano Zampini 
25678546b261SStefano Zampini   PetscFunctionBegin;
2568fc989267SStefano Zampini   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2569fc989267SStefano Zampini   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2570e432b41dSStefano Zampini 
25719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
25729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
25739566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
25749566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
25759566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A, &cong));
2576e432b41dSStefano Zampini 
2577fc989267SStefano Zampini   /* If NULL, local space matches global space */
2578fc989267SStefano Zampini   if (!rmapping) {
2579fc989267SStefano Zampini     IS is;
2580fc989267SStefano Zampini 
25819566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
25829566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
258358b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
25849566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2585e432b41dSStefano Zampini     freem[0] = PETSC_TRUE;
2586e432b41dSStefano Zampini     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2587e432b41dSStefano Zampini   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
25889566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2589e432b41dSStefano Zampini     if (rmapping == cmapping) {
25909566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2591e432b41dSStefano Zampini       is->cmapping = is->rmapping;
25929566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2593e432b41dSStefano Zampini       localcmapping = localrmapping;
2594fc989267SStefano Zampini     }
2595fc989267SStefano Zampini   }
2596fc989267SStefano Zampini   if (!cmapping) {
2597fc989267SStefano Zampini     IS is;
2598fc989267SStefano Zampini 
25999566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
26009566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
260158b7e2c1SStefano Zampini     PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
26029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
2603e432b41dSStefano Zampini     freem[1] = PETSC_TRUE;
2604e432b41dSStefano Zampini   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
26059566063dSJacob Faibussowitsch     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2606e432b41dSStefano Zampini   }
2607e432b41dSStefano Zampini   if (!is->rmapping) {
26089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rmapping));
2609e432b41dSStefano Zampini     is->rmapping = rmapping;
2610e432b41dSStefano Zampini   }
2611e432b41dSStefano Zampini   if (!is->cmapping) {
26129566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cmapping));
2613e432b41dSStefano Zampini     is->cmapping = cmapping;
2614fc989267SStefano Zampini   }
2615fc989267SStefano Zampini 
2616fc989267SStefano Zampini   /* Clean up */
26174f58015eSStefano Zampini   is->lnnzstate = 0;
26184f58015eSStefano Zampini   PetscCall(MatDestroy(&is->dA));
26194f58015eSStefano Zampini   PetscCall(MatDestroy(&is->assembledA));
26209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
2621872cf891SStefano Zampini   if (is->csf != is->sf) {
26229566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&is->csf));
26239566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2624f03112d0SStefano Zampini   } else is->csf = NULL;
26259566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&is->sf));
26269566063dSJacob Faibussowitsch   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
26279566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->bdiag));
26283bbff08aSStefano Zampini 
2629fc989267SStefano Zampini   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2630fc989267SStefano Zampini      (DOLFIN passes 2 different objects) */
26319566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
26329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
26339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
26349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2635e432b41dSStefano Zampini   if (is->rmapping != is->cmapping && cong) {
2636e432b41dSStefano Zampini     PetscBool same = PETSC_FALSE;
26376625354bSStefano Zampini     if (nr == nc && cbs == rbs) {
26386625354bSStefano Zampini       const PetscInt *idxs1, *idxs2;
26396625354bSStefano Zampini 
26409566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
26419566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
26429566063dSJacob Faibussowitsch       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
26439566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
26449566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
26456625354bSStefano Zampini     }
2646462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2647e432b41dSStefano Zampini     if (same) {
26489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
26499566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2650e432b41dSStefano Zampini       is->cmapping = is->rmapping;
2651e432b41dSStefano Zampini     }
26526625354bSStefano Zampini   }
26539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
26549566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2655e432b41dSStefano Zampini   /* Pass the user defined maps to the layout */
26569566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
26579566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
26589566063dSJacob Faibussowitsch   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
26599566063dSJacob Faibussowitsch   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
26606625354bSStefano Zampini 
266139b6f3f9SStefano Zampini   if (!is->islocalref) {
26626625354bSStefano Zampini     /* Create the local matrix A */
26639566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
26649566063dSJacob Faibussowitsch     PetscCall(MatSetType(is->A, is->lmattype));
26659566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
26669566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
26679566063dSJacob Faibussowitsch     PetscCall(MatSetOptionsPrefix(is->A, "is_"));
26689566063dSJacob Faibussowitsch     PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
26699566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->rmap));
26709566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(is->A->cmap));
26719566063dSJacob Faibussowitsch     PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
26729566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
26739566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2674fc989267SStefano Zampini     /* setup scatters and local vectors for MatMult */
267539b6f3f9SStefano Zampini     PetscCall(MatISSetUpScatters_Private(A));
267639b6f3f9SStefano Zampini   }
2677fc989267SStefano Zampini   A->preallocated = PETSC_TRUE;
26783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2679fc989267SStefano Zampini }
2680fc989267SStefano Zampini 
2681d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_IS(Mat A)
2682d71ae5a4SJacob Faibussowitsch {
268329f134acSStefano Zampini   Mat_IS                *is = (Mat_IS *)A->data;
2684fc989267SStefano Zampini   ISLocalToGlobalMapping rmap, cmap;
2685fc989267SStefano Zampini 
2686fc989267SStefano Zampini   PetscFunctionBegin;
268729f134acSStefano Zampini   if (!is->sf) {
26889566063dSJacob Faibussowitsch     PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
268929f134acSStefano Zampini     PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
269029f134acSStefano Zampini   }
26913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2692b4319ba4SBarry Smith }
2693b4319ba4SBarry Smith 
2694d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2695d71ae5a4SJacob Faibussowitsch {
26962e74eeadSLisandro Dalcin   Mat_IS  *is = (Mat_IS *)mat->data;
2697f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
26982e74eeadSLisandro Dalcin 
26992e74eeadSLisandro Dalcin   PetscFunctionBegin;
27009566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2701e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
27029566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
27039566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2704e432b41dSStefano Zampini   } else {
27059566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2706e432b41dSStefano Zampini   }
27073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27082e74eeadSLisandro Dalcin }
27092e74eeadSLisandro Dalcin 
2710d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2711d71ae5a4SJacob Faibussowitsch {
271297563a80SStefano Zampini   Mat_IS  *is = (Mat_IS *)mat->data;
2713f26d0771SStefano Zampini   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
271497563a80SStefano Zampini 
271597563a80SStefano Zampini   PetscFunctionBegin;
27169566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2717e432b41dSStefano Zampini   if (m != n || rows != cols || is->cmapping != is->rmapping) {
271884a95373SStefano Zampini     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
27199566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2720e432b41dSStefano Zampini   } else {
272184a95373SStefano Zampini     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2722e432b41dSStefano Zampini   }
27233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
272497563a80SStefano Zampini }
272597563a80SStefano Zampini 
2726d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2727d71ae5a4SJacob Faibussowitsch {
2728b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2729b4319ba4SBarry Smith 
2730b4319ba4SBarry Smith   PetscFunctionBegin;
2731e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
27329566063dSJacob Faibussowitsch     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2733872cf891SStefano Zampini   } else {
27349566063dSJacob Faibussowitsch     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2735872cf891SStefano Zampini   }
27363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2737b4319ba4SBarry Smith }
2738b4319ba4SBarry Smith 
2739d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2740d71ae5a4SJacob Faibussowitsch {
2741f0006bf2SLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
2742f0006bf2SLisandro Dalcin 
2743f0006bf2SLisandro Dalcin   PetscFunctionBegin;
2744e432b41dSStefano Zampini   if (is->A->rmap->mapping || is->A->cmap->mapping) {
27459566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2746b4f971dfSStefano Zampini   } else {
27479566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2748b4f971dfSStefano Zampini   }
27493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2750f0006bf2SLisandro Dalcin }
2751f0006bf2SLisandro Dalcin 
2752d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2753d71ae5a4SJacob Faibussowitsch {
2754f0ae7da4SStefano Zampini   Mat_IS *is = (Mat_IS *)A->data;
2755f0ae7da4SStefano Zampini 
2756f0ae7da4SStefano Zampini   PetscFunctionBegin;
2757f0ae7da4SStefano Zampini   if (!n) {
2758f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_TRUE;
2759f0ae7da4SStefano Zampini   } else {
2760f0ae7da4SStefano Zampini     PetscInt i;
2761f0ae7da4SStefano Zampini     is->pure_neumann = PETSC_FALSE;
2762f0ae7da4SStefano Zampini 
2763f0ae7da4SStefano Zampini     if (columns) {
27649566063dSJacob Faibussowitsch       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2765f0ae7da4SStefano Zampini     } else {
27669566063dSJacob Faibussowitsch       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2767f0ae7da4SStefano Zampini     }
2768f0ae7da4SStefano Zampini     if (diag != 0.) {
2769f0ae7da4SStefano Zampini       const PetscScalar *array;
27709566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(is->counter, &array));
277148a46eb9SPierre Jolivet       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
27729566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(is->counter, &array));
2773f0ae7da4SStefano Zampini     }
27749566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
27759566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2776f0ae7da4SStefano Zampini   }
27773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2778f0ae7da4SStefano Zampini }
2779f0ae7da4SStefano Zampini 
2780d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2781d71ae5a4SJacob Faibussowitsch {
27826e520ac8SStefano Zampini   Mat_IS   *matis = (Mat_IS *)A->data;
27836e520ac8SStefano Zampini   PetscInt  nr, nl, len, i;
27846e520ac8SStefano Zampini   PetscInt *lrows;
27852e74eeadSLisandro Dalcin 
27862e74eeadSLisandro Dalcin   PetscFunctionBegin;
2787cf9c20a2SJed Brown   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2788f0ae7da4SStefano Zampini     PetscBool cong;
278926b0207aSStefano Zampini 
27909566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
279126b0207aSStefano Zampini     cong = (PetscBool)(cong && matis->sf == matis->csf);
279208401ef6SPierre 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");
2793aed4548fSBarry 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");
2794aed4548fSBarry 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");
2795f0ae7da4SStefano Zampini   }
27966e520ac8SStefano Zampini   /* get locally owned rows */
27979566063dSJacob Faibussowitsch   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2798dd8e379bSPierre Jolivet   /* fix right-hand side if needed */
27996e520ac8SStefano Zampini   if (x && b) {
28006e520ac8SStefano Zampini     const PetscScalar *xx;
28016e520ac8SStefano Zampini     PetscScalar       *bb;
28026e520ac8SStefano Zampini 
28039566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(x, &xx));
28049566063dSJacob Faibussowitsch     PetscCall(VecGetArray(b, &bb));
28056e520ac8SStefano Zampini     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
28069566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(x, &xx));
28079566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(b, &bb));
28082e74eeadSLisandro Dalcin   }
28096e520ac8SStefano Zampini   /* get rows associated to the local matrices */
28109566063dSJacob Faibussowitsch   PetscCall(MatGetSize(matis->A, &nl, NULL));
28119566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
28129566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
28136e520ac8SStefano Zampini   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
28149566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
28159566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
28169566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
28179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nl, &lrows));
28189371c9d4SSatish Balay   for (i = 0, nr = 0; i < nl; i++)
28199371c9d4SSatish Balay     if (matis->sf_leafdata[i]) lrows[nr++] = i;
28209566063dSJacob Faibussowitsch   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
28219566063dSJacob Faibussowitsch   PetscCall(PetscFree(lrows));
2822d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2823d0dbe9f7SStefano Zampini   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
28243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28252e74eeadSLisandro Dalcin }
28262e74eeadSLisandro Dalcin 
2827d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2828d71ae5a4SJacob Faibussowitsch {
2829b4319ba4SBarry Smith   PetscFunctionBegin;
28309566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
28313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2832f0ae7da4SStefano Zampini }
28332205254eSKarl Rupp 
2834d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2835d71ae5a4SJacob Faibussowitsch {
2836f0ae7da4SStefano Zampini   PetscFunctionBegin;
28379566063dSJacob Faibussowitsch   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
28383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2839b4319ba4SBarry Smith }
2840b4319ba4SBarry Smith 
2841d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2842d71ae5a4SJacob Faibussowitsch {
2843b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)A->data;
2844b4319ba4SBarry Smith 
2845b4319ba4SBarry Smith   PetscFunctionBegin;
28469566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(is->A, type));
28473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2848b4319ba4SBarry Smith }
2849b4319ba4SBarry Smith 
2850d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2851d71ae5a4SJacob Faibussowitsch {
2852b4319ba4SBarry Smith   Mat_IS   *is = (Mat_IS *)A->data;
2853d0dbe9f7SStefano Zampini   PetscBool lnnz;
2854b4319ba4SBarry Smith 
2855b4319ba4SBarry Smith   PetscFunctionBegin;
28569566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(is->A, type));
2857872cf891SStefano Zampini   /* fix for local empty rows/cols */
2858872cf891SStefano Zampini   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2859872cf891SStefano Zampini     Mat                    newlA;
2860f03112d0SStefano Zampini     ISLocalToGlobalMapping rl2g, cl2g;
2861f03112d0SStefano Zampini     IS                     nzr, nzc;
2862f03112d0SStefano Zampini     PetscInt               nr, nc, nnzr, nnzc;
2863f03112d0SStefano Zampini     PetscBool              lnewl2g, newl2g;
2864872cf891SStefano Zampini 
28659566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &nr, &nc));
28669566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
286748a46eb9SPierre Jolivet     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
28689566063dSJacob Faibussowitsch     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
286948a46eb9SPierre Jolivet     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
28709566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzr, &nnzr));
28719566063dSJacob Faibussowitsch     PetscCall(ISGetSize(nzc, &nnzc));
2872e432b41dSStefano Zampini     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2873f03112d0SStefano Zampini       lnewl2g = PETSC_TRUE;
2874462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2875f03112d0SStefano Zampini 
2876872cf891SStefano Zampini       /* extract valid submatrix */
28779566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2878f03112d0SStefano Zampini     } else { /* local matrix fully populated */
2879f03112d0SStefano Zampini       lnewl2g = PETSC_FALSE;
2880462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
28819566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is->A));
2882f03112d0SStefano Zampini       newlA = is->A;
2883f03112d0SStefano Zampini     }
2884e432b41dSStefano Zampini 
2885f03112d0SStefano Zampini     /* attach new global l2g map if needed */
2886f03112d0SStefano Zampini     if (newl2g) {
2887e432b41dSStefano Zampini       IS              zr, zc;
2888e432b41dSStefano Zampini       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2889e432b41dSStefano Zampini       PetscInt       *nidxs, i;
2890f03112d0SStefano Zampini 
28919566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzr, 0, nr, &zr));
28929566063dSJacob Faibussowitsch       PetscCall(ISComplement(nzc, 0, nc, &zc));
28939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
28949566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
28959566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
28969566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zr, &zridxs));
28979566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(zc, &zcidxs));
28989566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zr, &nnzr));
28999566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(zc, &nnzc));
2900e432b41dSStefano Zampini 
29019566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2902e432b41dSStefano Zampini       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
29039566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
29049566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2905e432b41dSStefano Zampini       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
29069566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2907e432b41dSStefano Zampini 
29089566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zr, &zridxs));
29099566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(zc, &zcidxs));
29109566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
29119566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
29129566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzr));
29139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&nzc));
29149566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zr));
29159566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&zc));
29169566063dSJacob Faibussowitsch       PetscCall(PetscFree(nidxs));
29179566063dSJacob Faibussowitsch       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
29189566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
29199566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2920f03112d0SStefano Zampini     }
29219566063dSJacob Faibussowitsch     PetscCall(MatISSetLocalMat(A, newlA));
29229566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&newlA));
29239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzr));
29249566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&nzc));
2925872cf891SStefano Zampini     is->locempty = PETSC_FALSE;
2926f03112d0SStefano Zampini   }
2927d0dbe9f7SStefano Zampini   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2928d0dbe9f7SStefano Zampini   is->lnnzstate = is->A->nonzerostate;
2929462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
29304f58015eSStefano Zampini   if (!lnnz) A->nonzerostate++;
29313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2932b4319ba4SBarry Smith }
2933b4319ba4SBarry Smith 
2934d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
2935d71ae5a4SJacob Faibussowitsch {
2936b4319ba4SBarry Smith   Mat_IS *is = (Mat_IS *)mat->data;
2937b4319ba4SBarry Smith 
2938b4319ba4SBarry Smith   PetscFunctionBegin;
2939b4319ba4SBarry Smith   *local = is->A;
29403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2941b4319ba4SBarry Smith }
2942b4319ba4SBarry Smith 
2943d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
2944d71ae5a4SJacob Faibussowitsch {
29453b3b1effSJed Brown   PetscFunctionBegin;
29463b3b1effSJed Brown   *local = NULL;
29473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29483b3b1effSJed Brown }
29493b3b1effSJed Brown 
2950b4319ba4SBarry Smith /*@
295111a5261eSBarry Smith   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2952b4319ba4SBarry Smith 
29534f58015eSStefano Zampini   Not Collective.
29544f58015eSStefano Zampini 
2955b4319ba4SBarry Smith   Input Parameter:
2956b4319ba4SBarry Smith . mat - the matrix
2957b4319ba4SBarry Smith 
2958b4319ba4SBarry Smith   Output Parameter:
2959eb82efa4SStefano Zampini . local - the local matrix
2960b4319ba4SBarry Smith 
29614f58015eSStefano Zampini   Level: intermediate
2962b4319ba4SBarry Smith 
2963b4319ba4SBarry Smith   Notes:
2964b4319ba4SBarry Smith   This can be called if you have precomputed the nonzero structure of the
2965b4319ba4SBarry Smith   matrix and want to provide it to the inner matrix object to improve the performance
296611a5261eSBarry Smith   of the `MatSetValues()` operation.
2967b4319ba4SBarry Smith 
296811a5261eSBarry Smith   Call `MatISRestoreLocalMat()` when finished with the local matrix.
296996a6f129SJed Brown 
29701cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
2971b4319ba4SBarry Smith @*/
2972d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
2973d71ae5a4SJacob Faibussowitsch {
2974b4319ba4SBarry Smith   PetscFunctionBegin;
29750700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
29764f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2977cac4c232SBarry Smith   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
29783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2979b4319ba4SBarry Smith }
2980b4319ba4SBarry Smith 
29813b3b1effSJed Brown /*@
298211a5261eSBarry Smith   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
29833b3b1effSJed Brown 
29844f58015eSStefano Zampini   Not Collective.
29854f58015eSStefano Zampini 
29862ef1f0ffSBarry Smith   Input Parameters:
29872ef1f0ffSBarry Smith + mat   - the matrix
29882ef1f0ffSBarry Smith - local - the local matrix
29893b3b1effSJed Brown 
29904f58015eSStefano Zampini   Level: intermediate
29913b3b1effSJed Brown 
29921cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
29933b3b1effSJed Brown @*/
2994d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
2995d71ae5a4SJacob Faibussowitsch {
29963b3b1effSJed Brown   PetscFunctionBegin;
29973b3b1effSJed Brown   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
29984f572ea9SToby Isaac   PetscAssertPointer(local, 2);
2999cac4c232SBarry Smith   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
30003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30013b3b1effSJed Brown }
30023b3b1effSJed Brown 
3003d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3004d71ae5a4SJacob Faibussowitsch {
30058546b261SStefano Zampini   Mat_IS *is = (Mat_IS *)mat->data;
30068546b261SStefano Zampini 
30078546b261SStefano Zampini   PetscFunctionBegin;
30081baa6e33SBarry Smith   if (is->A) PetscCall(MatSetType(is->A, mtype));
30099566063dSJacob Faibussowitsch   PetscCall(PetscFree(is->lmattype));
30109566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
30113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30128546b261SStefano Zampini }
30138546b261SStefano Zampini 
30145d83a8b1SBarry Smith /*@
301511a5261eSBarry Smith   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
30168546b261SStefano Zampini 
30174f58015eSStefano Zampini   Logically Collective.
30184f58015eSStefano Zampini 
3019d8d19677SJose E. Roman   Input Parameters:
3020a2b725a8SWilliam Gropp + mat   - the matrix
3021a2b725a8SWilliam Gropp - mtype - the local matrix type
30228546b261SStefano Zampini 
30234f58015eSStefano Zampini   Level: intermediate
30248546b261SStefano Zampini 
30251cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
30268546b261SStefano Zampini @*/
3027d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3028d71ae5a4SJacob Faibussowitsch {
30298546b261SStefano Zampini   PetscFunctionBegin;
30308546b261SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3031cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
30323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30338546b261SStefano Zampini }
30348546b261SStefano Zampini 
3035d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3036d71ae5a4SJacob Faibussowitsch {
30373b03a366Sstefano_zampini   Mat_IS   *is = (Mat_IS *)mat->data;
30383b03a366Sstefano_zampini   PetscInt  nrows, ncols, orows, ocols;
30398546b261SStefano Zampini   MatType   mtype, otype;
30408546b261SStefano Zampini   PetscBool sametype = PETSC_TRUE;
30413b03a366Sstefano_zampini 
30423b03a366Sstefano_zampini   PetscFunctionBegin;
3043e432b41dSStefano Zampini   if (is->A && !is->islocalref) {
30449566063dSJacob Faibussowitsch     PetscCall(MatGetSize(is->A, &orows, &ocols));
30459566063dSJacob Faibussowitsch     PetscCall(MatGetSize(local, &nrows, &ncols));
30465042aa92SStefano 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);
30479566063dSJacob Faibussowitsch     PetscCall(MatGetType(local, &mtype));
30489566063dSJacob Faibussowitsch     PetscCall(MatGetType(is->A, &otype));
30499566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mtype, otype, &sametype));
30504e4c7dbeSStefano Zampini   }
30519566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)local));
30529566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&is->A));
30533b03a366Sstefano_zampini   is->A = local;
30549566063dSJacob Faibussowitsch   PetscCall(MatGetType(is->A, &mtype));
30559566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMatType(mat, mtype));
305648a46eb9SPierre Jolivet   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
30574f58015eSStefano Zampini   is->lnnzstate = 0;
30583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30593b03a366Sstefano_zampini }
30603b03a366Sstefano_zampini 
30613b03a366Sstefano_zampini /*@
306211a5261eSBarry Smith   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
30633b03a366Sstefano_zampini 
30644f58015eSStefano Zampini   Not Collective
30658546b261SStefano Zampini 
3066d8d19677SJose E. Roman   Input Parameters:
3067a2b725a8SWilliam Gropp + mat   - the matrix
3068a2b725a8SWilliam Gropp - local - the local matrix
30693b03a366Sstefano_zampini 
30704f58015eSStefano Zampini   Level: intermediate
307111a5261eSBarry Smith 
30721cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
30733b03a366Sstefano_zampini @*/
3074d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3075d71ae5a4SJacob Faibussowitsch {
30763b03a366Sstefano_zampini   PetscFunctionBegin;
30773b03a366Sstefano_zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3078b7ce53b6SStefano Zampini   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3079cac4c232SBarry Smith   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
30803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30813b03a366Sstefano_zampini }
30823b03a366Sstefano_zampini 
3083d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_IS(Mat A)
3084d71ae5a4SJacob Faibussowitsch {
30856726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
30866726f965SBarry Smith 
30876726f965SBarry Smith   PetscFunctionBegin;
30889566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(a->A));
30893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30906726f965SBarry Smith }
30916726f965SBarry Smith 
3092d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3093d71ae5a4SJacob Faibussowitsch {
30942e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
30952e74eeadSLisandro Dalcin 
30962e74eeadSLisandro Dalcin   PetscFunctionBegin;
30979566063dSJacob Faibussowitsch   PetscCall(MatScale(is->A, a));
30983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30992e74eeadSLisandro Dalcin }
31002e74eeadSLisandro Dalcin 
3101d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3102d71ae5a4SJacob Faibussowitsch {
31032e74eeadSLisandro Dalcin   Mat_IS *is = (Mat_IS *)A->data;
31042e74eeadSLisandro Dalcin 
31052e74eeadSLisandro Dalcin   PetscFunctionBegin;
31062e74eeadSLisandro Dalcin   /* get diagonal of the local matrix */
31079566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(is->A, is->y));
31082e74eeadSLisandro Dalcin 
31092e74eeadSLisandro Dalcin   /* scatter diagonal back into global vector */
31109566063dSJacob Faibussowitsch   PetscCall(VecSet(v, 0));
31119566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
31129566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
31133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31142e74eeadSLisandro Dalcin }
31152e74eeadSLisandro Dalcin 
3116d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3117d71ae5a4SJacob Faibussowitsch {
31186726f965SBarry Smith   Mat_IS *a = (Mat_IS *)A->data;
31196726f965SBarry Smith 
31206726f965SBarry Smith   PetscFunctionBegin;
31219566063dSJacob Faibussowitsch   PetscCall(MatSetOption(a->A, op, flg));
31223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31236726f965SBarry Smith }
31246726f965SBarry Smith 
3125d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3126d71ae5a4SJacob Faibussowitsch {
3127f26d0771SStefano Zampini   Mat_IS *y = (Mat_IS *)Y->data;
3128f26d0771SStefano Zampini   Mat_IS *x;
3129f26d0771SStefano Zampini 
3130f26d0771SStefano Zampini   PetscFunctionBegin;
313176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
313276bd3646SJed Brown     PetscBool ismatis;
31339566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
313428b400f6SJacob Faibussowitsch     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
313576bd3646SJed Brown   }
3136f26d0771SStefano Zampini   x = (Mat_IS *)X->data;
31379566063dSJacob Faibussowitsch   PetscCall(MatAXPY(y->A, a, x->A, str));
31383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3139f26d0771SStefano Zampini }
3140f26d0771SStefano Zampini 
3141d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3142d71ae5a4SJacob Faibussowitsch {
3143f26d0771SStefano Zampini   Mat                    lA;
3144f4f49eeaSPierre Jolivet   Mat_IS                *matis = (Mat_IS *)A->data;
3145f26d0771SStefano Zampini   ISLocalToGlobalMapping rl2g, cl2g;
3146f26d0771SStefano Zampini   IS                     is;
3147f26d0771SStefano Zampini   const PetscInt        *rg, *rl;
3148f26d0771SStefano Zampini   PetscInt               nrg;
3149f26d0771SStefano Zampini   PetscInt               N, M, nrl, i, *idxs;
3150f26d0771SStefano Zampini 
3151f26d0771SStefano Zampini   PetscFunctionBegin;
31529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
31539566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(row, &nrl));
31549566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(row, &rl));
31559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
315676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
3157e87b5d96SPierre 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);
315876bd3646SJed Brown   }
31599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nrg, &idxs));
3160f26d0771SStefano Zampini   /* map from [0,nrl) to row */
3161f26d0771SStefano Zampini   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3162f26d0771SStefano Zampini   for (i = nrl; i < nrg; i++) idxs[i] = -1;
31639566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(row, &rl));
31649566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
31659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
31669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
31679566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3168f26d0771SStefano Zampini   /* compute new l2g map for columns */
3169e432b41dSStefano Zampini   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3170f26d0771SStefano Zampini     const PetscInt *cg, *cl;
3171f26d0771SStefano Zampini     PetscInt        ncg;
3172f26d0771SStefano Zampini     PetscInt        ncl;
3173f26d0771SStefano Zampini 
31749566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
31759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(col, &ncl));
31769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(col, &cl));
31779566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
317876bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
3179e87b5d96SPierre 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);
318076bd3646SJed Brown     }
31819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncg, &idxs));
3182f26d0771SStefano Zampini     /* map from [0,ncl) to col */
3183f26d0771SStefano Zampini     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3184f26d0771SStefano Zampini     for (i = ncl; i < ncg; i++) idxs[i] = -1;
31859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(col, &cl));
31869566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
31879566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
31889566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
31899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is));
3190f26d0771SStefano Zampini   } else {
31919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)rl2g));
3192f26d0771SStefano Zampini     cl2g = rl2g;
3193f26d0771SStefano Zampini   }
3194f26d0771SStefano Zampini   /* create the MATIS submatrix */
31959566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &M, &N));
31969566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
31979566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
31989566063dSJacob Faibussowitsch   PetscCall(MatSetType(*submat, MATIS));
3199b0aa3428SStefano Zampini   matis             = (Mat_IS *)((*submat)->data);
3200f26d0771SStefano Zampini   matis->islocalref = PETSC_TRUE;
32019566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
32029566063dSJacob Faibussowitsch   PetscCall(MatISGetLocalMat(A, &lA));
32039566063dSJacob Faibussowitsch   PetscCall(MatISSetLocalMat(*submat, lA));
32049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
32059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3206e432b41dSStefano Zampini 
3207f26d0771SStefano Zampini   /* remove unsupported ops */
32089566063dSJacob Faibussowitsch   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3209f26d0771SStefano Zampini   (*submat)->ops->destroy               = MatDestroy_IS;
3210f26d0771SStefano Zampini   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3211f26d0771SStefano Zampini   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
321239b6f3f9SStefano Zampini   (*submat)->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_IS;
32133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3214f26d0771SStefano Zampini }
3215f26d0771SStefano Zampini 
3216ce78bad3SBarry Smith static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject)
3217d71ae5a4SJacob Faibussowitsch {
3218872cf891SStefano Zampini   Mat_IS   *a = (Mat_IS *)A->data;
32198546b261SStefano Zampini   char      type[256];
32208546b261SStefano Zampini   PetscBool flg;
3221872cf891SStefano Zampini 
3222872cf891SStefano Zampini   PetscFunctionBegin;
3223d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
32244f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
32254f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
32264f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
32274f58015eSStefano Zampini   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
32284f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
32294f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
32304f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
32314f58015eSStefano Zampini   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
32324f58015eSStefano Zampini   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
32331baa6e33SBarry Smith   if (flg) PetscCall(MatISSetLocalMatType(A, type));
32341baa6e33SBarry Smith   if (a->A) PetscCall(MatSetFromOptions(a->A));
3235d0609cedSBarry Smith   PetscOptionsHeadEnd();
32363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3237872cf891SStefano Zampini }
3238872cf891SStefano Zampini 
3239284134d9SBarry Smith /*@
32404f58015eSStefano Zampini   MatCreateIS - Creates a "process" unassembled matrix.
32414f58015eSStefano Zampini 
32424f58015eSStefano Zampini   Collective.
3243284134d9SBarry Smith 
3244284134d9SBarry Smith   Input Parameters:
3245284134d9SBarry Smith + comm - MPI communicator that will share the matrix
3246e176bc59SStefano Zampini . bs   - block size of the matrix
32472920cce0SJacob Faibussowitsch . m    - local size of left vector used in matrix vector products
32482920cce0SJacob Faibussowitsch . n    - local size of right vector used in matrix vector products
32492920cce0SJacob Faibussowitsch . M    - global size of left vector used in matrix vector products
32502920cce0SJacob Faibussowitsch . N    - global size of right vector used in matrix vector products
3251e176bc59SStefano Zampini . rmap - local to global map for rows
3252e176bc59SStefano Zampini - cmap - local to global map for cols
3253284134d9SBarry Smith 
3254284134d9SBarry Smith   Output Parameter:
3255284134d9SBarry Smith . A - the resulting matrix
3256284134d9SBarry Smith 
32574f58015eSStefano Zampini   Level: intermediate
32588e6c10adSSatish Balay 
325995452b02SPatrick Sanan   Notes:
32602ef1f0ffSBarry 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
32614f58015eSStefano Zampini   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
326211a5261eSBarry Smith 
32632ef1f0ffSBarry Smith   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3264284134d9SBarry Smith 
32651cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3266284134d9SBarry Smith @*/
3267d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3268d71ae5a4SJacob Faibussowitsch {
3269284134d9SBarry Smith   PetscFunctionBegin;
32709566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
32719566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
327248a46eb9SPierre Jolivet   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
32739566063dSJacob Faibussowitsch   PetscCall(MatSetType(*A, MATIS));
32749566063dSJacob Faibussowitsch   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
32753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3276284134d9SBarry Smith }
3277284134d9SBarry Smith 
3278d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3279d71ae5a4SJacob Faibussowitsch {
32808b9382cfSStefano Zampini   Mat_IS      *a              = (Mat_IS *)A->data;
3281e26763e4SStefano Zampini   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
32828b9382cfSStefano Zampini 
32838b9382cfSStefano Zampini   PetscFunctionBegin;
32848b9382cfSStefano Zampini   *has = PETSC_FALSE;
32853ba16761SJacob Faibussowitsch   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3286d0dbe9f7SStefano Zampini   *has = PETSC_TRUE;
32879371c9d4SSatish Balay   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
32883ba16761SJacob Faibussowitsch     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
32899566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(a->A, op, has));
32903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32918b9382cfSStefano Zampini }
32928b9382cfSStefano Zampini 
3293d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3294d71ae5a4SJacob Faibussowitsch {
3295e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3296e432b41dSStefano Zampini 
3297e432b41dSStefano Zampini   PetscFunctionBegin;
32989566063dSJacob Faibussowitsch   PetscCall(MatSetValuesCOO(a->A, v, imode));
32999566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
33009566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
33013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3302e432b41dSStefano Zampini }
3303e432b41dSStefano Zampini 
3304d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3305d71ae5a4SJacob Faibussowitsch {
3306e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3307e432b41dSStefano Zampini 
3308e432b41dSStefano Zampini   PetscFunctionBegin;
3309e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3310e432b41dSStefano Zampini   if (a->A->rmap->mapping || a->A->cmap->mapping) {
33119566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3312e432b41dSStefano Zampini   } else {
33139566063dSJacob Faibussowitsch     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3314e432b41dSStefano Zampini   }
33159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3316e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
33173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3318e432b41dSStefano Zampini }
3319e432b41dSStefano Zampini 
3320d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3321d71ae5a4SJacob Faibussowitsch {
3322e432b41dSStefano Zampini   Mat_IS  *a = (Mat_IS *)A->data;
3323835f2295SStefano Zampini   PetscInt ncoo_i;
3324e432b41dSStefano Zampini 
3325e432b41dSStefano Zampini   PetscFunctionBegin;
3326e432b41dSStefano Zampini   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3327835f2295SStefano Zampini   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3328835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3329835f2295SStefano Zampini   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3330e8729f6fSJunchao Zhang   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
33319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3332e432b41dSStefano Zampini   A->preallocated = PETSC_TRUE;
33333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3334e432b41dSStefano Zampini }
3335e432b41dSStefano Zampini 
3336d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3337d71ae5a4SJacob Faibussowitsch {
3338d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
33391690c2aeSBarry Smith   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
33401690c2aeSBarry Smith   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3341d0dbe9f7SStefano Zampini 
3342d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3343d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3344d0dbe9f7SStefano Zampini   Annzstate = A->nonzerostate;
3345d0dbe9f7SStefano Zampini   if (a->assembledA) {
3346d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3347d0dbe9f7SStefano Zampini     aAnnzstate = a->assembledA->nonzerostate;
3348d0dbe9f7SStefano Zampini   }
3349d0dbe9f7SStefano Zampini   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3350d0dbe9f7SStefano Zampini   if (Astate != aAstate || !a->assembledA) {
3351d0dbe9f7SStefano Zampini     MatType     aAtype;
3352d0dbe9f7SStefano Zampini     PetscMPIInt size;
3353d0dbe9f7SStefano Zampini     PetscInt    rbs, cbs, bs;
3354d0dbe9f7SStefano Zampini 
3355d0dbe9f7SStefano Zampini     /* the assembled form is used as temporary storage for parallel operations
3356d0dbe9f7SStefano Zampini        like createsubmatrices and the like, do not waste device memory */
3357d0dbe9f7SStefano Zampini     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3358d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3359d0dbe9f7SStefano Zampini     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3360d0dbe9f7SStefano Zampini     bs = rbs == cbs ? rbs : 1;
3361d0dbe9f7SStefano Zampini     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3362d0dbe9f7SStefano Zampini     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3363d0dbe9f7SStefano Zampini     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3364d0dbe9f7SStefano Zampini 
3365d0dbe9f7SStefano Zampini     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3366d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3367d0dbe9f7SStefano Zampini     a->assembledA->nonzerostate = Annzstate;
3368d0dbe9f7SStefano Zampini   }
3369d0dbe9f7SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3370d0dbe9f7SStefano Zampini   *tA = a->assembledA;
3371d0dbe9f7SStefano Zampini   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
33723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3373d0dbe9f7SStefano Zampini }
3374d0dbe9f7SStefano Zampini 
3375d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3376d71ae5a4SJacob Faibussowitsch {
3377d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3378d0dbe9f7SStefano Zampini   PetscCall(MatDestroy(tA));
3379d0dbe9f7SStefano Zampini   *tA = NULL;
33803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3381d0dbe9f7SStefano Zampini }
3382d0dbe9f7SStefano Zampini 
3383d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3384d71ae5a4SJacob Faibussowitsch {
3385d0dbe9f7SStefano Zampini   Mat_IS          *a = (Mat_IS *)A->data;
33861690c2aeSBarry Smith   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3387d0dbe9f7SStefano Zampini 
3388d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3389d0dbe9f7SStefano Zampini   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3390d0dbe9f7SStefano Zampini   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3391d0dbe9f7SStefano Zampini   if (Astate != dAstate) {
3392d0dbe9f7SStefano Zampini     Mat     tA;
3393d0dbe9f7SStefano Zampini     MatType ltype;
3394d0dbe9f7SStefano Zampini 
3395d0dbe9f7SStefano Zampini     PetscCall(MatDestroy(&a->dA));
3396d0dbe9f7SStefano Zampini     PetscCall(MatISGetAssembled_Private(A, &tA));
3397d0dbe9f7SStefano Zampini     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3398d0dbe9f7SStefano Zampini     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3399d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A, &ltype));
3400d0dbe9f7SStefano Zampini     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3401d0dbe9f7SStefano Zampini     PetscCall(PetscObjectReference((PetscObject)a->dA));
3402d0dbe9f7SStefano Zampini     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3403d0dbe9f7SStefano Zampini     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3404d0dbe9f7SStefano Zampini   }
3405d0dbe9f7SStefano Zampini   *dA = a->dA;
34063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3407d0dbe9f7SStefano Zampini }
3408d0dbe9f7SStefano Zampini 
3409d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3410d71ae5a4SJacob Faibussowitsch {
3411d0dbe9f7SStefano Zampini   Mat tA;
3412d0dbe9f7SStefano Zampini 
3413d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3414d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3415d0dbe9f7SStefano Zampini   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3416d0dbe9f7SStefano Zampini   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3417d0dbe9f7SStefano Zampini #if 0
3418d0dbe9f7SStefano Zampini   {
3419d0dbe9f7SStefano Zampini     Mat_IS    *a = (Mat_IS*)A->data;
3420d0dbe9f7SStefano Zampini     MatType   ltype;
3421d0dbe9f7SStefano Zampini     VecType   vtype;
3422d0dbe9f7SStefano Zampini     char      *flg;
3423d0dbe9f7SStefano Zampini 
3424d0dbe9f7SStefano Zampini     PetscCall(MatGetType(a->A,&ltype));
3425d0dbe9f7SStefano Zampini     PetscCall(MatGetVecType(a->A,&vtype));
3426d0dbe9f7SStefano Zampini     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3427d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3428d0dbe9f7SStefano Zampini     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3429d0dbe9f7SStefano Zampini     if (flg) {
3430d0dbe9f7SStefano Zampini       for (PetscInt i = 0; i < n; i++) {
3431d0dbe9f7SStefano Zampini         Mat sA = (*submat)[i];
3432d0dbe9f7SStefano Zampini 
3433d0dbe9f7SStefano Zampini         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3434d0dbe9f7SStefano Zampini         (*submat)[i] = sA;
3435d0dbe9f7SStefano Zampini       }
3436d0dbe9f7SStefano Zampini     }
3437d0dbe9f7SStefano Zampini   }
3438d0dbe9f7SStefano Zampini #endif
3439d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
34403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3441d0dbe9f7SStefano Zampini }
3442d0dbe9f7SStefano Zampini 
3443d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3444d71ae5a4SJacob Faibussowitsch {
3445d0dbe9f7SStefano Zampini   Mat tA;
3446d0dbe9f7SStefano Zampini 
3447d0dbe9f7SStefano Zampini   PetscFunctionBegin;
3448d0dbe9f7SStefano Zampini   PetscCall(MatISGetAssembled_Private(A, &tA));
3449d0dbe9f7SStefano Zampini   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3450d0dbe9f7SStefano Zampini   PetscCall(MatISRestoreAssembled_Private(A, &tA));
34513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3452d0dbe9f7SStefano Zampini }
3453d0dbe9f7SStefano Zampini 
3454e432b41dSStefano Zampini /*@
345511a5261eSBarry Smith   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3456e432b41dSStefano Zampini 
3457e432b41dSStefano Zampini   Not Collective
3458e432b41dSStefano Zampini 
3459e432b41dSStefano Zampini   Input Parameter:
3460e432b41dSStefano Zampini . A - the matrix
3461e432b41dSStefano Zampini 
3462e432b41dSStefano Zampini   Output Parameters:
3463e432b41dSStefano Zampini + rmapping - row mapping
3464e432b41dSStefano Zampini - cmapping - column mapping
3465e432b41dSStefano Zampini 
34662ef1f0ffSBarry Smith   Level: advanced
34672ef1f0ffSBarry Smith 
346811a5261eSBarry Smith   Note:
346911a5261eSBarry 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.
3470e432b41dSStefano Zampini 
3471bfe80ac4SPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3472e432b41dSStefano Zampini @*/
3473d71ae5a4SJacob Faibussowitsch PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3474d71ae5a4SJacob Faibussowitsch {
3475e432b41dSStefano Zampini   PetscFunctionBegin;
3476e432b41dSStefano Zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3477e432b41dSStefano Zampini   PetscValidType(A, 1);
34784f572ea9SToby Isaac   if (rmapping) PetscAssertPointer(rmapping, 2);
34794f572ea9SToby Isaac   if (cmapping) PetscAssertPointer(cmapping, 3);
3480cac4c232SBarry Smith   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
34813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3482e432b41dSStefano Zampini }
3483e432b41dSStefano Zampini 
3484d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3485d71ae5a4SJacob Faibussowitsch {
3486e432b41dSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3487e432b41dSStefano Zampini 
3488e432b41dSStefano Zampini   PetscFunctionBegin;
3489e432b41dSStefano Zampini   if (r) *r = a->rmapping;
3490e432b41dSStefano Zampini   if (c) *c = a->cmapping;
34913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3492e432b41dSStefano Zampini }
3493e432b41dSStefano Zampini 
3494a50ef18cSStefano Zampini static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3495a50ef18cSStefano Zampini {
3496a50ef18cSStefano Zampini   Mat_IS *a = (Mat_IS *)A->data;
3497a50ef18cSStefano Zampini 
3498a50ef18cSStefano Zampini   PetscFunctionBegin;
3499a50ef18cSStefano Zampini   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3500a50ef18cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
3501a50ef18cSStefano Zampini }
3502a50ef18cSStefano Zampini 
3503b4319ba4SBarry Smith /*MC
35044f58015eSStefano Zampini   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
35054f58015eSStefano Zampini   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3506b4319ba4SBarry Smith 
3507b4319ba4SBarry Smith   Options Database Keys:
35084f58015eSStefano Zampini + -mat_type is           - Set the matrix type to `MATIS`.
35094f58015eSStefano Zampini . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
35104f58015eSStefano Zampini . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
35114f58015eSStefano Zampini - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
35122ef1f0ffSBarry Smith 
35134f58015eSStefano Zampini   Level: intermediate
3514b4319ba4SBarry Smith 
351595452b02SPatrick Sanan   Notes:
35162ef1f0ffSBarry Smith   Options prefix for the inner matrix are given by `-is_mat_xxx`
3517b4319ba4SBarry Smith 
351811a5261eSBarry Smith   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3519b4319ba4SBarry Smith 
3520b4319ba4SBarry Smith   You can do matrix preallocation on the local matrix after you obtain it with
35214f58015eSStefano Zampini   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3522b4319ba4SBarry Smith 
35231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3524b4319ba4SBarry Smith M*/
3525d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3526d71ae5a4SJacob Faibussowitsch {
3527e432b41dSStefano Zampini   Mat_IS *a;
3528b4319ba4SBarry Smith 
3529b4319ba4SBarry Smith   PetscFunctionBegin;
35304dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&a));
35319566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3532e432b41dSStefano Zampini   A->data = (void *)a;
3533b4319ba4SBarry Smith 
3534e176bc59SStefano Zampini   /* matrix ops */
35359566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3536b4319ba4SBarry Smith   A->ops->mult                    = MatMult_IS;
35372e74eeadSLisandro Dalcin   A->ops->multadd                 = MatMultAdd_IS;
35382e74eeadSLisandro Dalcin   A->ops->multtranspose           = MatMultTranspose_IS;
35392e74eeadSLisandro Dalcin   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3540b4319ba4SBarry Smith   A->ops->destroy                 = MatDestroy_IS;
3541b4319ba4SBarry Smith   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
35422e74eeadSLisandro Dalcin   A->ops->setvalues               = MatSetValues_IS;
354398921651SStefano Zampini   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3544b4319ba4SBarry Smith   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3545f0006bf2SLisandro Dalcin   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
35462e74eeadSLisandro Dalcin   A->ops->zerorows                = MatZeroRows_IS;
3547f0ae7da4SStefano Zampini   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3548b4319ba4SBarry Smith   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3549b4319ba4SBarry Smith   A->ops->assemblyend             = MatAssemblyEnd_IS;
3550b4319ba4SBarry Smith   A->ops->view                    = MatView_IS;
35515042aa92SStefano Zampini   A->ops->load                    = MatLoad_IS;
35526726f965SBarry Smith   A->ops->zeroentries             = MatZeroEntries_IS;
35532e74eeadSLisandro Dalcin   A->ops->scale                   = MatScale_IS;
35542e74eeadSLisandro Dalcin   A->ops->getdiagonal             = MatGetDiagonal_IS;
35556726f965SBarry Smith   A->ops->setoption               = MatSetOption_IS;
355669796d55SStefano Zampini   A->ops->ishermitian             = MatIsHermitian_IS;
355769796d55SStefano Zampini   A->ops->issymmetric             = MatIsSymmetric_IS;
355845471136SStefano Zampini   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3559ad6194a2SStefano Zampini   A->ops->duplicate               = MatDuplicate_IS;
35606bd84002SStefano Zampini   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
35612b404112SStefano Zampini   A->ops->copy                    = MatCopy_IS;
3562659959c5SStefano Zampini   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
35637dae84e0SHong Zhang   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3564f26d0771SStefano Zampini   A->ops->axpy                    = MatAXPY_IS;
35653fd1c9e7SStefano Zampini   A->ops->diagonalset             = MatDiagonalSet_IS;
35663fd1c9e7SStefano Zampini   A->ops->shift                   = MatShift_IS;
3567d7f69cd0SStefano Zampini   A->ops->transpose               = MatTranspose_IS;
35687fa8f2d3SStefano Zampini   A->ops->getinfo                 = MatGetInfo_IS;
3569ad219c80Sstefano_zampini   A->ops->diagonalscale           = MatDiagonalScale_IS;
3570872cf891SStefano Zampini   A->ops->setfromoptions          = MatSetFromOptions_IS;
3571fc989267SStefano Zampini   A->ops->setup                   = MatSetUp_IS;
35728b9382cfSStefano Zampini   A->ops->hasoperation            = MatHasOperation_IS;
3573d0dbe9f7SStefano Zampini   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3574d0dbe9f7SStefano Zampini   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3575d0dbe9f7SStefano Zampini   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3576a50ef18cSStefano Zampini   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3577b4319ba4SBarry Smith 
3578b7ce53b6SStefano Zampini   /* special MATIS functions */
35799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
35809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
35819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
35829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
35839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
35844f58015eSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
35859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
35869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
35879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
35889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
35899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
35909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
35919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
35929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
35939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
35949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
35959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
35969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
35979566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
35983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3599b4319ba4SBarry Smith }
3600