xref: /petsc/src/mat/impls/is/matis.c (revision ac7f1a8b79ea0e2b8b86ec6656890d6a06746de2)
1 /*
2     Creates a matrix class for using the Neumann-Neumann type preconditioners.
3     This stores the matrices in globally unassembled form. Each processor
4     assembles only its local Neumann problem and the parallel matrix vector
5     product is handled "implicitly".
6 
7     Currently this allows for only one subdomain per processor.
8 */
9 
10 #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/
11 #include <../src/mat/impls/aij/mpi/mpiaij.h>
12 #include <petsc/private/sfimpl.h>
13 #include <petsc/private/vecimpl.h>
14 #include <petsc/private/hashseti.h>
15 
16 #define MATIS_MAX_ENTRIES_INSERTION 2048
17 static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
18 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode);
19 static PetscErrorCode MatISSetUpScatters_Private(Mat);
20 
21 static PetscErrorCode MatISContainerDestroyPtAP_Private(void **ptr)
22 {
23   MatISPtAP ptap = (MatISPtAP)*ptr;
24 
25   PetscFunctionBegin;
26   PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP));
27   PetscCall(ISDestroy(&ptap->cis0));
28   PetscCall(ISDestroy(&ptap->cis1));
29   PetscCall(ISDestroy(&ptap->ris0));
30   PetscCall(ISDestroy(&ptap->ris1));
31   PetscCall(PetscFree(ptap));
32   PetscFunctionReturn(PETSC_SUCCESS);
33 }
34 
35 static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
36 {
37   MatISPtAP      ptap;
38   Mat_IS        *matis = (Mat_IS *)A->data;
39   Mat            lA, lC;
40   MatReuse       reuse;
41   IS             ris[2], cis[2];
42   PetscContainer c;
43   PetscInt       n;
44 
45   PetscFunctionBegin;
46   PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c));
47   PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information");
48   PetscCall(PetscContainerGetPointer(c, (void **)&ptap));
49   ris[0] = ptap->ris0;
50   ris[1] = ptap->ris1;
51   cis[0] = ptap->cis0;
52   cis[1] = ptap->cis1;
53   n      = ptap->ris1 ? 2 : 1;
54   reuse  = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
55   PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP));
56 
57   PetscCall(MatISGetLocalMat(A, &lA));
58   PetscCall(MatISGetLocalMat(C, &lC));
59   if (ptap->ris1) { /* unsymmetric A mapping */
60     Mat lPt;
61 
62     PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt));
63     PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC));
64     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", (PetscObject)lPt));
65     PetscCall(MatDestroy(&lPt));
66   } else {
67     PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC));
68     if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0]));
69   }
70   if (reuse == MAT_INITIAL_MATRIX) {
71     PetscCall(MatISSetLocalMat(C, lC));
72     PetscCall(MatDestroy(&lC));
73   }
74   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
75   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis)
80 {
81   Mat             Po, Pd;
82   IS              zd, zo;
83   const PetscInt *garray;
84   PetscInt       *aux, i, bs;
85   PetscInt        dc, stc, oc, ctd, cto;
86   PetscBool       ismpiaij, ismpibaij, isseqaij, isseqbaij;
87   MPI_Comm        comm;
88 
89   PetscFunctionBegin;
90   PetscValidHeaderSpecific(PT, MAT_CLASSID, 1);
91   PetscAssertPointer(cis, 2);
92   PetscCall(PetscObjectGetComm((PetscObject)PT, &comm));
93   bs = 1;
94   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij));
95   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij));
96   PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij));
97   PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij));
98   if (isseqaij || isseqbaij) {
99     Pd     = PT;
100     Po     = NULL;
101     garray = NULL;
102   } else if (ismpiaij) {
103     PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray));
104   } else if (ismpibaij) {
105     PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray));
106     PetscCall(MatGetBlockSize(PT, &bs));
107   } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)PT)->type_name);
108 
109   /* identify any null columns in Pd or Po */
110   /* We use a tolerance comparison since it may happen that, with geometric multigrid,
111      some of the columns are not really zero, but very close to */
112   zo = zd = NULL;
113   if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo));
114   PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd));
115 
116   PetscCall(MatGetLocalSize(PT, NULL, &dc));
117   PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL));
118   if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc));
119   else oc = 0;
120   PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
121   if (zd) {
122     const PetscInt *idxs;
123     PetscInt        nz;
124 
125     /* this will throw an error if bs is not valid */
126     PetscCall(ISSetBlockSize(zd, bs));
127     PetscCall(ISGetLocalSize(zd, &nz));
128     PetscCall(ISGetIndices(zd, &idxs));
129     ctd = nz / bs;
130     for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs;
131     PetscCall(ISRestoreIndices(zd, &idxs));
132   } else {
133     ctd = dc / bs;
134     for (i = 0; i < ctd; i++) aux[i] = i + stc / bs;
135   }
136   if (zo) {
137     const PetscInt *idxs;
138     PetscInt        nz;
139 
140     /* this will throw an error if bs is not valid */
141     PetscCall(ISSetBlockSize(zo, bs));
142     PetscCall(ISGetLocalSize(zo, &nz));
143     PetscCall(ISGetIndices(zo, &idxs));
144     cto = nz / bs;
145     for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs];
146     PetscCall(ISRestoreIndices(zo, &idxs));
147   } else {
148     cto = oc / bs;
149     for (i = 0; i < cto; i++) aux[i + ctd] = garray[i];
150   }
151   PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis));
152   PetscCall(ISDestroy(&zd));
153   PetscCall(ISDestroy(&zo));
154   PetscFunctionReturn(PETSC_SUCCESS);
155 }
156 
157 static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C)
158 {
159   Mat                    PT, lA;
160   MatISPtAP              ptap;
161   ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g;
162   PetscContainer         c;
163   MatType                lmtype;
164   const PetscInt        *garray;
165   PetscInt               ibs, N, dc;
166   MPI_Comm               comm;
167 
168   PetscFunctionBegin;
169   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
170   PetscCall(MatSetType(C, MATIS));
171   PetscCall(MatISGetLocalMat(A, &lA));
172   PetscCall(MatGetType(lA, &lmtype));
173   PetscCall(MatISSetLocalMatType(C, lmtype));
174   PetscCall(MatGetSize(P, NULL, &N));
175   PetscCall(MatGetLocalSize(P, NULL, &dc));
176   PetscCall(MatSetSizes(C, dc, dc, N, N));
177   /* Not sure about this
178   PetscCall(MatGetBlockSizes(P,NULL,&ibs));
179   PetscCall(MatSetBlockSize(*C,ibs));
180 */
181 
182   PetscCall(PetscNew(&ptap));
183   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
184   PetscCall(PetscContainerSetPointer(c, ptap));
185   PetscCall(PetscContainerSetCtxDestroy(c, MatISContainerDestroyPtAP_Private));
186   PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c));
187   PetscCall(PetscContainerDestroy(&c));
188   ptap->fill = fill;
189 
190   PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g));
191 
192   PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs));
193   PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N));
194   PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray));
195   PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0));
196   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray));
197 
198   PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT));
199   PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0));
200   PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g));
201   PetscCall(MatDestroy(&PT));
202 
203   Crl2g = NULL;
204   if (rl2g != cl2g) { /* unsymmetric A mapping */
205     PetscBool same, lsame = PETSC_FALSE;
206     PetscInt  N1, ibs1;
207 
208     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1));
209     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1));
210     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray));
211     PetscCall(ISCreateBlock(comm, ibs, N1 / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1));
212     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray));
213     if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
214       const PetscInt *i1, *i2;
215 
216       PetscCall(ISBlockGetIndices(ptap->ris0, &i1));
217       PetscCall(ISBlockGetIndices(ptap->ris1, &i2));
218       PetscCall(PetscArraycmp(i1, i2, N, &lsame));
219     }
220     PetscCallMPI(MPIU_Allreduce(&lsame, &same, 1, MPIU_BOOL, MPI_LAND, comm));
221     if (same) {
222       PetscCall(ISDestroy(&ptap->ris1));
223     } else {
224       PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT));
225       PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1));
226       PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g));
227       PetscCall(MatDestroy(&PT));
228     }
229   }
230   /* Not sure about this
231   if (!Crl2g) {
232     PetscCall(MatGetBlockSize(C,&ibs));
233     PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs));
234   }
235 */
236   PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g));
237   PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g));
238   PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g));
239 
240   C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
241   PetscFunctionReturn(PETSC_SUCCESS);
242 }
243 
244 static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
245 {
246   Mat_Product *product = C->product;
247   Mat          A = product->A, P = product->B;
248   PetscReal    fill = product->fill;
249 
250   PetscFunctionBegin;
251   PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C));
252   C->ops->productnumeric = MatProductNumeric_PtAP;
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
257 {
258   PetscFunctionBegin;
259   C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
260   PetscFunctionReturn(PETSC_SUCCESS);
261 }
262 
263 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
264 {
265   Mat_Product *product = C->product;
266 
267   PetscFunctionBegin;
268   if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C));
269   PetscFunctionReturn(PETSC_SUCCESS);
270 }
271 
272 static PetscErrorCode MatISContainerDestroyFields_Private(void **ptr)
273 {
274   MatISLocalFields lf = (MatISLocalFields)*ptr;
275   PetscInt         i;
276 
277   PetscFunctionBegin;
278   for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i]));
279   for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i]));
280   PetscCall(PetscFree2(lf->rf, lf->cf));
281   PetscCall(PetscFree(lf));
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284 
285 static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
286 {
287   Mat B, lB;
288 
289   PetscFunctionBegin;
290   if (reuse != MAT_REUSE_MATRIX) {
291     ISLocalToGlobalMapping rl2g, cl2g;
292     PetscInt               bs;
293     IS                     is;
294 
295     PetscCall(MatGetBlockSize(A, &bs));
296     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is));
297     if (bs > 1) {
298       IS       is2;
299       PetscInt i, *aux;
300 
301       PetscCall(ISGetLocalSize(is, &i));
302       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
303       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
304       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
305       PetscCall(ISDestroy(&is));
306       is = is2;
307     }
308     PetscCall(ISSetIdentity(is));
309     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
310     PetscCall(ISDestroy(&is));
311     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is));
312     if (bs > 1) {
313       IS       is2;
314       PetscInt i, *aux;
315 
316       PetscCall(ISGetLocalSize(is, &i));
317       PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
318       PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2));
319       PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
320       PetscCall(ISDestroy(&is));
321       is = is2;
322     }
323     PetscCall(ISSetIdentity(is));
324     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
325     PetscCall(ISDestroy(&is));
326     PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B));
327     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
328     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
329     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB));
330     if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
331   } else {
332     B = *newmat;
333     PetscCall(PetscObjectReference((PetscObject)A));
334     lB = A;
335   }
336   PetscCall(MatISSetLocalMat(B, lB));
337   PetscCall(MatDestroy(&lB));
338   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
339   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
340   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
341   PetscFunctionReturn(PETSC_SUCCESS);
342 }
343 
344 static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
345 {
346   Mat_IS         *matis = (Mat_IS *)A->data;
347   PetscScalar    *aa;
348   const PetscInt *ii, *jj;
349   PetscInt        i, n, m;
350   PetscInt       *ecount, **eneighs;
351   PetscBool       flg;
352 
353   PetscFunctionBegin;
354   PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
355   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
356   PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
357   PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n);
358   PetscCall(MatSeqAIJGetArray(matis->A, &aa));
359   for (i = 0; i < n; i++) {
360     if (ecount[i] > 1) {
361       PetscInt j;
362 
363       for (j = ii[i]; j < ii[i + 1]; j++) {
364         PetscInt  i2   = jj[j], p, p2;
365         PetscReal scal = 0.0;
366 
367         for (p = 0; p < ecount[i]; p++) {
368           for (p2 = 0; p2 < ecount[i2]; p2++) {
369             if (eneighs[i][p] == eneighs[i2][p2]) {
370               scal += 1.0;
371               break;
372             }
373           }
374         }
375         if (scal) aa[j] /= scal;
376       }
377     }
378   }
379   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs));
380   PetscCall(MatSeqAIJRestoreArray(matis->A, &aa));
381   PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
382   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
383   PetscFunctionReturn(PETSC_SUCCESS);
384 }
385 
386 typedef enum {
387   MAT_IS_DISASSEMBLE_L2G_NATURAL,
388   MAT_IS_DISASSEMBLE_L2G_MAT,
389   MAT_IS_DISASSEMBLE_L2G_ND
390 } MatISDisassemblel2gType;
391 
392 static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
393 {
394   Mat                     Ad, Ao;
395   IS                      is, ndmap, ndsub;
396   MPI_Comm                comm;
397   const PetscInt         *garray, *ndmapi;
398   PetscInt                bs, i, cnt, nl, *ncount, *ndmapc;
399   PetscBool               ismpiaij, ismpibaij;
400   const char *const       MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL};
401   MatISDisassemblel2gType mode                       = MAT_IS_DISASSEMBLE_L2G_NATURAL;
402   MatPartitioning         part;
403   PetscSF                 sf;
404   PetscObject             dm;
405 
406   PetscFunctionBegin;
407   PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat");
408   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));
409   PetscOptionsEnd();
410   if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
411     PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
412     PetscFunctionReturn(PETSC_SUCCESS);
413   }
414   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
415   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
416   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
417   PetscCall(MatGetBlockSize(A, &bs));
418   switch (mode) {
419   case MAT_IS_DISASSEMBLE_L2G_ND:
420     PetscCall(MatPartitioningCreate(comm, &part));
421     PetscCall(MatPartitioningSetAdjacency(part, A));
422     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix));
423     PetscCall(MatPartitioningSetFromOptions(part));
424     PetscCall(MatPartitioningApplyND(part, &ndmap));
425     PetscCall(MatPartitioningDestroy(&part));
426     PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub));
427     PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE));
428     PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1));
429     PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g));
430 
431     /* it may happen that a separator node is not properly shared */
432     PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL));
433     PetscCall(PetscSFCreate(comm, &sf));
434     PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray));
435     PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray));
436     PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray));
437     PetscCall(PetscCalloc1(A->rmap->n, &ndmapc));
438     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
439     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE));
440     PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL));
441     PetscCall(ISGetIndices(ndmap, &ndmapi));
442     for (i = 0, cnt = 0; i < A->rmap->n; i++)
443       if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++;
444 
445     PetscCallMPI(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm));
446     if (i) { /* we detected isolated separator nodes */
447       Mat                    A2, A3;
448       IS                    *workis, is2;
449       PetscScalar           *vals;
450       PetscInt               gcnt = i, *dnz, *onz, j, *lndmapi;
451       ISLocalToGlobalMapping ll2g;
452       PetscBool              flg;
453       const PetscInt        *ii, *jj;
454 
455       /* communicate global id of separators */
456       MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz);
457       for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
458 
459       PetscCall(PetscMalloc1(nl, &lndmapi));
460       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
461 
462       /* compute adjacency of isolated separators node */
463       PetscCall(PetscMalloc1(gcnt, &workis));
464       for (i = 0, cnt = 0; i < A->rmap->n; i++) {
465         if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++]));
466       }
467       for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i]));
468       for (i = 0; i < gcnt; i++) {
469         PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED"));
470         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
471       }
472 
473       /* no communications since all the ISes correspond to locally owned rows */
474       PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1));
475 
476       /* end communicate global id of separators */
477       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE));
478 
479       /* communicate new layers : create a matrix and transpose it */
480       PetscCall(PetscArrayzero(dnz, A->rmap->n));
481       PetscCall(PetscArrayzero(onz, A->rmap->n));
482       for (i = 0, j = 0; i < A->rmap->n; i++) {
483         if (ndmapi[i] < 0 && ndmapc[i] < 2) {
484           const PetscInt *idxs;
485           PetscInt        s;
486 
487           PetscCall(ISGetLocalSize(workis[j], &s));
488           PetscCall(ISGetIndices(workis[j], &idxs));
489           PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz));
490           j++;
491         }
492       }
493       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
494 
495       for (i = 0; i < gcnt; i++) {
496         PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED"));
497         PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators"));
498       }
499 
500       for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]);
501       PetscCall(PetscMalloc1(j, &vals));
502       for (i = 0; i < j; i++) vals[i] = 1.0;
503 
504       PetscCall(MatCreate(comm, &A2));
505       PetscCall(MatSetType(A2, MATMPIAIJ));
506       PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
507       PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz));
508       PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
509       for (i = 0, j = 0; i < A2->rmap->n; i++) {
510         PetscInt        row = i + A2->rmap->rstart, s = dnz[i] + onz[i];
511         const PetscInt *idxs;
512 
513         if (s) {
514           PetscCall(ISGetIndices(workis[j], &idxs));
515           PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES));
516           PetscCall(ISRestoreIndices(workis[j], &idxs));
517           j++;
518         }
519       }
520       PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt);
521       PetscCall(PetscFree(vals));
522       PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
523       PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
524       PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
525 
526       /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
527       for (i = 0, j = 0; i < nl; i++)
528         if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
529       PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is));
530       PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3));
531       PetscCall(ISDestroy(&is));
532       PetscCall(MatDestroy(&A2));
533 
534       /* extend local to global map to include connected isolated separators */
535       PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is));
536       PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map");
537       PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g));
538       PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
539       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
540       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is));
541       PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg));
542       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
543       PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2));
544       PetscCall(ISDestroy(&is));
545       PetscCall(ISLocalToGlobalMappingDestroy(&ll2g));
546 
547       /* add new nodes to the local-to-global map */
548       PetscCall(ISLocalToGlobalMappingDestroy(l2g));
549       PetscCall(ISExpand(ndsub, is2, &is));
550       PetscCall(ISDestroy(&is2));
551       PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
552       PetscCall(ISDestroy(&is));
553 
554       PetscCall(MatDestroy(&A3));
555       PetscCall(PetscFree(lndmapi));
556       MatPreallocateEnd(dnz, onz);
557       for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i]));
558       PetscCall(PetscFree(workis));
559     }
560     PetscCall(ISRestoreIndices(ndmap, &ndmapi));
561     PetscCall(PetscSFDestroy(&sf));
562     PetscCall(PetscFree(ndmapc));
563     PetscCall(ISDestroy(&ndmap));
564     PetscCall(ISDestroy(&ndsub));
565     PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs));
566     PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-mat_is_nd_l2g_view"));
567     break;
568   case MAT_IS_DISASSEMBLE_L2G_NATURAL:
569     PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", &dm));
570     if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */
571       PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL));
572       PetscCall(PetscObjectReference((PetscObject)*l2g));
573       if (*l2g) PetscFunctionReturn(PETSC_SUCCESS);
574     }
575     if (ismpiaij) {
576       PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
577     } else if (ismpibaij) {
578       PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
579     } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
580     if (A->rmap->n) {
581       PetscInt dc, oc, stc, *aux;
582 
583       PetscCall(MatGetLocalSize(Ad, NULL, &dc));
584       PetscCall(MatGetLocalSize(Ao, NULL, &oc));
585       PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
586       PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
587       PetscCall(PetscMalloc1((dc + oc) / bs, &aux));
588       for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs;
589       for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]);
590       PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is));
591     } else {
592       PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is));
593     }
594     PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g));
595     PetscCall(ISDestroy(&is));
596     break;
597   default:
598     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode);
599   }
600   PetscFunctionReturn(PETSC_SUCCESS);
601 }
602 
603 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
604 {
605   Mat                    lA, Ad, Ao, B = NULL;
606   ISLocalToGlobalMapping rl2g, cl2g;
607   IS                     is;
608   MPI_Comm               comm;
609   void                  *ptrs[2];
610   const char            *names[2] = {"_convert_csr_aux", "_convert_csr_data"};
611   const PetscInt        *garray;
612   PetscScalar           *dd, *od, *aa, *data;
613   const PetscInt        *di, *dj, *oi, *oj;
614   const PetscInt        *odi, *odj, *ooi, *ooj;
615   PetscInt              *aux, *ii, *jj;
616   PetscInt               rbs, cbs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum;
617   PetscBool              flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE, cong;
618   PetscMPIInt            size;
619 
620   PetscFunctionBegin;
621   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
622   PetscCallMPI(MPI_Comm_size(comm, &size));
623   if (size == 1) {
624     PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat));
625     PetscFunctionReturn(PETSC_SUCCESS);
626   }
627   PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
628   PetscCall(MatHasCongruentLayouts(A, &cong));
629   if (reuse != MAT_REUSE_MATRIX && cong && rbs == cbs) {
630     PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g));
631     PetscCall(MatCreate(comm, &B));
632     PetscCall(MatSetType(B, MATIS));
633     PetscCall(MatSetSizes(B, A->rmap->n, A->rmap->n, A->rmap->N, A->rmap->N));
634     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g));
635     PetscCall(MatSetBlockSizes(B, rbs, rbs));
636     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
637     if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
638     reuse = MAT_REUSE_MATRIX;
639   }
640   if (reuse == MAT_REUSE_MATRIX) {
641     Mat            *newlA, lA;
642     IS              rows, cols;
643     const PetscInt *ridx, *cidx;
644     PetscInt        nr, nc;
645 
646     if (!B) B = *newmat;
647     PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g));
648     PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx));
649     PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx));
650     PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr));
651     PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc));
652     PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs));
653     PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs));
654     PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows));
655     if (rl2g != cl2g) {
656       PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols));
657     } else {
658       PetscCall(PetscObjectReference((PetscObject)rows));
659       cols = rows;
660     }
661     PetscCall(MatISGetLocalMat(B, &lA));
662     PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA));
663     PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0]));
664     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx));
665     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx));
666     PetscCall(ISDestroy(&rows));
667     PetscCall(ISDestroy(&cols));
668     if (!lA->preallocated) { /* first time */
669       PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA));
670       PetscCall(MatISSetLocalMat(B, lA));
671       PetscCall(PetscObjectDereference((PetscObject)lA));
672     }
673     PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN));
674     PetscCall(MatDestroySubMatrices(1, &newlA));
675     PetscCall(MatISScaleDisassembling_Private(B));
676     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
677     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
678     if (was_inplace) PetscCall(MatHeaderReplace(A, &B));
679     else *newmat = B;
680     PetscFunctionReturn(PETSC_SUCCESS);
681   }
682   /* general case, just compress out the column space */
683   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij));
684   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij));
685   if (ismpiaij) {
686     cbs = 1; /* We cannot guarantee the off-process matrix will respect the column block size */
687     PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray));
688   } else if (ismpibaij) {
689     PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray));
690     PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad));
691     PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao));
692   } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name);
693   PetscCall(MatSeqAIJGetArray(Ad, &dd));
694   PetscCall(MatSeqAIJGetArray(Ao, &od));
695 
696   /* access relevant information from MPIAIJ */
697   PetscCall(MatGetOwnershipRange(A, &str, NULL));
698   PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL));
699   PetscCall(MatGetLocalSize(Ad, &dr, &dc));
700   PetscCall(MatGetLocalSize(Ao, NULL, &oc));
701   PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present");
702 
703   PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg));
704   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
705   PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg));
706   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure");
707   nnz = di[dr] + oi[dr];
708   /* store original pointers to be restored later */
709   odi = di;
710   odj = dj;
711   ooi = oi;
712   ooj = oj;
713 
714   /* generate l2g maps for rows and cols */
715   PetscCall(ISCreateStride(comm, dr / rbs, str / rbs, 1, &is));
716   if (rbs > 1) {
717     IS is2;
718 
719     PetscCall(ISGetLocalSize(is, &i));
720     PetscCall(ISGetIndices(is, (const PetscInt **)&aux));
721     PetscCall(ISCreateBlock(comm, rbs, i, aux, PETSC_COPY_VALUES, &is2));
722     PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux));
723     PetscCall(ISDestroy(&is));
724     is = is2;
725   }
726   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
727   PetscCall(ISDestroy(&is));
728   if (dr) {
729     PetscCall(PetscMalloc1((dc + oc) / cbs, &aux));
730     for (i = 0; i < dc / cbs; i++) aux[i] = i + stc / cbs;
731     for (i = 0; i < oc / cbs; i++) aux[i + dc / cbs] = garray[i];
732     PetscCall(ISCreateBlock(comm, cbs, (dc + oc) / cbs, aux, PETSC_OWN_POINTER, &is));
733     lc = dc + oc;
734   } else {
735     PetscCall(ISCreateBlock(comm, cbs, 0, NULL, PETSC_OWN_POINTER, &is));
736     lc = 0;
737   }
738   PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
739   PetscCall(ISDestroy(&is));
740 
741   /* create MATIS object */
742   PetscCall(MatCreate(comm, &B));
743   PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE));
744   PetscCall(MatSetType(B, MATIS));
745   PetscCall(MatSetBlockSizes(B, rbs, cbs));
746   PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
747   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
748   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
749 
750   /* merge local matrices */
751   PetscCall(PetscMalloc1(nnz + dr + 1, &aux));
752   PetscCall(PetscMalloc1(nnz, &data));
753   ii  = aux;
754   jj  = aux + dr + 1;
755   aa  = data;
756   *ii = *(di++) + *(oi++);
757   for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) {
758     for (; jd < *di; jd++) {
759       *jj++ = *dj++;
760       *aa++ = *dd++;
761     }
762     for (; jo < *oi; jo++) {
763       *jj++ = *oj++ + dc;
764       *aa++ = *od++;
765     }
766     *(++ii) = *(di++) + *(oi++);
767   }
768   for (; cum < dr; cum++) *(++ii) = nnz;
769 
770   PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg));
771   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
772   PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg));
773   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure");
774   PetscCall(MatSeqAIJRestoreArray(Ad, &dd));
775   PetscCall(MatSeqAIJRestoreArray(Ao, &od));
776 
777   ii = aux;
778   jj = aux + dr + 1;
779   aa = data;
780   PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA));
781 
782   /* create containers to destroy the data */
783   ptrs[0] = aux;
784   ptrs[1] = data;
785   for (i = 0; i < 2; i++) PetscCall(PetscObjectContainerCompose((PetscObject)lA, names[i], ptrs[i], PetscCtxDestroyDefault));
786   if (ismpibaij) { /* destroy converted local matrices */
787     PetscCall(MatDestroy(&Ad));
788     PetscCall(MatDestroy(&Ao));
789   }
790 
791   /* finalize matrix */
792   PetscCall(MatISSetLocalMat(B, lA));
793   PetscCall(MatDestroy(&lA));
794   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
795   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
796   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
797   else *newmat = B;
798   PetscFunctionReturn(PETSC_SUCCESS);
799 }
800 
801 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
802 {
803   Mat                  **nest, *snest, **rnest, lA, B;
804   IS                    *iscol, *isrow, *islrow, *islcol;
805   ISLocalToGlobalMapping rl2g, cl2g;
806   MPI_Comm               comm;
807   PetscInt              *lr, *lc, *l2gidxs;
808   PetscInt               i, j, nr, nc, rbs, cbs;
809   PetscBool              convert, lreuse, *istrans;
810   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
811 
812   PetscFunctionBegin;
813   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
814   lreuse = PETSC_FALSE;
815   rnest  = NULL;
816   if (reuse == MAT_REUSE_MATRIX) {
817     PetscBool ismatis, isnest;
818 
819     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
820     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
821     PetscCall(MatISGetLocalMat(*newmat, &lA));
822     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
823     if (isnest) {
824       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
825       lreuse = (PetscBool)(i == nr && j == nc);
826       if (!lreuse) rnest = NULL;
827     }
828   }
829   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
830   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
831   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
832   PetscCall(MatNestGetISs(A, isrow, iscol));
833   for (i = 0; i < nr; i++) {
834     for (j = 0; j < nc; j++) {
835       PetscBool ismatis, sallow;
836       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
837 
838       /* Null matrix pointers are allowed in MATNEST */
839       if (!nest[i][j]) continue;
840 
841       /* Nested matrices should be of type MATIS */
842       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
843       if (istrans[ij]) {
844         Mat T, lT;
845         PetscCall(MatTransposeGetMat(nest[i][j], &T));
846         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
847         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);
848         PetscCall(MatISGetAllowRepeated(T, &sallow));
849         PetscCall(MatISGetLocalMat(T, &lT));
850         PetscCall(MatCreateTranspose(lT, &snest[ij]));
851       } else {
852         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
853         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);
854         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
855         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
856       }
857       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
858       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
859 
860       /* Check compatibility of local sizes */
861       PetscCall(MatGetSize(snest[ij], &l1, &l2));
862       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
863       if (!l1 || !l2) continue;
864       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);
865       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);
866       lr[i] = l1;
867       lc[j] = l2;
868 
869       /* check compatibility for local matrix reusage */
870       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
871     }
872   }
873 
874   if (PetscDefined(USE_DEBUG)) {
875     /* Check compatibility of l2g maps for rows */
876     for (i = 0; i < nr; i++) {
877       rl2g = NULL;
878       for (j = 0; j < nc; j++) {
879         PetscInt n1, n2;
880 
881         if (!nest[i][j]) continue;
882         if (istrans[i * nc + j]) {
883           Mat T;
884 
885           PetscCall(MatTransposeGetMat(nest[i][j], &T));
886           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
887         } else {
888           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
889         }
890         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
891         if (!n1) continue;
892         if (!rl2g) {
893           rl2g = cl2g;
894         } else {
895           const PetscInt *idxs1, *idxs2;
896           PetscBool       same;
897 
898           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
899           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);
900           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
901           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
902           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
903           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
904           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
905           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);
906         }
907       }
908     }
909     /* Check compatibility of l2g maps for columns */
910     for (i = 0; i < nc; i++) {
911       rl2g = NULL;
912       for (j = 0; j < nr; j++) {
913         PetscInt n1, n2;
914 
915         if (!nest[j][i]) continue;
916         if (istrans[j * nc + i]) {
917           Mat T;
918 
919           PetscCall(MatTransposeGetMat(nest[j][i], &T));
920           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
921         } else {
922           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
923         }
924         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
925         if (!n1) continue;
926         if (!rl2g) {
927           rl2g = cl2g;
928         } else {
929           const PetscInt *idxs1, *idxs2;
930           PetscBool       same;
931 
932           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
933           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);
934           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
935           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
936           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
937           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
938           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
939           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);
940         }
941       }
942     }
943   }
944 
945   B = NULL;
946   if (reuse != MAT_REUSE_MATRIX) {
947     PetscInt stl;
948 
949     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
950     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
951     PetscCall(PetscMalloc1(stl, &l2gidxs));
952     for (i = 0, stl = 0; i < nr; i++) {
953       Mat             usedmat;
954       Mat_IS         *matis;
955       const PetscInt *idxs;
956 
957       /* local IS for local NEST */
958       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
959 
960       /* l2gmap */
961       j       = 0;
962       usedmat = nest[i][j];
963       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
964       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
965 
966       if (istrans[i * nc + j]) {
967         Mat T;
968         PetscCall(MatTransposeGetMat(usedmat, &T));
969         usedmat = T;
970       }
971       matis = (Mat_IS *)usedmat->data;
972       PetscCall(ISGetIndices(isrow[i], &idxs));
973       if (istrans[i * nc + j]) {
974         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
975         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
976       } else {
977         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
978         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
979       }
980       PetscCall(ISRestoreIndices(isrow[i], &idxs));
981       stl += lr[i];
982     }
983     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
984 
985     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
986     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
987     PetscCall(PetscMalloc1(stl, &l2gidxs));
988     for (i = 0, stl = 0; i < nc; i++) {
989       Mat             usedmat;
990       Mat_IS         *matis;
991       const PetscInt *idxs;
992 
993       /* local IS for local NEST */
994       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
995 
996       /* l2gmap */
997       j       = 0;
998       usedmat = nest[j][i];
999       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
1000       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
1001       if (istrans[j * nc + i]) {
1002         Mat T;
1003         PetscCall(MatTransposeGetMat(usedmat, &T));
1004         usedmat = T;
1005       }
1006       matis = (Mat_IS *)usedmat->data;
1007       PetscCall(ISGetIndices(iscol[i], &idxs));
1008       if (istrans[j * nc + i]) {
1009         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1010         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1011       } else {
1012         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1013         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1014       }
1015       PetscCall(ISRestoreIndices(iscol[i], &idxs));
1016       stl += lc[i];
1017     }
1018     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
1019 
1020     /* Create MATIS */
1021     PetscCall(MatCreate(comm, &B));
1022     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
1023     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
1024     PetscCall(MatSetBlockSizes(B, rbs, cbs));
1025     PetscCall(MatSetType(B, MATIS));
1026     PetscCall(MatISSetLocalMatType(B, MATNEST));
1027     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
1028     { /* hack : avoid setup of scatters */
1029       Mat_IS *matis     = (Mat_IS *)B->data;
1030       matis->islocalref = PETSC_TRUE;
1031     }
1032     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
1033     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1034     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1035     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1036     PetscCall(MatNestSetVecType(lA, VECNEST));
1037     for (i = 0; i < nr * nc; i++) {
1038       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1039     }
1040     PetscCall(MatISSetLocalMat(B, lA));
1041     PetscCall(MatDestroy(&lA));
1042     { /* hack : setup of scatters done here */
1043       Mat_IS *matis = (Mat_IS *)B->data;
1044 
1045       matis->islocalref = PETSC_FALSE;
1046       PetscCall(MatISSetUpScatters_Private(B));
1047     }
1048     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1049     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1050     if (reuse == MAT_INPLACE_MATRIX) {
1051       PetscCall(MatHeaderReplace(A, &B));
1052     } else {
1053       *newmat = B;
1054     }
1055   } else {
1056     if (lreuse) {
1057       PetscCall(MatISGetLocalMat(*newmat, &lA));
1058       for (i = 0; i < nr; i++) {
1059         for (j = 0; j < nc; j++) {
1060           if (snest[i * nc + j]) {
1061             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
1062             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
1063           }
1064         }
1065       }
1066     } else {
1067       PetscInt stl;
1068       for (i = 0, stl = 0; i < nr; i++) {
1069         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
1070         stl += lr[i];
1071       }
1072       for (i = 0, stl = 0; i < nc; i++) {
1073         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
1074         stl += lc[i];
1075       }
1076       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1077       for (i = 0; i < nr * nc; i++) {
1078         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1079       }
1080       PetscCall(MatISSetLocalMat(*newmat, lA));
1081       PetscCall(MatDestroy(&lA));
1082     }
1083     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1084     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1085   }
1086 
1087   /* Create local matrix in MATNEST format */
1088   convert = PETSC_FALSE;
1089   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
1090   if (convert) {
1091     Mat              M;
1092     MatISLocalFields lf;
1093 
1094     PetscCall(MatISGetLocalMat(*newmat, &lA));
1095     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
1096     PetscCall(MatISSetLocalMat(*newmat, M));
1097     PetscCall(MatDestroy(&M));
1098 
1099     /* attach local fields to the matrix */
1100     PetscCall(PetscNew(&lf));
1101     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
1102     for (i = 0; i < nr; i++) {
1103       PetscInt n, st;
1104 
1105       PetscCall(ISGetLocalSize(islrow[i], &n));
1106       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
1107       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
1108     }
1109     for (i = 0; i < nc; i++) {
1110       PetscInt n, st;
1111 
1112       PetscCall(ISGetLocalSize(islcol[i], &n));
1113       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
1114       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
1115     }
1116     lf->nr = nr;
1117     lf->nc = nc;
1118     PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private));
1119   }
1120 
1121   /* Free workspace */
1122   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
1123   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
1124   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
1125   PetscCall(PetscFree2(lr, lc));
1126   PetscFunctionReturn(PETSC_SUCCESS);
1127 }
1128 
1129 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1130 {
1131   Mat_IS            *matis = (Mat_IS *)A->data;
1132   Vec                ll, rr;
1133   const PetscScalar *Y, *X;
1134   PetscScalar       *x, *y;
1135 
1136   PetscFunctionBegin;
1137   if (l) {
1138     ll = matis->y;
1139     PetscCall(VecGetArrayRead(l, &Y));
1140     PetscCall(VecGetArray(ll, &y));
1141     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1142   } else {
1143     ll = NULL;
1144   }
1145   if (r) {
1146     rr = matis->x;
1147     PetscCall(VecGetArrayRead(r, &X));
1148     PetscCall(VecGetArray(rr, &x));
1149     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1150   } else {
1151     rr = NULL;
1152   }
1153   if (ll) {
1154     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1155     PetscCall(VecRestoreArrayRead(l, &Y));
1156     PetscCall(VecRestoreArray(ll, &y));
1157   }
1158   if (rr) {
1159     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1160     PetscCall(VecRestoreArrayRead(r, &X));
1161     PetscCall(VecRestoreArray(rr, &x));
1162   }
1163   PetscCall(MatDiagonalScale(matis->A, ll, rr));
1164   PetscFunctionReturn(PETSC_SUCCESS);
1165 }
1166 
1167 static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1168 {
1169   Mat_IS        *matis = (Mat_IS *)A->data;
1170   MatInfo        info;
1171   PetscLogDouble isend[6], irecv[6];
1172   PetscInt       bs;
1173 
1174   PetscFunctionBegin;
1175   PetscCall(MatGetBlockSize(A, &bs));
1176   if (matis->A->ops->getinfo) {
1177     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
1178     isend[0] = info.nz_used;
1179     isend[1] = info.nz_allocated;
1180     isend[2] = info.nz_unneeded;
1181     isend[3] = info.memory;
1182     isend[4] = info.mallocs;
1183   } else {
1184     isend[0] = 0.;
1185     isend[1] = 0.;
1186     isend[2] = 0.;
1187     isend[3] = 0.;
1188     isend[4] = 0.;
1189   }
1190   isend[5] = matis->A->num_ass;
1191   if (flag == MAT_LOCAL) {
1192     ginfo->nz_used      = isend[0];
1193     ginfo->nz_allocated = isend[1];
1194     ginfo->nz_unneeded  = isend[2];
1195     ginfo->memory       = isend[3];
1196     ginfo->mallocs      = isend[4];
1197     ginfo->assemblies   = isend[5];
1198   } else if (flag == MAT_GLOBAL_MAX) {
1199     PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
1200 
1201     ginfo->nz_used      = irecv[0];
1202     ginfo->nz_allocated = irecv[1];
1203     ginfo->nz_unneeded  = irecv[2];
1204     ginfo->memory       = irecv[3];
1205     ginfo->mallocs      = irecv[4];
1206     ginfo->assemblies   = irecv[5];
1207   } else if (flag == MAT_GLOBAL_SUM) {
1208     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
1209 
1210     ginfo->nz_used      = irecv[0];
1211     ginfo->nz_allocated = irecv[1];
1212     ginfo->nz_unneeded  = irecv[2];
1213     ginfo->memory       = irecv[3];
1214     ginfo->mallocs      = irecv[4];
1215     ginfo->assemblies   = A->num_ass;
1216   }
1217   ginfo->block_size        = bs;
1218   ginfo->fill_ratio_given  = 0;
1219   ginfo->fill_ratio_needed = 0;
1220   ginfo->factor_mallocs    = 0;
1221   PetscFunctionReturn(PETSC_SUCCESS);
1222 }
1223 
1224 static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1225 {
1226   Mat C, lC, lA;
1227 
1228   PetscFunctionBegin;
1229   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1230   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1231     ISLocalToGlobalMapping rl2g, cl2g;
1232     PetscBool              allow_repeated;
1233 
1234     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
1235     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
1236     PetscCall(MatSetBlockSizes(C, A->cmap->bs, A->rmap->bs));
1237     PetscCall(MatSetType(C, MATIS));
1238     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
1239     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
1240     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
1241     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1242   } else C = *B;
1243 
1244   /* perform local transposition */
1245   PetscCall(MatISGetLocalMat(A, &lA));
1246   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
1247   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
1248   PetscCall(MatISSetLocalMat(C, lC));
1249   PetscCall(MatDestroy(&lC));
1250 
1251   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1252     *B = C;
1253   } else {
1254     PetscCall(MatHeaderMerge(A, &C));
1255   }
1256   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1257   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1258   PetscFunctionReturn(PETSC_SUCCESS);
1259 }
1260 
1261 static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1262 {
1263   Mat_IS *is = (Mat_IS *)A->data;
1264 
1265   PetscFunctionBegin;
1266   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
1267   if (D) { /* MatShift_IS pass D = NULL */
1268     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
1269     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
1270   }
1271   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
1272   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
1273   PetscFunctionReturn(PETSC_SUCCESS);
1274 }
1275 
1276 static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1277 {
1278   Mat_IS *is = (Mat_IS *)A->data;
1279 
1280   PetscFunctionBegin;
1281   PetscCall(VecSet(is->y, a));
1282   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
1283   PetscFunctionReturn(PETSC_SUCCESS);
1284 }
1285 
1286 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1287 {
1288   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1289 
1290   PetscFunctionBegin;
1291   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);
1292   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
1293   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
1294   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1295   PetscFunctionReturn(PETSC_SUCCESS);
1296 }
1297 
1298 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1299 {
1300   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1301 
1302   PetscFunctionBegin;
1303   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);
1304   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
1305   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
1306   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1307   PetscFunctionReturn(PETSC_SUCCESS);
1308 }
1309 
1310 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1311 {
1312   Mat             locmat, newlocmat;
1313   Mat_IS         *newmatis;
1314   const PetscInt *idxs;
1315   PetscInt        i, m, n;
1316 
1317   PetscFunctionBegin;
1318   if (scall == MAT_REUSE_MATRIX) {
1319     PetscBool ismatis;
1320 
1321     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
1322     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1323     newmatis = (Mat_IS *)(*newmat)->data;
1324     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
1325     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1326   }
1327   /* irow and icol may not have duplicate entries */
1328   if (PetscDefined(USE_DEBUG)) {
1329     Vec                rtest, ltest;
1330     const PetscScalar *array;
1331 
1332     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
1333     PetscCall(ISGetLocalSize(irow, &n));
1334     PetscCall(ISGetIndices(irow, &idxs));
1335     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
1336     PetscCall(VecAssemblyBegin(rtest));
1337     PetscCall(VecAssemblyEnd(rtest));
1338     PetscCall(VecGetLocalSize(rtest, &n));
1339     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
1340     PetscCall(VecGetArrayRead(rtest, &array));
1341     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]));
1342     PetscCall(VecRestoreArrayRead(rtest, &array));
1343     PetscCall(ISRestoreIndices(irow, &idxs));
1344     PetscCall(ISGetLocalSize(icol, &n));
1345     PetscCall(ISGetIndices(icol, &idxs));
1346     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
1347     PetscCall(VecAssemblyBegin(ltest));
1348     PetscCall(VecAssemblyEnd(ltest));
1349     PetscCall(VecGetLocalSize(ltest, &n));
1350     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
1351     PetscCall(VecGetArrayRead(ltest, &array));
1352     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]));
1353     PetscCall(VecRestoreArrayRead(ltest, &array));
1354     PetscCall(ISRestoreIndices(icol, &idxs));
1355     PetscCall(VecDestroy(&rtest));
1356     PetscCall(VecDestroy(&ltest));
1357   }
1358   if (scall == MAT_INITIAL_MATRIX) {
1359     Mat_IS                *matis = (Mat_IS *)mat->data;
1360     ISLocalToGlobalMapping rl2g;
1361     IS                     is;
1362     PetscInt              *lidxs, *lgidxs, *newgidxs;
1363     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
1364     PetscBool              cong;
1365     MPI_Comm               comm;
1366 
1367     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
1368     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
1369     PetscCall(ISGetBlockSize(irow, &irbs));
1370     PetscCall(ISGetBlockSize(icol, &icbs));
1371     rbs = arbs == irbs ? irbs : 1;
1372     cbs = acbs == icbs ? icbs : 1;
1373     PetscCall(ISGetLocalSize(irow, &m));
1374     PetscCall(ISGetLocalSize(icol, &n));
1375     PetscCall(MatCreate(comm, newmat));
1376     PetscCall(MatSetType(*newmat, MATIS));
1377     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
1378     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
1379     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1380     /* communicate irow to their owners in the layout */
1381     PetscCall(ISGetIndices(irow, &idxs));
1382     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
1383     PetscCall(ISRestoreIndices(irow, &idxs));
1384     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1385     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
1386     PetscCall(PetscFree(lidxs));
1387     PetscCall(PetscFree(lgidxs));
1388     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1389     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1390     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1391       if (matis->sf_leafdata[i]) newloc++;
1392     PetscCall(PetscMalloc1(newloc, &newgidxs));
1393     PetscCall(PetscMalloc1(newloc, &lidxs));
1394     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1395       if (matis->sf_leafdata[i]) {
1396         lidxs[newloc]      = i;
1397         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1398       }
1399     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
1400     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
1401     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
1402     PetscCall(ISDestroy(&is));
1403     /* local is to extract local submatrix */
1404     newmatis = (Mat_IS *)(*newmat)->data;
1405     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
1406     PetscCall(MatHasCongruentLayouts(mat, &cong));
1407     if (cong && irow == icol && matis->csf == matis->sf) {
1408       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
1409       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1410       newmatis->getsub_cis = newmatis->getsub_ris;
1411     } else {
1412       ISLocalToGlobalMapping cl2g;
1413 
1414       /* communicate icol to their owners in the layout */
1415       PetscCall(ISGetIndices(icol, &idxs));
1416       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
1417       PetscCall(ISRestoreIndices(icol, &idxs));
1418       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1419       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
1420       PetscCall(PetscFree(lidxs));
1421       PetscCall(PetscFree(lgidxs));
1422       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
1423       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
1424       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1425         if (matis->csf_leafdata[i]) newloc++;
1426       PetscCall(PetscMalloc1(newloc, &newgidxs));
1427       PetscCall(PetscMalloc1(newloc, &lidxs));
1428       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1429         if (matis->csf_leafdata[i]) {
1430           lidxs[newloc]      = i;
1431           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1432         }
1433       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
1434       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
1435       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
1436       PetscCall(ISDestroy(&is));
1437       /* local is to extract local submatrix */
1438       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
1439       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
1440       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1441     }
1442     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1443   } else {
1444     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1445   }
1446   PetscCall(MatISGetLocalMat(mat, &locmat));
1447   newmatis = (Mat_IS *)(*newmat)->data;
1448   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1449   if (scall == MAT_INITIAL_MATRIX) {
1450     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
1451     PetscCall(MatDestroy(&newlocmat));
1452   }
1453   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1454   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1455   PetscFunctionReturn(PETSC_SUCCESS);
1456 }
1457 
1458 static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1459 {
1460   Mat_IS   *a = (Mat_IS *)A->data, *b;
1461   PetscBool ismatis;
1462 
1463   PetscFunctionBegin;
1464   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
1465   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
1466   b = (Mat_IS *)B->data;
1467   PetscCall(MatCopy(a->A, b->A, str));
1468   PetscCall(PetscObjectStateIncrease((PetscObject)B));
1469   PetscFunctionReturn(PETSC_SUCCESS);
1470 }
1471 
1472 static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1473 {
1474   Vec                v;
1475   const PetscScalar *array;
1476   PetscInt           i, n;
1477 
1478   PetscFunctionBegin;
1479   *missing = PETSC_FALSE;
1480   PetscCall(MatCreateVecs(A, NULL, &v));
1481   PetscCall(MatGetDiagonal(A, v));
1482   PetscCall(VecGetLocalSize(v, &n));
1483   PetscCall(VecGetArrayRead(v, &array));
1484   for (i = 0; i < n; i++)
1485     if (array[i] == 0.) break;
1486   PetscCall(VecRestoreArrayRead(v, &array));
1487   PetscCall(VecDestroy(&v));
1488   if (i != n) *missing = PETSC_TRUE;
1489   if (d) {
1490     *d = -1;
1491     if (*missing) {
1492       PetscInt rstart;
1493       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1494       *d = i + rstart;
1495     }
1496   }
1497   PetscFunctionReturn(PETSC_SUCCESS);
1498 }
1499 
1500 static PetscErrorCode MatISSetUpSF_IS(Mat B)
1501 {
1502   Mat_IS         *matis = (Mat_IS *)B->data;
1503   const PetscInt *gidxs;
1504   PetscInt        nleaves;
1505 
1506   PetscFunctionBegin;
1507   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
1508   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
1509   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
1510   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
1511   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
1512   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
1513   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1514   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
1515     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
1516     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
1517     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
1518     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
1519     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
1520     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1521   } else {
1522     matis->csf          = matis->sf;
1523     matis->csf_leafdata = matis->sf_leafdata;
1524     matis->csf_rootdata = matis->sf_rootdata;
1525   }
1526   PetscFunctionReturn(PETSC_SUCCESS);
1527 }
1528 
1529 /*@
1530   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
1531 
1532   Not Collective
1533 
1534   Input Parameter:
1535 . A - the matrix
1536 
1537   Output Parameter:
1538 . flg - the boolean flag
1539 
1540   Level: intermediate
1541 
1542 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
1543 @*/
1544 PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
1545 {
1546   PetscBool ismatis;
1547 
1548   PetscFunctionBegin;
1549   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1550   PetscAssertPointer(flg, 2);
1551   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
1552   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
1553   *flg = ((Mat_IS *)A->data)->allow_repeated;
1554   PetscFunctionReturn(PETSC_SUCCESS);
1555 }
1556 
1557 /*@
1558   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
1559 
1560   Logically Collective
1561 
1562   Input Parameters:
1563 + A   - the matrix
1564 - flg - the boolean flag
1565 
1566   Level: intermediate
1567 
1568   Notes:
1569   The default value is `PETSC_FALSE`.
1570   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
1571   if `flg` is different from the previously set value.
1572   Specifically, when `flg` is true it will just recreate the local matrices, while if
1573   `flg` is false will assemble the local matrices summing up repeated entries.
1574 
1575 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
1576 @*/
1577 PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
1578 {
1579   PetscFunctionBegin;
1580   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1581   PetscValidType(A, 1);
1582   PetscValidLogicalCollectiveBool(A, flg, 2);
1583   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
1584   PetscFunctionReturn(PETSC_SUCCESS);
1585 }
1586 
1587 static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
1588 {
1589   Mat_IS                *matis = (Mat_IS *)A->data;
1590   Mat                    lA    = NULL;
1591   ISLocalToGlobalMapping lrmap, lcmap;
1592 
1593   PetscFunctionBegin;
1594   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
1595   if (!matis->A) { /* matrix has not been preallocated yet */
1596     matis->allow_repeated = flg;
1597     PetscFunctionReturn(PETSC_SUCCESS);
1598   }
1599   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
1600   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
1601     lA = matis->A;
1602     PetscCall(PetscObjectReference((PetscObject)lA));
1603   }
1604   /* In case flg is True, we only recreate the local matrix */
1605   matis->allow_repeated = flg;
1606   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
1607   if (lA) { /* assemble previous local matrix if needed */
1608     Mat nA = matis->A;
1609 
1610     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
1611     if (!lrmap && !lcmap) {
1612       PetscCall(MatISSetLocalMat(A, lA));
1613     } else {
1614       Mat            P = NULL, R = NULL;
1615       MatProductType ptype;
1616 
1617       if (lrmap == lcmap) {
1618         ptype = MATPRODUCT_PtAP;
1619         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
1620         PetscCall(MatProductCreate(lA, P, NULL, &nA));
1621       } else {
1622         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
1623         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
1624         if (R && P) {
1625           ptype = MATPRODUCT_ABC;
1626           PetscCall(MatProductCreate(R, lA, P, &nA));
1627         } else if (R) {
1628           ptype = MATPRODUCT_AB;
1629           PetscCall(MatProductCreate(R, lA, NULL, &nA));
1630         } else {
1631           ptype = MATPRODUCT_AB;
1632           PetscCall(MatProductCreate(lA, P, NULL, &nA));
1633         }
1634       }
1635       PetscCall(MatProductSetType(nA, ptype));
1636       PetscCall(MatProductSetFromOptions(nA));
1637       PetscCall(MatProductSymbolic(nA));
1638       PetscCall(MatProductNumeric(nA));
1639       PetscCall(MatProductClear(nA));
1640       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
1641       PetscCall(MatISSetLocalMat(A, nA));
1642       PetscCall(MatDestroy(&nA));
1643       PetscCall(MatDestroy(&P));
1644       PetscCall(MatDestroy(&R));
1645     }
1646   }
1647   PetscCall(MatDestroy(&lA));
1648   PetscFunctionReturn(PETSC_SUCCESS);
1649 }
1650 
1651 /*@
1652   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
1653 
1654   Logically Collective
1655 
1656   Input Parameters:
1657 + A     - the matrix
1658 - store - the boolean flag
1659 
1660   Level: advanced
1661 
1662 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
1663 @*/
1664 PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1665 {
1666   PetscFunctionBegin;
1667   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1668   PetscValidType(A, 1);
1669   PetscValidLogicalCollectiveBool(A, store, 2);
1670   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
1671   PetscFunctionReturn(PETSC_SUCCESS);
1672 }
1673 
1674 static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1675 {
1676   Mat_IS *matis = (Mat_IS *)A->data;
1677 
1678   PetscFunctionBegin;
1679   matis->storel2l = store;
1680   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
1681   PetscFunctionReturn(PETSC_SUCCESS);
1682 }
1683 
1684 /*@
1685   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1686 
1687   Logically Collective
1688 
1689   Input Parameters:
1690 + A   - the matrix
1691 - fix - the boolean flag
1692 
1693   Level: advanced
1694 
1695   Note:
1696   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1697 
1698 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1699 @*/
1700 PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1701 {
1702   PetscFunctionBegin;
1703   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1704   PetscValidType(A, 1);
1705   PetscValidLogicalCollectiveBool(A, fix, 2);
1706   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
1707   PetscFunctionReturn(PETSC_SUCCESS);
1708 }
1709 
1710 static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1711 {
1712   Mat_IS *matis = (Mat_IS *)A->data;
1713 
1714   PetscFunctionBegin;
1715   matis->locempty = fix;
1716   PetscFunctionReturn(PETSC_SUCCESS);
1717 }
1718 
1719 /*@
1720   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1721 
1722   Collective
1723 
1724   Input Parameters:
1725 + B     - the matrix
1726 . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1727            (same value is used for all local rows)
1728 . d_nnz - array containing the number of nonzeros in the various rows of the
1729            DIAGONAL portion of the local submatrix (possibly different for each row)
1730            or `NULL`, if `d_nz` is used to specify the nonzero structure.
1731            The size of this array is equal to the number of local rows, i.e `m`.
1732            For matrices that will be factored, you must leave room for (and set)
1733            the diagonal entry even if it is zero.
1734 . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1735            submatrix (same value is used for all local rows).
1736 - o_nnz - array containing the number of nonzeros in the various rows of the
1737            OFF-DIAGONAL portion of the local submatrix (possibly different for
1738            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1739            structure. The size of this array is equal to the number
1740            of local rows, i.e `m`.
1741 
1742    If the *_nnz parameter is given then the *_nz parameter is ignored
1743 
1744   Level: intermediate
1745 
1746   Note:
1747   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
1748   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1749   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1750 
1751 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1752 @*/
1753 PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1754 {
1755   PetscFunctionBegin;
1756   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1757   PetscValidType(B, 1);
1758   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
1759   PetscFunctionReturn(PETSC_SUCCESS);
1760 }
1761 
1762 static PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1763 {
1764   Mat_IS  *matis = (Mat_IS *)B->data;
1765   PetscInt bs, i, nlocalcols;
1766 
1767   PetscFunctionBegin;
1768   PetscCall(MatSetUp(B));
1769   if (!d_nnz)
1770     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
1771   else
1772     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
1773 
1774   if (!o_nnz)
1775     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
1776   else
1777     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
1778 
1779   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1780   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
1781   PetscCall(MatGetBlockSize(matis->A, &bs));
1782   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1783 
1784   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
1785   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
1786 #if defined(PETSC_HAVE_HYPRE)
1787   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
1788 #endif
1789 
1790   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1791     PetscInt b;
1792 
1793     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1794     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1795   }
1796   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
1797 
1798   nlocalcols /= bs;
1799   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
1800   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
1801 
1802   /* for other matrix types */
1803   PetscCall(MatSetUp(matis->A));
1804   PetscFunctionReturn(PETSC_SUCCESS);
1805 }
1806 
1807 PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1808 {
1809   Mat_IS            *matis     = (Mat_IS *)mat->data;
1810   Mat                local_mat = NULL, MT;
1811   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1812   PetscInt           local_rows, local_cols;
1813   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1814   PetscMPIInt        size;
1815   const PetscScalar *array;
1816 
1817   PetscFunctionBegin;
1818   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1819   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
1820     Mat      B;
1821     IS       irows = NULL, icols = NULL;
1822     PetscInt rbs, cbs;
1823 
1824     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
1825     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
1826     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
1827       IS              rows, cols;
1828       const PetscInt *ridxs, *cidxs;
1829       PetscInt        i, nw;
1830       PetscBT         work;
1831 
1832       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
1833       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
1834       nw = nw / rbs;
1835       PetscCall(PetscBTCreate(nw, &work));
1836       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
1837       for (i = 0; i < nw; i++)
1838         if (!PetscBTLookup(work, i)) break;
1839       if (i == nw) {
1840         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
1841         PetscCall(ISSetPermutation(rows));
1842         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
1843         PetscCall(ISDestroy(&rows));
1844       }
1845       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
1846       PetscCall(PetscBTDestroy(&work));
1847       if (irows && matis->rmapping != matis->cmapping) {
1848         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
1849         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
1850         nw = nw / cbs;
1851         PetscCall(PetscBTCreate(nw, &work));
1852         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
1853         for (i = 0; i < nw; i++)
1854           if (!PetscBTLookup(work, i)) break;
1855         if (i == nw) {
1856           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
1857           PetscCall(ISSetPermutation(cols));
1858           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
1859           PetscCall(ISDestroy(&cols));
1860         }
1861         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
1862         PetscCall(PetscBTDestroy(&work));
1863       } else if (irows) {
1864         PetscCall(PetscObjectReference((PetscObject)irows));
1865         icols = irows;
1866       }
1867     } else {
1868       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
1869       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
1870       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
1871       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
1872     }
1873     if (!irows || !icols) {
1874       PetscCall(ISDestroy(&icols));
1875       PetscCall(ISDestroy(&irows));
1876       goto general_assembly;
1877     }
1878     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
1879     if (reuse != MAT_INPLACE_MATRIX) {
1880       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
1881       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
1882       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
1883     } else {
1884       Mat C;
1885 
1886       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
1887       PetscCall(MatHeaderReplace(mat, &C));
1888     }
1889     PetscCall(MatDestroy(&B));
1890     PetscCall(ISDestroy(&icols));
1891     PetscCall(ISDestroy(&irows));
1892     PetscFunctionReturn(PETSC_SUCCESS);
1893   }
1894 general_assembly:
1895   PetscCall(MatGetSize(mat, &rows, &cols));
1896   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
1897   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
1898   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
1899   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
1900   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
1901   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
1902   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
1903   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
1904   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
1905   if (PetscDefined(USE_DEBUG)) {
1906     PetscBool lb[4], bb[4];
1907 
1908     lb[0] = isseqdense;
1909     lb[1] = isseqaij;
1910     lb[2] = isseqbaij;
1911     lb[3] = isseqsbaij;
1912     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
1913     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
1914   }
1915 
1916   if (reuse != MAT_REUSE_MATRIX) {
1917     PetscCount ncoo;
1918     PetscInt  *coo_i, *coo_j;
1919 
1920     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
1921     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
1922     PetscCall(MatSetType(MT, mtype));
1923     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
1924     if (!isseqaij && !isseqdense) {
1925       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1926     } else {
1927       PetscCall(PetscObjectReference((PetscObject)matis->A));
1928       local_mat = matis->A;
1929     }
1930     PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
1931     if (isseqdense) {
1932       PetscInt nr, nc;
1933 
1934       PetscCall(MatGetSize(local_mat, &nr, &nc));
1935       ncoo = nr * nc;
1936       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1937       for (PetscInt j = 0; j < nc; j++) {
1938         for (PetscInt i = 0; i < nr; i++) {
1939           coo_i[j * nr + i] = i;
1940           coo_j[j * nr + i] = j;
1941         }
1942       }
1943     } else {
1944       const PetscInt *ii, *jj;
1945       PetscInt        nr;
1946       PetscBool       done;
1947 
1948       PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1949       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1950       ncoo = ii[nr];
1951       PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j));
1952       PetscCall(PetscArraycpy(coo_j, jj, ncoo));
1953       for (PetscInt i = 0; i < nr; i++) {
1954         for (PetscInt j = ii[i]; j < ii[i + 1]; j++) coo_i[j] = i;
1955       }
1956       PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done));
1957       PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1958     }
1959     PetscCall(MatSetPreallocationCOOLocal(MT, ncoo, coo_i, coo_j));
1960     PetscCall(PetscFree2(coo_i, coo_j));
1961   } else {
1962     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
1963 
1964     /* some checks */
1965     MT = *M;
1966     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
1967     PetscCall(MatGetSize(MT, &mrows, &mcols));
1968     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
1969     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
1970     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
1971     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
1972     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
1973     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
1974     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
1975     PetscCall(MatZeroEntries(MT));
1976     if (!isseqaij && !isseqdense) {
1977       PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
1978     } else {
1979       PetscCall(PetscObjectReference((PetscObject)matis->A));
1980       local_mat = matis->A;
1981     }
1982   }
1983 
1984   /* Set values */
1985   if (isseqdense) {
1986     PetscCall(MatDenseGetArrayRead(local_mat, &array));
1987     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
1988     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
1989   } else {
1990     PetscCall(MatSeqAIJGetArrayRead(local_mat, &array));
1991     PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES));
1992     PetscCall(MatSeqAIJRestoreArrayRead(local_mat, &array));
1993   }
1994   PetscCall(MatDestroy(&local_mat));
1995   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
1996   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
1997   if (reuse == MAT_INPLACE_MATRIX) {
1998     PetscCall(MatHeaderReplace(mat, &MT));
1999   } else if (reuse == MAT_INITIAL_MATRIX) {
2000     *M = MT;
2001   }
2002   PetscFunctionReturn(PETSC_SUCCESS);
2003 }
2004 
2005 static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2006 {
2007   Mat_IS  *matis = (Mat_IS *)mat->data;
2008   PetscInt rbs, cbs, m, n, M, N;
2009   Mat      B, localmat;
2010 
2011   PetscFunctionBegin;
2012   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
2013   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
2014   PetscCall(MatGetSize(mat, &M, &N));
2015   PetscCall(MatGetLocalSize(mat, &m, &n));
2016   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
2017   PetscCall(MatSetSizes(B, m, n, M, N));
2018   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
2019   PetscCall(MatSetType(B, MATIS));
2020   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
2021   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
2022   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
2023   PetscCall(MatDuplicate(matis->A, op, &localmat));
2024   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
2025   PetscCall(MatISSetLocalMat(B, localmat));
2026   PetscCall(MatDestroy(&localmat));
2027   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2028   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2029   *newmat = B;
2030   PetscFunctionReturn(PETSC_SUCCESS);
2031 }
2032 
2033 static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2034 {
2035   Mat_IS   *matis = (Mat_IS *)A->data;
2036   PetscBool local_sym;
2037 
2038   PetscFunctionBegin;
2039   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
2040   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2041   PetscFunctionReturn(PETSC_SUCCESS);
2042 }
2043 
2044 static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2045 {
2046   Mat_IS   *matis = (Mat_IS *)A->data;
2047   PetscBool local_sym;
2048 
2049   PetscFunctionBegin;
2050   if (matis->rmapping != matis->cmapping) {
2051     *flg = PETSC_FALSE;
2052     PetscFunctionReturn(PETSC_SUCCESS);
2053   }
2054   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
2055   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2056   PetscFunctionReturn(PETSC_SUCCESS);
2057 }
2058 
2059 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2060 {
2061   Mat_IS   *matis = (Mat_IS *)A->data;
2062   PetscBool local_sym;
2063 
2064   PetscFunctionBegin;
2065   if (matis->rmapping != matis->cmapping) {
2066     *flg = PETSC_FALSE;
2067     PetscFunctionReturn(PETSC_SUCCESS);
2068   }
2069   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
2070   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2071   PetscFunctionReturn(PETSC_SUCCESS);
2072 }
2073 
2074 static PetscErrorCode MatDestroy_IS(Mat A)
2075 {
2076   Mat_IS *b = (Mat_IS *)A->data;
2077 
2078   PetscFunctionBegin;
2079   PetscCall(PetscFree(b->bdiag));
2080   PetscCall(PetscFree(b->lmattype));
2081   PetscCall(MatDestroy(&b->A));
2082   PetscCall(VecScatterDestroy(&b->cctx));
2083   PetscCall(VecScatterDestroy(&b->rctx));
2084   PetscCall(VecDestroy(&b->x));
2085   PetscCall(VecDestroy(&b->y));
2086   PetscCall(VecDestroy(&b->counter));
2087   PetscCall(ISDestroy(&b->getsub_ris));
2088   PetscCall(ISDestroy(&b->getsub_cis));
2089   if (b->sf != b->csf) {
2090     PetscCall(PetscSFDestroy(&b->csf));
2091     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2092   } else b->csf = NULL;
2093   PetscCall(PetscSFDestroy(&b->sf));
2094   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
2095   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
2096   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2097   PetscCall(MatDestroy(&b->dA));
2098   PetscCall(MatDestroy(&b->assembledA));
2099   PetscCall(PetscFree(A->data));
2100   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
2101   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
2102   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
2103   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
2104   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
2105   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
2106   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
2107   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
2108   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
2109   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
2110   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
2111   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
2112   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
2113   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
2114   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
2115   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
2116   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
2117   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
2118   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
2119   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
2120   PetscFunctionReturn(PETSC_SUCCESS);
2121 }
2122 
2123 static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2124 {
2125   Mat_IS     *is   = (Mat_IS *)A->data;
2126   PetscScalar zero = 0.0;
2127 
2128   PetscFunctionBegin;
2129   /*  scatter the global vector x into the local work vector */
2130   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2131   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2132 
2133   /* multiply the local matrix */
2134   PetscCall(MatMult(is->A, is->x, is->y));
2135 
2136   /* scatter product back into global memory */
2137   PetscCall(VecSet(y, zero));
2138   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2139   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2140   PetscFunctionReturn(PETSC_SUCCESS);
2141 }
2142 
2143 static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2144 {
2145   Vec temp_vec;
2146 
2147   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2148   if (v3 != v2) {
2149     PetscCall(MatMult(A, v1, v3));
2150     PetscCall(VecAXPY(v3, 1.0, v2));
2151   } else {
2152     PetscCall(VecDuplicate(v2, &temp_vec));
2153     PetscCall(MatMult(A, v1, temp_vec));
2154     PetscCall(VecAXPY(temp_vec, 1.0, v2));
2155     PetscCall(VecCopy(temp_vec, v3));
2156     PetscCall(VecDestroy(&temp_vec));
2157   }
2158   PetscFunctionReturn(PETSC_SUCCESS);
2159 }
2160 
2161 static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2162 {
2163   Mat_IS *is = (Mat_IS *)A->data;
2164 
2165   PetscFunctionBegin;
2166   /*  scatter the global vector x into the local work vector */
2167   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
2168   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
2169 
2170   /* multiply the local matrix */
2171   PetscCall(MatMultTranspose(is->A, is->y, is->x));
2172 
2173   /* scatter product back into global vector */
2174   PetscCall(VecSet(x, 0));
2175   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
2176   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
2177   PetscFunctionReturn(PETSC_SUCCESS);
2178 }
2179 
2180 static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2181 {
2182   Vec temp_vec;
2183 
2184   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2185   if (v3 != v2) {
2186     PetscCall(MatMultTranspose(A, v1, v3));
2187     PetscCall(VecAXPY(v3, 1.0, v2));
2188   } else {
2189     PetscCall(VecDuplicate(v2, &temp_vec));
2190     PetscCall(MatMultTranspose(A, v1, temp_vec));
2191     PetscCall(VecAXPY(temp_vec, 1.0, v2));
2192     PetscCall(VecCopy(temp_vec, v3));
2193     PetscCall(VecDestroy(&temp_vec));
2194   }
2195   PetscFunctionReturn(PETSC_SUCCESS);
2196 }
2197 
2198 static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2199 {
2200   Mat_IS                *a = (Mat_IS *)A->data;
2201   PetscViewer            sviewer;
2202   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
2203   PetscViewerFormat      format;
2204   ISLocalToGlobalMapping rmap, cmap;
2205 
2206   PetscFunctionBegin;
2207   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2208   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2209   PetscCall(PetscViewerGetFormat(viewer, &format));
2210   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
2211   if (native) {
2212     rmap = A->rmap->mapping;
2213     cmap = A->cmap->mapping;
2214   } else {
2215     rmap = a->rmapping;
2216     cmap = a->cmapping;
2217   }
2218   if (isascii) {
2219     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
2220     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
2221   } else if (isbinary) {
2222     PetscInt    tr[6], nr, nc;
2223     char        lmattype[64] = {'\0'};
2224     PetscMPIInt size;
2225     PetscBool   skipHeader;
2226     IS          is;
2227 
2228     PetscCall(PetscViewerSetUp(viewer));
2229     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2230     tr[0] = MAT_FILE_CLASSID;
2231     tr[1] = A->rmap->N;
2232     tr[2] = A->cmap->N;
2233     tr[3] = -size; /* AIJ stores nnz here */
2234     tr[4] = (PetscInt)(rmap == cmap);
2235     tr[5] = a->allow_repeated;
2236     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
2237 
2238     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
2239     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
2240 
2241     /* first dump l2g info (we need the header for proper loading on different number of processes) */
2242     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
2243     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
2244     PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2245     if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2246 
2247     /* then the sizes of the local matrices */
2248     PetscCall(MatGetSize(a->A, &nr, &nc));
2249     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
2250     PetscCall(ISView(is, viewer));
2251     PetscCall(ISDestroy(&is));
2252     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
2253     PetscCall(ISView(is, viewer));
2254     PetscCall(ISDestroy(&is));
2255     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
2256   }
2257   if (format == PETSC_VIEWER_ASCII_MATLAB) {
2258     char        name[64];
2259     PetscMPIInt size, rank;
2260 
2261     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2262     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
2263     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
2264     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
2265     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
2266   }
2267 
2268   /* Dump the local matrices */
2269   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
2270     PetscBool   isaij;
2271     PetscInt    nr, nc;
2272     Mat         lA, B;
2273     Mat_MPIAIJ *b;
2274 
2275     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
2276     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
2277     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
2278     else {
2279       PetscCall(PetscObjectReference((PetscObject)a->A));
2280       lA = a->A;
2281     }
2282     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
2283     PetscCall(MatSetType(B, MATMPIAIJ));
2284     PetscCall(MatGetSize(lA, &nr, &nc));
2285     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
2286     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
2287 
2288     b = (Mat_MPIAIJ *)B->data;
2289     PetscCall(MatDestroy(&b->A));
2290     b->A = lA;
2291 
2292     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2293     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2294     PetscCall(MatView(B, viewer));
2295     PetscCall(MatDestroy(&B));
2296   } else {
2297     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2298     PetscCall(MatView(a->A, sviewer));
2299     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2300   }
2301 
2302   /* with ASCII, we dump the l2gmaps at the end */
2303   if (viewl2g) {
2304     if (format == PETSC_VIEWER_ASCII_MATLAB) {
2305       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
2306       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2307       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
2308       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2309     } else {
2310       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2311       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2312     }
2313   }
2314   PetscFunctionReturn(PETSC_SUCCESS);
2315 }
2316 
2317 static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
2318 {
2319   ISLocalToGlobalMapping rmap, cmap;
2320   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
2321   PetscBool              isbinary, samel, allow, isbaij;
2322   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
2323   const PetscInt        *idx;
2324   PetscMPIInt            size;
2325   char                   lmattype[64];
2326   Mat                    dA, lA;
2327   IS                     is;
2328 
2329   PetscFunctionBegin;
2330   PetscCheckSameComm(A, 1, viewer, 2);
2331   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2332   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
2333 
2334   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
2335   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
2336   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2337   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2338   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2339   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2340   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2341   M     = tr[1];
2342   N     = tr[2];
2343   Asize = -tr[3];
2344   samel = (PetscBool)tr[4];
2345   allow = (PetscBool)tr[5];
2346   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
2347 
2348   /* if we are loading from a larger set of processes, allow repeated entries */
2349   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2350   if (Asize > size) allow = PETSC_TRUE;
2351 
2352   /* set global sizes if not set already */
2353   if (A->rmap->N < 0) A->rmap->N = M;
2354   if (A->cmap->N < 0) A->cmap->N = N;
2355   PetscCall(PetscLayoutSetUp(A->rmap));
2356   PetscCall(PetscLayoutSetUp(A->cmap));
2357   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
2358   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
2359 
2360   /* load l2g maps */
2361   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
2362   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
2363   if (!samel) {
2364     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
2365     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
2366   } else {
2367     PetscCall(PetscObjectReference((PetscObject)rmap));
2368     cmap = rmap;
2369   }
2370 
2371   /* load sizes of local matrices */
2372   PetscCall(ISCreate(comm, &is));
2373   PetscCall(ISSetType(is, ISGENERAL));
2374   PetscCall(ISLoad(is, viewer));
2375   PetscCall(ISGetLocalSize(is, &isn));
2376   PetscCall(ISGetIndices(is, &idx));
2377   nr = 0;
2378   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
2379   PetscCall(ISRestoreIndices(is, &idx));
2380   PetscCall(ISDestroy(&is));
2381   PetscCall(ISCreate(comm, &is));
2382   PetscCall(ISSetType(is, ISGENERAL));
2383   PetscCall(ISLoad(is, viewer));
2384   PetscCall(ISGetLocalSize(is, &isn));
2385   PetscCall(ISGetIndices(is, &idx));
2386   nc = 0;
2387   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
2388   PetscCall(ISRestoreIndices(is, &idx));
2389   PetscCall(ISDestroy(&is));
2390 
2391   /* now load the unassembled operator */
2392   PetscCall(MatCreate(comm, &dA));
2393   PetscCall(MatSetType(dA, MATMPIAIJ));
2394   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
2395   PetscCall(MatLoad(dA, viewer));
2396   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
2397   PetscCall(PetscObjectReference((PetscObject)lA));
2398   PetscCall(MatDestroy(&dA));
2399 
2400   /* and convert to the desired format */
2401   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
2402   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
2403   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
2404 
2405   /* assemble the MATIS object */
2406   PetscCall(MatISSetAllowRepeated(A, allow));
2407   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
2408   PetscCall(MatISSetLocalMat(A, lA));
2409   PetscCall(MatDestroy(&lA));
2410   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
2411   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
2412   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2413   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2414   PetscFunctionReturn(PETSC_SUCCESS);
2415 }
2416 
2417 static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2418 {
2419   Mat_IS            *is = (Mat_IS *)mat->data;
2420   MPI_Datatype       nodeType;
2421   const PetscScalar *lv;
2422   PetscInt           bs;
2423   PetscMPIInt        mbs;
2424 
2425   PetscFunctionBegin;
2426   PetscCall(MatGetBlockSize(mat, &bs));
2427   PetscCall(MatSetBlockSize(is->A, bs));
2428   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
2429   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2430   PetscCall(PetscMPIIntCast(bs, &mbs));
2431   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
2432   PetscCallMPI(MPI_Type_commit(&nodeType));
2433   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
2434   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
2435   PetscCallMPI(MPI_Type_free(&nodeType));
2436   if (values) *values = is->bdiag;
2437   PetscFunctionReturn(PETSC_SUCCESS);
2438 }
2439 
2440 static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2441 {
2442   Vec             cglobal, rglobal;
2443   IS              from;
2444   Mat_IS         *is = (Mat_IS *)A->data;
2445   PetscScalar     sum;
2446   const PetscInt *garray;
2447   PetscInt        nr, rbs, nc, cbs;
2448   VecType         rtype;
2449 
2450   PetscFunctionBegin;
2451   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
2452   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
2453   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
2454   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2455   PetscCall(VecDestroy(&is->x));
2456   PetscCall(VecDestroy(&is->y));
2457   PetscCall(VecDestroy(&is->counter));
2458   PetscCall(VecScatterDestroy(&is->rctx));
2459   PetscCall(VecScatterDestroy(&is->cctx));
2460   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
2461   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
2462   PetscCall(VecGetRootType_Private(is->y, &rtype));
2463   PetscCall(PetscFree(A->defaultvectype));
2464   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
2465   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
2466   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
2467   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
2468   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
2469   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
2470   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
2471   PetscCall(ISDestroy(&from));
2472   if (is->rmapping != is->cmapping) {
2473     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
2474     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
2475     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
2476     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
2477     PetscCall(ISDestroy(&from));
2478   } else {
2479     PetscCall(PetscObjectReference((PetscObject)is->rctx));
2480     is->cctx = is->rctx;
2481   }
2482   PetscCall(VecDestroy(&cglobal));
2483 
2484   /* interface counter vector (local) */
2485   PetscCall(VecDuplicate(is->y, &is->counter));
2486   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
2487   PetscCall(VecSet(is->y, 1.));
2488   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
2489   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
2490   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
2491   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
2492   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
2493   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2494 
2495   /* special functions for block-diagonal matrices */
2496   PetscCall(VecSum(rglobal, &sum));
2497   A->ops->invertblockdiagonal = NULL;
2498   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
2499   PetscCall(VecDestroy(&rglobal));
2500 
2501   /* setup SF for general purpose shared indices based communications */
2502   PetscCall(MatISSetUpSF_IS(A));
2503   PetscFunctionReturn(PETSC_SUCCESS);
2504 }
2505 
2506 static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2507 {
2508   Mat_IS                    *matis = (Mat_IS *)A->data;
2509   IS                         is;
2510   ISLocalToGlobalMappingType l2gtype;
2511   const PetscInt            *idxs;
2512   PetscHSetI                 ht;
2513   PetscInt                  *nidxs;
2514   PetscInt                   i, n, bs, c;
2515   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2516 
2517   PetscFunctionBegin;
2518   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
2519   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
2520   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
2521   PetscCall(PetscHSetICreate(&ht));
2522   PetscCall(PetscMalloc1(n / bs, &nidxs));
2523   for (i = 0, c = 0; i < n / bs; i++) {
2524     PetscBool missing = PETSC_TRUE;
2525     if (idxs[i] < 0) {
2526       flg[0] = PETSC_TRUE;
2527       continue;
2528     }
2529     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2530     if (!missing) flg[1] = PETSC_TRUE;
2531     else nidxs[c++] = idxs[i];
2532   }
2533   PetscCall(PetscHSetIDestroy(&ht));
2534   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2535   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2536     *nmap = NULL;
2537     *lmap = NULL;
2538     PetscCall(PetscFree(nidxs));
2539     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2540     PetscFunctionReturn(PETSC_SUCCESS);
2541   }
2542 
2543   /* New l2g map without negative indices (and repeated indices if not allowed) */
2544   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
2545   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
2546   PetscCall(ISDestroy(&is));
2547   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
2548   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2549 
2550   /* New local l2g map for repeated indices if not allowed */
2551   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
2552   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
2553   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
2554   PetscCall(ISDestroy(&is));
2555   PetscCall(PetscFree(nidxs));
2556   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2557   PetscFunctionReturn(PETSC_SUCCESS);
2558 }
2559 
2560 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2561 {
2562   Mat_IS                *is            = (Mat_IS *)A->data;
2563   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2564   PetscInt               nr, rbs, nc, cbs;
2565   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
2566 
2567   PetscFunctionBegin;
2568   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2569   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2570 
2571   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
2572   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
2573   PetscCall(PetscLayoutSetUp(A->rmap));
2574   PetscCall(PetscLayoutSetUp(A->cmap));
2575   PetscCall(MatHasCongruentLayouts(A, &cong));
2576 
2577   /* If NULL, local space matches global space */
2578   if (!rmapping) {
2579     IS is;
2580 
2581     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
2582     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
2583     PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
2584     PetscCall(ISDestroy(&is));
2585     freem[0] = PETSC_TRUE;
2586     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2587   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
2588     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2589     if (rmapping == cmapping) {
2590       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2591       is->cmapping = is->rmapping;
2592       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2593       localcmapping = localrmapping;
2594     }
2595   }
2596   if (!cmapping) {
2597     IS is;
2598 
2599     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
2600     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
2601     PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
2602     PetscCall(ISDestroy(&is));
2603     freem[1] = PETSC_TRUE;
2604   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
2605     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2606   }
2607   if (!is->rmapping) {
2608     PetscCall(PetscObjectReference((PetscObject)rmapping));
2609     is->rmapping = rmapping;
2610   }
2611   if (!is->cmapping) {
2612     PetscCall(PetscObjectReference((PetscObject)cmapping));
2613     is->cmapping = cmapping;
2614   }
2615 
2616   /* Clean up */
2617   is->lnnzstate = 0;
2618   PetscCall(MatDestroy(&is->dA));
2619   PetscCall(MatDestroy(&is->assembledA));
2620   PetscCall(MatDestroy(&is->A));
2621   if (is->csf != is->sf) {
2622     PetscCall(PetscSFDestroy(&is->csf));
2623     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2624   } else is->csf = NULL;
2625   PetscCall(PetscSFDestroy(&is->sf));
2626   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
2627   PetscCall(PetscFree(is->bdiag));
2628 
2629   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2630      (DOLFIN passes 2 different objects) */
2631   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
2632   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
2633   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
2634   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2635   if (is->rmapping != is->cmapping && cong) {
2636     PetscBool same = PETSC_FALSE;
2637     if (nr == nc && cbs == rbs) {
2638       const PetscInt *idxs1, *idxs2;
2639 
2640       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
2641       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
2642       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
2643       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
2644       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
2645     }
2646     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2647     if (same) {
2648       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
2649       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2650       is->cmapping = is->rmapping;
2651     }
2652   }
2653   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
2654   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2655   /* Pass the user defined maps to the layout */
2656   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
2657   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
2658   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
2659   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
2660 
2661   if (!is->islocalref) {
2662     /* Create the local matrix A */
2663     PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
2664     PetscCall(MatSetType(is->A, is->lmattype));
2665     PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
2666     PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
2667     PetscCall(MatSetOptionsPrefix(is->A, "is_"));
2668     PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
2669     PetscCall(PetscLayoutSetUp(is->A->rmap));
2670     PetscCall(PetscLayoutSetUp(is->A->cmap));
2671     PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
2672     PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
2673     PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2674     /* setup scatters and local vectors for MatMult */
2675     PetscCall(MatISSetUpScatters_Private(A));
2676   }
2677   A->preallocated = PETSC_TRUE;
2678   PetscFunctionReturn(PETSC_SUCCESS);
2679 }
2680 
2681 static PetscErrorCode MatSetUp_IS(Mat A)
2682 {
2683   Mat_IS                *is = (Mat_IS *)A->data;
2684   ISLocalToGlobalMapping rmap, cmap;
2685 
2686   PetscFunctionBegin;
2687   if (!is->sf) {
2688     PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
2689     PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
2690   }
2691   PetscFunctionReturn(PETSC_SUCCESS);
2692 }
2693 
2694 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2695 {
2696   Mat_IS  *is = (Mat_IS *)mat->data;
2697   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
2698 
2699   PetscFunctionBegin;
2700   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2701   if (m != n || rows != cols || is->cmapping != is->rmapping) {
2702     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
2703     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2704   } else {
2705     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2706   }
2707   PetscFunctionReturn(PETSC_SUCCESS);
2708 }
2709 
2710 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2711 {
2712   Mat_IS  *is = (Mat_IS *)mat->data;
2713   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
2714 
2715   PetscFunctionBegin;
2716   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2717   if (m != n || rows != cols || is->cmapping != is->rmapping) {
2718     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
2719     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2720   } else {
2721     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2722   }
2723   PetscFunctionReturn(PETSC_SUCCESS);
2724 }
2725 
2726 static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2727 {
2728   Mat_IS *is = (Mat_IS *)A->data;
2729 
2730   PetscFunctionBegin;
2731   if (is->A->rmap->mapping || is->A->cmap->mapping) {
2732     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2733   } else {
2734     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2735   }
2736   PetscFunctionReturn(PETSC_SUCCESS);
2737 }
2738 
2739 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2740 {
2741   Mat_IS *is = (Mat_IS *)A->data;
2742 
2743   PetscFunctionBegin;
2744   if (is->A->rmap->mapping || is->A->cmap->mapping) {
2745     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2746   } else {
2747     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2748   }
2749   PetscFunctionReturn(PETSC_SUCCESS);
2750 }
2751 
2752 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2753 {
2754   Mat_IS *is = (Mat_IS *)A->data;
2755 
2756   PetscFunctionBegin;
2757   if (!n) {
2758     is->pure_neumann = PETSC_TRUE;
2759   } else {
2760     PetscInt i;
2761     is->pure_neumann = PETSC_FALSE;
2762 
2763     if (columns) {
2764       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2765     } else {
2766       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2767     }
2768     if (diag != 0.) {
2769       const PetscScalar *array;
2770       PetscCall(VecGetArrayRead(is->counter, &array));
2771       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
2772       PetscCall(VecRestoreArrayRead(is->counter, &array));
2773     }
2774     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
2775     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2776   }
2777   PetscFunctionReturn(PETSC_SUCCESS);
2778 }
2779 
2780 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2781 {
2782   Mat_IS   *matis = (Mat_IS *)A->data;
2783   PetscInt  nr, nl, len, i;
2784   PetscInt *lrows;
2785 
2786   PetscFunctionBegin;
2787   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2788     PetscBool cong;
2789 
2790     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
2791     cong = (PetscBool)(cong && matis->sf == matis->csf);
2792     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");
2793     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");
2794     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");
2795   }
2796   /* get locally owned rows */
2797   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2798   /* fix right-hand side if needed */
2799   if (x && b) {
2800     const PetscScalar *xx;
2801     PetscScalar       *bb;
2802 
2803     PetscCall(VecGetArrayRead(x, &xx));
2804     PetscCall(VecGetArray(b, &bb));
2805     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
2806     PetscCall(VecRestoreArrayRead(x, &xx));
2807     PetscCall(VecRestoreArray(b, &bb));
2808   }
2809   /* get rows associated to the local matrices */
2810   PetscCall(MatGetSize(matis->A, &nl, NULL));
2811   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
2812   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
2813   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
2814   PetscCall(PetscFree(lrows));
2815   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2816   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2817   PetscCall(PetscMalloc1(nl, &lrows));
2818   for (i = 0, nr = 0; i < nl; i++)
2819     if (matis->sf_leafdata[i]) lrows[nr++] = i;
2820   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
2821   PetscCall(PetscFree(lrows));
2822   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2823   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2824   PetscFunctionReturn(PETSC_SUCCESS);
2825 }
2826 
2827 static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2828 {
2829   PetscFunctionBegin;
2830   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
2831   PetscFunctionReturn(PETSC_SUCCESS);
2832 }
2833 
2834 static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2835 {
2836   PetscFunctionBegin;
2837   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
2838   PetscFunctionReturn(PETSC_SUCCESS);
2839 }
2840 
2841 static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
2842 {
2843   Mat_IS *is = (Mat_IS *)A->data;
2844 
2845   PetscFunctionBegin;
2846   PetscCall(MatAssemblyBegin(is->A, type));
2847   PetscFunctionReturn(PETSC_SUCCESS);
2848 }
2849 
2850 static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
2851 {
2852   Mat_IS   *is = (Mat_IS *)A->data;
2853   PetscBool lnnz;
2854 
2855   PetscFunctionBegin;
2856   PetscCall(MatAssemblyEnd(is->A, type));
2857   /* fix for local empty rows/cols */
2858   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2859     Mat                    newlA;
2860     ISLocalToGlobalMapping rl2g, cl2g;
2861     IS                     nzr, nzc;
2862     PetscInt               nr, nc, nnzr, nnzc;
2863     PetscBool              lnewl2g, newl2g;
2864 
2865     PetscCall(MatGetSize(is->A, &nr, &nc));
2866     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
2867     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
2868     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
2869     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
2870     PetscCall(ISGetSize(nzr, &nnzr));
2871     PetscCall(ISGetSize(nzc, &nnzc));
2872     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
2873       lnewl2g = PETSC_TRUE;
2874       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2875 
2876       /* extract valid submatrix */
2877       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
2878     } else { /* local matrix fully populated */
2879       lnewl2g = PETSC_FALSE;
2880       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2881       PetscCall(PetscObjectReference((PetscObject)is->A));
2882       newlA = is->A;
2883     }
2884 
2885     /* attach new global l2g map if needed */
2886     if (newl2g) {
2887       IS              zr, zc;
2888       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
2889       PetscInt       *nidxs, i;
2890 
2891       PetscCall(ISComplement(nzr, 0, nr, &zr));
2892       PetscCall(ISComplement(nzc, 0, nc, &zc));
2893       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
2894       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
2895       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
2896       PetscCall(ISGetIndices(zr, &zridxs));
2897       PetscCall(ISGetIndices(zc, &zcidxs));
2898       PetscCall(ISGetLocalSize(zr, &nnzr));
2899       PetscCall(ISGetLocalSize(zc, &nnzc));
2900 
2901       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
2902       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
2903       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
2904       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
2905       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
2906       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
2907 
2908       PetscCall(ISRestoreIndices(zr, &zridxs));
2909       PetscCall(ISRestoreIndices(zc, &zcidxs));
2910       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
2911       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
2912       PetscCall(ISDestroy(&nzr));
2913       PetscCall(ISDestroy(&nzc));
2914       PetscCall(ISDestroy(&zr));
2915       PetscCall(ISDestroy(&zc));
2916       PetscCall(PetscFree(nidxs));
2917       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
2918       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
2919       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
2920     }
2921     PetscCall(MatISSetLocalMat(A, newlA));
2922     PetscCall(MatDestroy(&newlA));
2923     PetscCall(ISDestroy(&nzr));
2924     PetscCall(ISDestroy(&nzc));
2925     is->locempty = PETSC_FALSE;
2926   }
2927   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
2928   is->lnnzstate = is->A->nonzerostate;
2929   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2930   if (!lnnz) A->nonzerostate++;
2931   PetscFunctionReturn(PETSC_SUCCESS);
2932 }
2933 
2934 static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
2935 {
2936   Mat_IS *is = (Mat_IS *)mat->data;
2937 
2938   PetscFunctionBegin;
2939   *local = is->A;
2940   PetscFunctionReturn(PETSC_SUCCESS);
2941 }
2942 
2943 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
2944 {
2945   PetscFunctionBegin;
2946   *local = NULL;
2947   PetscFunctionReturn(PETSC_SUCCESS);
2948 }
2949 
2950 /*@
2951   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
2952 
2953   Not Collective.
2954 
2955   Input Parameter:
2956 . mat - the matrix
2957 
2958   Output Parameter:
2959 . local - the local matrix
2960 
2961   Level: intermediate
2962 
2963   Notes:
2964   This can be called if you have precomputed the nonzero structure of the
2965   matrix and want to provide it to the inner matrix object to improve the performance
2966   of the `MatSetValues()` operation.
2967 
2968   Call `MatISRestoreLocalMat()` when finished with the local matrix.
2969 
2970 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
2971 @*/
2972 PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
2973 {
2974   PetscFunctionBegin;
2975   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2976   PetscAssertPointer(local, 2);
2977   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
2978   PetscFunctionReturn(PETSC_SUCCESS);
2979 }
2980 
2981 /*@
2982   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
2983 
2984   Not Collective.
2985 
2986   Input Parameters:
2987 + mat   - the matrix
2988 - local - the local matrix
2989 
2990   Level: intermediate
2991 
2992 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
2993 @*/
2994 PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
2995 {
2996   PetscFunctionBegin;
2997   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2998   PetscAssertPointer(local, 2);
2999   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
3000   PetscFunctionReturn(PETSC_SUCCESS);
3001 }
3002 
3003 static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3004 {
3005   Mat_IS *is = (Mat_IS *)mat->data;
3006 
3007   PetscFunctionBegin;
3008   if (is->A) PetscCall(MatSetType(is->A, mtype));
3009   PetscCall(PetscFree(is->lmattype));
3010   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
3011   PetscFunctionReturn(PETSC_SUCCESS);
3012 }
3013 
3014 /*@
3015   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
3016 
3017   Logically Collective.
3018 
3019   Input Parameters:
3020 + mat   - the matrix
3021 - mtype - the local matrix type
3022 
3023   Level: intermediate
3024 
3025 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
3026 @*/
3027 PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3028 {
3029   PetscFunctionBegin;
3030   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3031   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
3032   PetscFunctionReturn(PETSC_SUCCESS);
3033 }
3034 
3035 static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3036 {
3037   Mat_IS   *is = (Mat_IS *)mat->data;
3038   PetscInt  nrows, ncols, orows, ocols;
3039   MatType   mtype, otype;
3040   PetscBool sametype = PETSC_TRUE;
3041 
3042   PetscFunctionBegin;
3043   if (is->A && !is->islocalref) {
3044     PetscCall(MatGetSize(is->A, &orows, &ocols));
3045     PetscCall(MatGetSize(local, &nrows, &ncols));
3046     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);
3047     PetscCall(MatGetType(local, &mtype));
3048     PetscCall(MatGetType(is->A, &otype));
3049     PetscCall(PetscStrcmp(mtype, otype, &sametype));
3050   }
3051   PetscCall(PetscObjectReference((PetscObject)local));
3052   PetscCall(MatDestroy(&is->A));
3053   is->A = local;
3054   PetscCall(MatGetType(is->A, &mtype));
3055   PetscCall(MatISSetLocalMatType(mat, mtype));
3056   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
3057   is->lnnzstate = 0;
3058   PetscFunctionReturn(PETSC_SUCCESS);
3059 }
3060 
3061 /*@
3062   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
3063 
3064   Not Collective
3065 
3066   Input Parameters:
3067 + mat   - the matrix
3068 - local - the local matrix
3069 
3070   Level: intermediate
3071 
3072 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
3073 @*/
3074 PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3075 {
3076   PetscFunctionBegin;
3077   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3078   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3079   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
3080   PetscFunctionReturn(PETSC_SUCCESS);
3081 }
3082 
3083 static PetscErrorCode MatZeroEntries_IS(Mat A)
3084 {
3085   Mat_IS *a = (Mat_IS *)A->data;
3086 
3087   PetscFunctionBegin;
3088   PetscCall(MatZeroEntries(a->A));
3089   PetscFunctionReturn(PETSC_SUCCESS);
3090 }
3091 
3092 static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3093 {
3094   Mat_IS *is = (Mat_IS *)A->data;
3095 
3096   PetscFunctionBegin;
3097   PetscCall(MatScale(is->A, a));
3098   PetscFunctionReturn(PETSC_SUCCESS);
3099 }
3100 
3101 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3102 {
3103   Mat_IS *is = (Mat_IS *)A->data;
3104 
3105   PetscFunctionBegin;
3106   /* get diagonal of the local matrix */
3107   PetscCall(MatGetDiagonal(is->A, is->y));
3108 
3109   /* scatter diagonal back into global vector */
3110   PetscCall(VecSet(v, 0));
3111   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
3112   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
3113   PetscFunctionReturn(PETSC_SUCCESS);
3114 }
3115 
3116 static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3117 {
3118   Mat_IS *a = (Mat_IS *)A->data;
3119 
3120   PetscFunctionBegin;
3121   PetscCall(MatSetOption(a->A, op, flg));
3122   PetscFunctionReturn(PETSC_SUCCESS);
3123 }
3124 
3125 static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3126 {
3127   Mat_IS *y = (Mat_IS *)Y->data;
3128   Mat_IS *x;
3129 
3130   PetscFunctionBegin;
3131   if (PetscDefined(USE_DEBUG)) {
3132     PetscBool ismatis;
3133     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
3134     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
3135   }
3136   x = (Mat_IS *)X->data;
3137   PetscCall(MatAXPY(y->A, a, x->A, str));
3138   PetscFunctionReturn(PETSC_SUCCESS);
3139 }
3140 
3141 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3142 {
3143   Mat                    lA;
3144   Mat_IS                *matis = (Mat_IS *)A->data;
3145   ISLocalToGlobalMapping rl2g, cl2g;
3146   IS                     is;
3147   const PetscInt        *rg, *rl;
3148   PetscInt               nrg;
3149   PetscInt               N, M, nrl, i, *idxs;
3150 
3151   PetscFunctionBegin;
3152   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
3153   PetscCall(ISGetLocalSize(row, &nrl));
3154   PetscCall(ISGetIndices(row, &rl));
3155   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
3156   if (PetscDefined(USE_DEBUG)) {
3157     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);
3158   }
3159   PetscCall(PetscMalloc1(nrg, &idxs));
3160   /* map from [0,nrl) to row */
3161   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3162   for (i = nrl; i < nrg; i++) idxs[i] = -1;
3163   PetscCall(ISRestoreIndices(row, &rl));
3164   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
3165   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
3166   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3167   PetscCall(ISDestroy(&is));
3168   /* compute new l2g map for columns */
3169   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3170     const PetscInt *cg, *cl;
3171     PetscInt        ncg;
3172     PetscInt        ncl;
3173 
3174     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
3175     PetscCall(ISGetLocalSize(col, &ncl));
3176     PetscCall(ISGetIndices(col, &cl));
3177     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
3178     if (PetscDefined(USE_DEBUG)) {
3179       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);
3180     }
3181     PetscCall(PetscMalloc1(ncg, &idxs));
3182     /* map from [0,ncl) to col */
3183     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3184     for (i = ncl; i < ncg; i++) idxs[i] = -1;
3185     PetscCall(ISRestoreIndices(col, &cl));
3186     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
3187     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
3188     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3189     PetscCall(ISDestroy(&is));
3190   } else {
3191     PetscCall(PetscObjectReference((PetscObject)rl2g));
3192     cl2g = rl2g;
3193   }
3194   /* create the MATIS submatrix */
3195   PetscCall(MatGetSize(A, &M, &N));
3196   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
3197   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
3198   PetscCall(MatSetType(*submat, MATIS));
3199   matis             = (Mat_IS *)((*submat)->data);
3200   matis->islocalref = PETSC_TRUE;
3201   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
3202   PetscCall(MatISGetLocalMat(A, &lA));
3203   PetscCall(MatISSetLocalMat(*submat, lA));
3204   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3205   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3206 
3207   /* remove unsupported ops */
3208   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3209   (*submat)->ops->destroy               = MatDestroy_IS;
3210   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3211   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3212   (*submat)->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_IS;
3213   PetscFunctionReturn(PETSC_SUCCESS);
3214 }
3215 
3216 static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject)
3217 {
3218   Mat_IS   *a = (Mat_IS *)A->data;
3219   char      type[256];
3220   PetscBool flg;
3221 
3222   PetscFunctionBegin;
3223   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3224   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
3225   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
3226   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
3227   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
3228   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
3229   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
3230   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
3231   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
3232   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
3233   if (flg) PetscCall(MatISSetLocalMatType(A, type));
3234   if (a->A) PetscCall(MatSetFromOptions(a->A));
3235   PetscOptionsHeadEnd();
3236   PetscFunctionReturn(PETSC_SUCCESS);
3237 }
3238 
3239 /*@
3240   MatCreateIS - Creates a "process" unassembled matrix.
3241 
3242   Collective.
3243 
3244   Input Parameters:
3245 + comm - MPI communicator that will share the matrix
3246 . bs   - block size of the matrix
3247 . m    - local size of left vector used in matrix vector products
3248 . n    - local size of right vector used in matrix vector products
3249 . M    - global size of left vector used in matrix vector products
3250 . N    - global size of right vector used in matrix vector products
3251 . rmap - local to global map for rows
3252 - cmap - local to global map for cols
3253 
3254   Output Parameter:
3255 . A - the resulting matrix
3256 
3257   Level: intermediate
3258 
3259   Notes:
3260   `m` and `n` are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
3261   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
3262 
3263   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3264 
3265 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3266 @*/
3267 PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3268 {
3269   PetscFunctionBegin;
3270   PetscCall(MatCreate(comm, A));
3271   PetscCall(MatSetSizes(*A, m, n, M, N));
3272   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
3273   PetscCall(MatSetType(*A, MATIS));
3274   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
3275   PetscFunctionReturn(PETSC_SUCCESS);
3276 }
3277 
3278 static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3279 {
3280   Mat_IS      *a              = (Mat_IS *)A->data;
3281   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
3282 
3283   PetscFunctionBegin;
3284   *has = PETSC_FALSE;
3285   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3286   *has = PETSC_TRUE;
3287   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
3288     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
3289   PetscCall(MatHasOperation(a->A, op, has));
3290   PetscFunctionReturn(PETSC_SUCCESS);
3291 }
3292 
3293 static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3294 {
3295   Mat_IS *a = (Mat_IS *)A->data;
3296 
3297   PetscFunctionBegin;
3298   PetscCall(MatSetValuesCOO(a->A, v, imode));
3299   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
3300   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3301   PetscFunctionReturn(PETSC_SUCCESS);
3302 }
3303 
3304 static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3305 {
3306   Mat_IS *a = (Mat_IS *)A->data;
3307 
3308   PetscFunctionBegin;
3309   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3310   if (a->A->rmap->mapping || a->A->cmap->mapping) {
3311     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3312   } else {
3313     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3314   }
3315   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3316   A->preallocated = PETSC_TRUE;
3317   PetscFunctionReturn(PETSC_SUCCESS);
3318 }
3319 
3320 static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3321 {
3322   Mat_IS  *a = (Mat_IS *)A->data;
3323   PetscInt ncoo_i;
3324 
3325   PetscFunctionBegin;
3326   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3327   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3328   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3329   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3330   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3331   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3332   A->preallocated = PETSC_TRUE;
3333   PetscFunctionReturn(PETSC_SUCCESS);
3334 }
3335 
3336 static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3337 {
3338   Mat_IS          *a = (Mat_IS *)A->data;
3339   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
3340   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3341 
3342   PetscFunctionBegin;
3343   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3344   Annzstate = A->nonzerostate;
3345   if (a->assembledA) {
3346     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3347     aAnnzstate = a->assembledA->nonzerostate;
3348   }
3349   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3350   if (Astate != aAstate || !a->assembledA) {
3351     MatType     aAtype;
3352     PetscMPIInt size;
3353     PetscInt    rbs, cbs, bs;
3354 
3355     /* the assembled form is used as temporary storage for parallel operations
3356        like createsubmatrices and the like, do not waste device memory */
3357     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3358     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3359     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3360     bs = rbs == cbs ? rbs : 1;
3361     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3362     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3363     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3364 
3365     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3366     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3367     a->assembledA->nonzerostate = Annzstate;
3368   }
3369   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3370   *tA = a->assembledA;
3371   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
3372   PetscFunctionReturn(PETSC_SUCCESS);
3373 }
3374 
3375 static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3376 {
3377   PetscFunctionBegin;
3378   PetscCall(MatDestroy(tA));
3379   *tA = NULL;
3380   PetscFunctionReturn(PETSC_SUCCESS);
3381 }
3382 
3383 static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3384 {
3385   Mat_IS          *a = (Mat_IS *)A->data;
3386   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3387 
3388   PetscFunctionBegin;
3389   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3390   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3391   if (Astate != dAstate) {
3392     Mat     tA;
3393     MatType ltype;
3394 
3395     PetscCall(MatDestroy(&a->dA));
3396     PetscCall(MatISGetAssembled_Private(A, &tA));
3397     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3398     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3399     PetscCall(MatGetType(a->A, &ltype));
3400     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3401     PetscCall(PetscObjectReference((PetscObject)a->dA));
3402     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3403     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3404   }
3405   *dA = a->dA;
3406   PetscFunctionReturn(PETSC_SUCCESS);
3407 }
3408 
3409 static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3410 {
3411   Mat tA;
3412 
3413   PetscFunctionBegin;
3414   PetscCall(MatISGetAssembled_Private(A, &tA));
3415   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3416   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3417 #if 0
3418   {
3419     Mat_IS    *a = (Mat_IS*)A->data;
3420     MatType   ltype;
3421     VecType   vtype;
3422     char      *flg;
3423 
3424     PetscCall(MatGetType(a->A,&ltype));
3425     PetscCall(MatGetVecType(a->A,&vtype));
3426     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3427     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3428     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3429     if (flg) {
3430       for (PetscInt i = 0; i < n; i++) {
3431         Mat sA = (*submat)[i];
3432 
3433         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3434         (*submat)[i] = sA;
3435       }
3436     }
3437   }
3438 #endif
3439   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3440   PetscFunctionReturn(PETSC_SUCCESS);
3441 }
3442 
3443 static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3444 {
3445   Mat tA;
3446 
3447   PetscFunctionBegin;
3448   PetscCall(MatISGetAssembled_Private(A, &tA));
3449   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3450   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3451   PetscFunctionReturn(PETSC_SUCCESS);
3452 }
3453 
3454 /*@
3455   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3456 
3457   Not Collective
3458 
3459   Input Parameter:
3460 . A - the matrix
3461 
3462   Output Parameters:
3463 + rmapping - row mapping
3464 - cmapping - column mapping
3465 
3466   Level: advanced
3467 
3468   Note:
3469   The returned map can be different from the one used to construct the `MATIS` object, since it will not contain negative or repeated indices.
3470 
3471 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3472 @*/
3473 PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3474 {
3475   PetscFunctionBegin;
3476   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3477   PetscValidType(A, 1);
3478   if (rmapping) PetscAssertPointer(rmapping, 2);
3479   if (cmapping) PetscAssertPointer(cmapping, 3);
3480   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
3481   PetscFunctionReturn(PETSC_SUCCESS);
3482 }
3483 
3484 static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3485 {
3486   Mat_IS *a = (Mat_IS *)A->data;
3487 
3488   PetscFunctionBegin;
3489   if (r) *r = a->rmapping;
3490   if (c) *c = a->cmapping;
3491   PetscFunctionReturn(PETSC_SUCCESS);
3492 }
3493 
3494 static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3495 {
3496   Mat_IS *a = (Mat_IS *)A->data;
3497 
3498   PetscFunctionBegin;
3499   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3500   PetscFunctionReturn(PETSC_SUCCESS);
3501 }
3502 
3503 /*MC
3504   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
3505   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3506 
3507   Options Database Keys:
3508 + -mat_type is           - Set the matrix type to `MATIS`.
3509 . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
3510 . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
3511 - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
3512 
3513   Level: intermediate
3514 
3515   Notes:
3516   Options prefix for the inner matrix are given by `-is_mat_xxx`
3517 
3518   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3519 
3520   You can do matrix preallocation on the local matrix after you obtain it with
3521   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3522 
3523 .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3524 M*/
3525 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3526 {
3527   Mat_IS *a;
3528 
3529   PetscFunctionBegin;
3530   PetscCall(PetscNew(&a));
3531   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3532   A->data = (void *)a;
3533 
3534   /* matrix ops */
3535   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3536   A->ops->mult                    = MatMult_IS;
3537   A->ops->multadd                 = MatMultAdd_IS;
3538   A->ops->multtranspose           = MatMultTranspose_IS;
3539   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3540   A->ops->destroy                 = MatDestroy_IS;
3541   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3542   A->ops->setvalues               = MatSetValues_IS;
3543   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3544   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3545   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
3546   A->ops->zerorows                = MatZeroRows_IS;
3547   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3548   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3549   A->ops->assemblyend             = MatAssemblyEnd_IS;
3550   A->ops->view                    = MatView_IS;
3551   A->ops->load                    = MatLoad_IS;
3552   A->ops->zeroentries             = MatZeroEntries_IS;
3553   A->ops->scale                   = MatScale_IS;
3554   A->ops->getdiagonal             = MatGetDiagonal_IS;
3555   A->ops->setoption               = MatSetOption_IS;
3556   A->ops->ishermitian             = MatIsHermitian_IS;
3557   A->ops->issymmetric             = MatIsSymmetric_IS;
3558   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3559   A->ops->duplicate               = MatDuplicate_IS;
3560   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
3561   A->ops->copy                    = MatCopy_IS;
3562   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
3563   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3564   A->ops->axpy                    = MatAXPY_IS;
3565   A->ops->diagonalset             = MatDiagonalSet_IS;
3566   A->ops->shift                   = MatShift_IS;
3567   A->ops->transpose               = MatTranspose_IS;
3568   A->ops->getinfo                 = MatGetInfo_IS;
3569   A->ops->diagonalscale           = MatDiagonalScale_IS;
3570   A->ops->setfromoptions          = MatSetFromOptions_IS;
3571   A->ops->setup                   = MatSetUp_IS;
3572   A->ops->hasoperation            = MatHasOperation_IS;
3573   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3574   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3575   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3576   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3577 
3578   /* special MATIS functions */
3579   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
3580   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
3581   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
3582   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
3583   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
3584   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
3585   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
3586   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
3587   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
3588   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
3589   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
3590   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
3591   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
3592   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
3593   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
3594   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
3595   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
3596   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
3597   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
3598   PetscFunctionReturn(PETSC_SUCCESS);
3599 }
3600