xref: /petsc/src/mat/impls/is/matis.c (revision e91c04dfc8a52dee1965211bb1cc8e5bf775178f)
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) {
797     PetscCall(MatHeaderReplace(A, &B));
798   } else *newmat = B;
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat)
803 {
804   Mat                  **nest, *snest, **rnest, lA, B;
805   IS                    *iscol, *isrow, *islrow, *islcol;
806   ISLocalToGlobalMapping rl2g, cl2g;
807   MPI_Comm               comm;
808   PetscInt              *lr, *lc, *l2gidxs;
809   PetscInt               i, j, nr, nc, rbs, cbs;
810   PetscBool              convert, lreuse, *istrans;
811   PetscBool3             allow_repeated = PETSC_BOOL3_UNKNOWN;
812 
813   PetscFunctionBegin;
814   PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest));
815   lreuse = PETSC_FALSE;
816   rnest  = NULL;
817   if (reuse == MAT_REUSE_MATRIX) {
818     PetscBool ismatis, isnest;
819 
820     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
821     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name);
822     PetscCall(MatISGetLocalMat(*newmat, &lA));
823     PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest));
824     if (isnest) {
825       PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest));
826       lreuse = (PetscBool)(i == nr && j == nc);
827       if (!lreuse) rnest = NULL;
828     }
829   }
830   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
831   PetscCall(PetscCalloc2(nr, &lr, nc, &lc));
832   PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans));
833   PetscCall(MatNestGetISs(A, isrow, iscol));
834   for (i = 0; i < nr; i++) {
835     for (j = 0; j < nc; j++) {
836       PetscBool ismatis, sallow;
837       PetscInt  l1, l2, lb1, lb2, ij = i * nc + j;
838 
839       /* Null matrix pointers are allowed in MATNEST */
840       if (!nest[i][j]) continue;
841 
842       /* Nested matrices should be of type MATIS */
843       PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij]));
844       if (istrans[ij]) {
845         Mat T, lT;
846         PetscCall(MatTransposeGetMat(nest[i][j], &T));
847         PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis));
848         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);
849         PetscCall(MatISGetAllowRepeated(T, &sallow));
850         PetscCall(MatISGetLocalMat(T, &lT));
851         PetscCall(MatCreateTranspose(lT, &snest[ij]));
852       } else {
853         PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis));
854         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);
855         PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow));
856         PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij]));
857       }
858       if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow);
859       PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps");
860 
861       /* Check compatibility of local sizes */
862       PetscCall(MatGetSize(snest[ij], &l1, &l2));
863       PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2));
864       if (!l1 || !l2) continue;
865       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);
866       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);
867       lr[i] = l1;
868       lc[j] = l2;
869 
870       /* check compatibility for local matrix reusage */
871       if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
872     }
873   }
874 
875   if (PetscDefined(USE_DEBUG)) {
876     /* Check compatibility of l2g maps for rows */
877     for (i = 0; i < nr; i++) {
878       rl2g = NULL;
879       for (j = 0; j < nc; j++) {
880         PetscInt n1, n2;
881 
882         if (!nest[i][j]) continue;
883         if (istrans[i * nc + j]) {
884           Mat T;
885 
886           PetscCall(MatTransposeGetMat(nest[i][j], &T));
887           PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g));
888         } else {
889           PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL));
890         }
891         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
892         if (!n1) continue;
893         if (!rl2g) {
894           rl2g = cl2g;
895         } else {
896           const PetscInt *idxs1, *idxs2;
897           PetscBool       same;
898 
899           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
900           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);
901           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
902           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
903           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
904           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
905           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
906           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);
907         }
908       }
909     }
910     /* Check compatibility of l2g maps for columns */
911     for (i = 0; i < nc; i++) {
912       rl2g = NULL;
913       for (j = 0; j < nr; j++) {
914         PetscInt n1, n2;
915 
916         if (!nest[j][i]) continue;
917         if (istrans[j * nc + i]) {
918           Mat T;
919 
920           PetscCall(MatTransposeGetMat(nest[j][i], &T));
921           PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL));
922         } else {
923           PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g));
924         }
925         PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1));
926         if (!n1) continue;
927         if (!rl2g) {
928           rl2g = cl2g;
929         } else {
930           const PetscInt *idxs1, *idxs2;
931           PetscBool       same;
932 
933           PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2));
934           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);
935           PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1));
936           PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2));
937           PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same));
938           PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1));
939           PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2));
940           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);
941         }
942       }
943     }
944   }
945 
946   B = NULL;
947   if (reuse != MAT_REUSE_MATRIX) {
948     PetscInt stl;
949 
950     /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
951     for (i = 0, stl = 0; i < nr; i++) stl += lr[i];
952     PetscCall(PetscMalloc1(stl, &l2gidxs));
953     for (i = 0, stl = 0; i < nr; i++) {
954       Mat             usedmat;
955       Mat_IS         *matis;
956       const PetscInt *idxs;
957 
958       /* local IS for local NEST */
959       PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
960 
961       /* l2gmap */
962       j       = 0;
963       usedmat = nest[i][j];
964       while (!usedmat && j < nc - 1) usedmat = nest[i][++j];
965       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat");
966 
967       if (istrans[i * nc + j]) {
968         Mat T;
969         PetscCall(MatTransposeGetMat(usedmat, &T));
970         usedmat = T;
971       }
972       matis = (Mat_IS *)usedmat->data;
973       PetscCall(ISGetIndices(isrow[i], &idxs));
974       if (istrans[i * nc + j]) {
975         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
976         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
977       } else {
978         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
979         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
980       }
981       PetscCall(ISRestoreIndices(isrow[i], &idxs));
982       stl += lr[i];
983     }
984     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g));
985 
986     /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
987     for (i = 0, stl = 0; i < nc; i++) stl += lc[i];
988     PetscCall(PetscMalloc1(stl, &l2gidxs));
989     for (i = 0, stl = 0; i < nc; i++) {
990       Mat             usedmat;
991       Mat_IS         *matis;
992       const PetscInt *idxs;
993 
994       /* local IS for local NEST */
995       PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
996 
997       /* l2gmap */
998       j       = 0;
999       usedmat = nest[j][i];
1000       while (!usedmat && j < nr - 1) usedmat = nest[++j][i];
1001       PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat");
1002       if (istrans[j * nc + i]) {
1003         Mat T;
1004         PetscCall(MatTransposeGetMat(usedmat, &T));
1005         usedmat = T;
1006       }
1007       matis = (Mat_IS *)usedmat->data;
1008       PetscCall(ISGetIndices(iscol[i], &idxs));
1009       if (istrans[j * nc + i]) {
1010         PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1011         PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1012       } else {
1013         PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1014         PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE));
1015       }
1016       PetscCall(ISRestoreIndices(iscol[i], &idxs));
1017       stl += lc[i];
1018     }
1019     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g));
1020 
1021     /* Create MATIS */
1022     PetscCall(MatCreate(comm, &B));
1023     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
1024     PetscCall(MatGetBlockSizes(A, &rbs, &cbs));
1025     PetscCall(MatSetBlockSizes(B, rbs, cbs));
1026     PetscCall(MatSetType(B, MATIS));
1027     PetscCall(MatISSetLocalMatType(B, MATNEST));
1028     PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated)));
1029     { /* hack : avoid setup of scatters */
1030       Mat_IS *matis     = (Mat_IS *)B->data;
1031       matis->islocalref = PETSC_TRUE;
1032     }
1033     PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g));
1034     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1035     PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1036     PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1037     PetscCall(MatNestSetVecType(lA, VECNEST));
1038     for (i = 0; i < nr * nc; i++) {
1039       if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1040     }
1041     PetscCall(MatISSetLocalMat(B, lA));
1042     PetscCall(MatDestroy(&lA));
1043     { /* hack : setup of scatters done here */
1044       Mat_IS *matis = (Mat_IS *)B->data;
1045 
1046       matis->islocalref = PETSC_FALSE;
1047       PetscCall(MatISSetUpScatters_Private(B));
1048     }
1049     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1050     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1051     if (reuse == MAT_INPLACE_MATRIX) {
1052       PetscCall(MatHeaderReplace(A, &B));
1053     } else {
1054       *newmat = B;
1055     }
1056   } else {
1057     if (lreuse) {
1058       PetscCall(MatISGetLocalMat(*newmat, &lA));
1059       for (i = 0; i < nr; i++) {
1060         for (j = 0; j < nc; j++) {
1061           if (snest[i * nc + j]) {
1062             PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j]));
1063             if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j]));
1064           }
1065         }
1066       }
1067     } else {
1068       PetscInt stl;
1069       for (i = 0, stl = 0; i < nr; i++) {
1070         PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i]));
1071         stl += lr[i];
1072       }
1073       for (i = 0, stl = 0; i < nc; i++) {
1074         PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i]));
1075         stl += lc[i];
1076       }
1077       PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA));
1078       for (i = 0; i < nr * nc; i++) {
1079         if (istrans[i]) PetscCall(MatDestroy(&snest[i]));
1080       }
1081       PetscCall(MatISSetLocalMat(*newmat, lA));
1082       PetscCall(MatDestroy(&lA));
1083     }
1084     PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1085     PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1086   }
1087 
1088   /* Create local matrix in MATNEST format */
1089   convert = PETSC_FALSE;
1090   PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL));
1091   if (convert) {
1092     Mat              M;
1093     MatISLocalFields lf;
1094 
1095     PetscCall(MatISGetLocalMat(*newmat, &lA));
1096     PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M));
1097     PetscCall(MatISSetLocalMat(*newmat, M));
1098     PetscCall(MatDestroy(&M));
1099 
1100     /* attach local fields to the matrix */
1101     PetscCall(PetscNew(&lf));
1102     PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf));
1103     for (i = 0; i < nr; i++) {
1104       PetscInt n, st;
1105 
1106       PetscCall(ISGetLocalSize(islrow[i], &n));
1107       PetscCall(ISStrideGetInfo(islrow[i], &st, NULL));
1108       PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i]));
1109     }
1110     for (i = 0; i < nc; i++) {
1111       PetscInt n, st;
1112 
1113       PetscCall(ISGetLocalSize(islcol[i], &n));
1114       PetscCall(ISStrideGetInfo(islcol[i], &st, NULL));
1115       PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i]));
1116     }
1117     lf->nr = nr;
1118     lf->nc = nc;
1119     PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private));
1120   }
1121 
1122   /* Free workspace */
1123   for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i]));
1124   for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i]));
1125   PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans));
1126   PetscCall(PetscFree2(lr, lc));
1127   PetscFunctionReturn(PETSC_SUCCESS);
1128 }
1129 
1130 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1131 {
1132   Mat_IS            *matis = (Mat_IS *)A->data;
1133   Vec                ll, rr;
1134   const PetscScalar *Y, *X;
1135   PetscScalar       *x, *y;
1136 
1137   PetscFunctionBegin;
1138   if (l) {
1139     ll = matis->y;
1140     PetscCall(VecGetArrayRead(l, &Y));
1141     PetscCall(VecGetArray(ll, &y));
1142     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1143   } else {
1144     ll = NULL;
1145   }
1146   if (r) {
1147     rr = matis->x;
1148     PetscCall(VecGetArrayRead(r, &X));
1149     PetscCall(VecGetArray(rr, &x));
1150     PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1151   } else {
1152     rr = NULL;
1153   }
1154   if (ll) {
1155     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE));
1156     PetscCall(VecRestoreArrayRead(l, &Y));
1157     PetscCall(VecRestoreArray(ll, &y));
1158   }
1159   if (rr) {
1160     PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE));
1161     PetscCall(VecRestoreArrayRead(r, &X));
1162     PetscCall(VecRestoreArray(rr, &x));
1163   }
1164   PetscCall(MatDiagonalScale(matis->A, ll, rr));
1165   PetscFunctionReturn(PETSC_SUCCESS);
1166 }
1167 
1168 static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo)
1169 {
1170   Mat_IS        *matis = (Mat_IS *)A->data;
1171   MatInfo        info;
1172   PetscLogDouble isend[6], irecv[6];
1173   PetscInt       bs;
1174 
1175   PetscFunctionBegin;
1176   PetscCall(MatGetBlockSize(A, &bs));
1177   if (matis->A->ops->getinfo) {
1178     PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info));
1179     isend[0] = info.nz_used;
1180     isend[1] = info.nz_allocated;
1181     isend[2] = info.nz_unneeded;
1182     isend[3] = info.memory;
1183     isend[4] = info.mallocs;
1184   } else {
1185     isend[0] = 0.;
1186     isend[1] = 0.;
1187     isend[2] = 0.;
1188     isend[3] = 0.;
1189     isend[4] = 0.;
1190   }
1191   isend[5] = matis->A->num_ass;
1192   if (flag == MAT_LOCAL) {
1193     ginfo->nz_used      = isend[0];
1194     ginfo->nz_allocated = isend[1];
1195     ginfo->nz_unneeded  = isend[2];
1196     ginfo->memory       = isend[3];
1197     ginfo->mallocs      = isend[4];
1198     ginfo->assemblies   = isend[5];
1199   } else if (flag == MAT_GLOBAL_MAX) {
1200     PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
1201 
1202     ginfo->nz_used      = irecv[0];
1203     ginfo->nz_allocated = irecv[1];
1204     ginfo->nz_unneeded  = irecv[2];
1205     ginfo->memory       = irecv[3];
1206     ginfo->mallocs      = irecv[4];
1207     ginfo->assemblies   = irecv[5];
1208   } else if (flag == MAT_GLOBAL_SUM) {
1209     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
1210 
1211     ginfo->nz_used      = irecv[0];
1212     ginfo->nz_allocated = irecv[1];
1213     ginfo->nz_unneeded  = irecv[2];
1214     ginfo->memory       = irecv[3];
1215     ginfo->mallocs      = irecv[4];
1216     ginfo->assemblies   = A->num_ass;
1217   }
1218   ginfo->block_size        = bs;
1219   ginfo->fill_ratio_given  = 0;
1220   ginfo->fill_ratio_needed = 0;
1221   ginfo->factor_mallocs    = 0;
1222   PetscFunctionReturn(PETSC_SUCCESS);
1223 }
1224 
1225 static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B)
1226 {
1227   Mat C, lC, lA;
1228 
1229   PetscFunctionBegin;
1230   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
1231   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1232     ISLocalToGlobalMapping rl2g, cl2g;
1233     PetscBool              allow_repeated;
1234 
1235     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
1236     PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N));
1237     PetscCall(MatSetBlockSizes(C, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
1238     PetscCall(MatSetType(C, MATIS));
1239     PetscCall(MatISGetAllowRepeated(A, &allow_repeated));
1240     PetscCall(MatISSetAllowRepeated(C, allow_repeated));
1241     PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
1242     PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g));
1243   } else C = *B;
1244 
1245   /* perform local transposition */
1246   PetscCall(MatISGetLocalMat(A, &lA));
1247   PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC));
1248   PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping));
1249   PetscCall(MatISSetLocalMat(C, lC));
1250   PetscCall(MatDestroy(&lC));
1251 
1252   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1253     *B = C;
1254   } else {
1255     PetscCall(MatHeaderMerge(A, &C));
1256   }
1257   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1258   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1259   PetscFunctionReturn(PETSC_SUCCESS);
1260 }
1261 
1262 static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode)
1263 {
1264   Mat_IS *is = (Mat_IS *)A->data;
1265 
1266   PetscFunctionBegin;
1267   PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported");
1268   if (D) { /* MatShift_IS pass D = NULL */
1269     PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
1270     PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD));
1271   }
1272   PetscCall(VecPointwiseDivide(is->y, is->y, is->counter));
1273   PetscCall(MatDiagonalSet(is->A, is->y, insmode));
1274   PetscFunctionReturn(PETSC_SUCCESS);
1275 }
1276 
1277 static PetscErrorCode MatShift_IS(Mat A, PetscScalar a)
1278 {
1279   Mat_IS *is = (Mat_IS *)A->data;
1280 
1281   PetscFunctionBegin;
1282   PetscCall(VecSet(is->y, a));
1283   PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES));
1284   PetscFunctionReturn(PETSC_SUCCESS);
1285 }
1286 
1287 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1288 {
1289   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1290 
1291   PetscFunctionBegin;
1292   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);
1293   PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l));
1294   PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l));
1295   PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1296   PetscFunctionReturn(PETSC_SUCCESS);
1297 }
1298 
1299 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
1300 {
1301   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
1302 
1303   PetscFunctionBegin;
1304   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);
1305   PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping, m, rows, rows_l));
1306   PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping, n, cols, cols_l));
1307   PetscCall(MatSetValuesBlockedLocal_IS(A, m, rows_l, n, cols_l, values, addv));
1308   PetscFunctionReturn(PETSC_SUCCESS);
1309 }
1310 
1311 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat)
1312 {
1313   Mat             locmat, newlocmat;
1314   Mat_IS         *newmatis;
1315   const PetscInt *idxs;
1316   PetscInt        i, m, n;
1317 
1318   PetscFunctionBegin;
1319   if (scall == MAT_REUSE_MATRIX) {
1320     PetscBool ismatis;
1321 
1322     PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis));
1323     PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type");
1324     newmatis = (Mat_IS *)(*newmat)->data;
1325     PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS");
1326     PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS");
1327   }
1328   /* irow and icol may not have duplicate entries */
1329   if (PetscDefined(USE_DEBUG)) {
1330     Vec                rtest, ltest;
1331     const PetscScalar *array;
1332 
1333     PetscCall(MatCreateVecs(mat, &ltest, &rtest));
1334     PetscCall(ISGetLocalSize(irow, &n));
1335     PetscCall(ISGetIndices(irow, &idxs));
1336     for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES));
1337     PetscCall(VecAssemblyBegin(rtest));
1338     PetscCall(VecAssemblyEnd(rtest));
1339     PetscCall(VecGetLocalSize(rtest, &n));
1340     PetscCall(VecGetOwnershipRange(rtest, &m, NULL));
1341     PetscCall(VecGetArrayRead(rtest, &array));
1342     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]));
1343     PetscCall(VecRestoreArrayRead(rtest, &array));
1344     PetscCall(ISRestoreIndices(irow, &idxs));
1345     PetscCall(ISGetLocalSize(icol, &n));
1346     PetscCall(ISGetIndices(icol, &idxs));
1347     for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES));
1348     PetscCall(VecAssemblyBegin(ltest));
1349     PetscCall(VecAssemblyEnd(ltest));
1350     PetscCall(VecGetLocalSize(ltest, &n));
1351     PetscCall(VecGetOwnershipRange(ltest, &m, NULL));
1352     PetscCall(VecGetArrayRead(ltest, &array));
1353     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]));
1354     PetscCall(VecRestoreArrayRead(ltest, &array));
1355     PetscCall(ISRestoreIndices(icol, &idxs));
1356     PetscCall(VecDestroy(&rtest));
1357     PetscCall(VecDestroy(&ltest));
1358   }
1359   if (scall == MAT_INITIAL_MATRIX) {
1360     Mat_IS                *matis = (Mat_IS *)mat->data;
1361     ISLocalToGlobalMapping rl2g;
1362     IS                     is;
1363     PetscInt              *lidxs, *lgidxs, *newgidxs;
1364     PetscInt               ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs;
1365     PetscBool              cong;
1366     MPI_Comm               comm;
1367 
1368     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
1369     PetscCall(MatGetBlockSizes(mat, &arbs, &acbs));
1370     PetscCall(ISGetBlockSize(irow, &irbs));
1371     PetscCall(ISGetBlockSize(icol, &icbs));
1372     rbs = arbs == irbs ? irbs : 1;
1373     cbs = acbs == icbs ? icbs : 1;
1374     PetscCall(ISGetLocalSize(irow, &m));
1375     PetscCall(ISGetLocalSize(icol, &n));
1376     PetscCall(MatCreate(comm, newmat));
1377     PetscCall(MatSetType(*newmat, MATIS));
1378     PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated));
1379     PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE));
1380     PetscCall(MatSetBlockSizes(*newmat, rbs, cbs));
1381     /* communicate irow to their owners in the layout */
1382     PetscCall(ISGetIndices(irow, &idxs));
1383     PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs));
1384     PetscCall(ISRestoreIndices(irow, &idxs));
1385     PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots));
1386     for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1;
1387     PetscCall(PetscFree(lidxs));
1388     PetscCall(PetscFree(lgidxs));
1389     PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1390     PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1391     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1392       if (matis->sf_leafdata[i]) newloc++;
1393     PetscCall(PetscMalloc1(newloc, &newgidxs));
1394     PetscCall(PetscMalloc1(newloc, &lidxs));
1395     for (i = 0, newloc = 0; i < matis->sf->nleaves; i++)
1396       if (matis->sf_leafdata[i]) {
1397         lidxs[newloc]      = i;
1398         newgidxs[newloc++] = matis->sf_leafdata[i] - 1;
1399       }
1400     PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
1401     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
1402     PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs));
1403     PetscCall(ISDestroy(&is));
1404     /* local is to extract local submatrix */
1405     newmatis = (Mat_IS *)(*newmat)->data;
1406     PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris));
1407     PetscCall(MatHasCongruentLayouts(mat, &cong));
1408     if (cong && irow == icol && matis->csf == matis->sf) {
1409       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g));
1410       PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris));
1411       newmatis->getsub_cis = newmatis->getsub_ris;
1412     } else {
1413       ISLocalToGlobalMapping cl2g;
1414 
1415       /* communicate icol to their owners in the layout */
1416       PetscCall(ISGetIndices(icol, &idxs));
1417       PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs));
1418       PetscCall(ISRestoreIndices(icol, &idxs));
1419       PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots));
1420       for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1;
1421       PetscCall(PetscFree(lidxs));
1422       PetscCall(PetscFree(lgidxs));
1423       PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
1424       PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE));
1425       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1426         if (matis->csf_leafdata[i]) newloc++;
1427       PetscCall(PetscMalloc1(newloc, &newgidxs));
1428       PetscCall(PetscMalloc1(newloc, &lidxs));
1429       for (i = 0, newloc = 0; i < matis->csf->nleaves; i++)
1430         if (matis->csf_leafdata[i]) {
1431           lidxs[newloc]      = i;
1432           newgidxs[newloc++] = matis->csf_leafdata[i] - 1;
1433         }
1434       PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is));
1435       PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
1436       PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs));
1437       PetscCall(ISDestroy(&is));
1438       /* local is to extract local submatrix */
1439       PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis));
1440       PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g));
1441       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
1442     }
1443     PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
1444   } else {
1445     PetscCall(MatISGetLocalMat(*newmat, &newlocmat));
1446   }
1447   PetscCall(MatISGetLocalMat(mat, &locmat));
1448   newmatis = (Mat_IS *)(*newmat)->data;
1449   PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat));
1450   if (scall == MAT_INITIAL_MATRIX) {
1451     PetscCall(MatISSetLocalMat(*newmat, newlocmat));
1452     PetscCall(MatDestroy(&newlocmat));
1453   }
1454   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1455   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1456   PetscFunctionReturn(PETSC_SUCCESS);
1457 }
1458 
1459 static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str)
1460 {
1461   Mat_IS   *a = (Mat_IS *)A->data, *b;
1462   PetscBool ismatis;
1463 
1464   PetscFunctionBegin;
1465   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis));
1466   PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented");
1467   b = (Mat_IS *)B->data;
1468   PetscCall(MatCopy(a->A, b->A, str));
1469   PetscCall(PetscObjectStateIncrease((PetscObject)B));
1470   PetscFunctionReturn(PETSC_SUCCESS);
1471 }
1472 
1473 static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d)
1474 {
1475   Vec                v;
1476   const PetscScalar *array;
1477   PetscInt           i, n;
1478 
1479   PetscFunctionBegin;
1480   *missing = PETSC_FALSE;
1481   PetscCall(MatCreateVecs(A, NULL, &v));
1482   PetscCall(MatGetDiagonal(A, v));
1483   PetscCall(VecGetLocalSize(v, &n));
1484   PetscCall(VecGetArrayRead(v, &array));
1485   for (i = 0; i < n; i++)
1486     if (array[i] == 0.) break;
1487   PetscCall(VecRestoreArrayRead(v, &array));
1488   PetscCall(VecDestroy(&v));
1489   if (i != n) *missing = PETSC_TRUE;
1490   if (d) {
1491     *d = -1;
1492     if (*missing) {
1493       PetscInt rstart;
1494       PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
1495       *d = i + rstart;
1496     }
1497   }
1498   PetscFunctionReturn(PETSC_SUCCESS);
1499 }
1500 
1501 static PetscErrorCode MatISSetUpSF_IS(Mat B)
1502 {
1503   Mat_IS         *matis = (Mat_IS *)B->data;
1504   const PetscInt *gidxs;
1505   PetscInt        nleaves;
1506 
1507   PetscFunctionBegin;
1508   if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS);
1509   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf));
1510   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs));
1511   PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves));
1512   PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
1513   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs));
1514   PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata));
1515   if (matis->rmapping != matis->cmapping) { /* setup SF for columns */
1516     PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves));
1517     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf));
1518     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs));
1519     PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
1520     PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs));
1521     PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata));
1522   } else {
1523     matis->csf          = matis->sf;
1524     matis->csf_leafdata = matis->sf_leafdata;
1525     matis->csf_rootdata = matis->sf_rootdata;
1526   }
1527   PetscFunctionReturn(PETSC_SUCCESS);
1528 }
1529 
1530 /*@
1531   MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map
1532 
1533   Not Collective
1534 
1535   Input Parameter:
1536 . A - the matrix
1537 
1538   Output Parameter:
1539 . flg - the boolean flag
1540 
1541   Level: intermediate
1542 
1543 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()`
1544 @*/
1545 PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg)
1546 {
1547   PetscBool ismatis;
1548 
1549   PetscFunctionBegin;
1550   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1551   PetscAssertPointer(flg, 2);
1552   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis));
1553   PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
1554   *flg = ((Mat_IS *)A->data)->allow_repeated;
1555   PetscFunctionReturn(PETSC_SUCCESS);
1556 }
1557 
1558 /*@
1559   MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map
1560 
1561   Logically Collective
1562 
1563   Input Parameters:
1564 + A   - the matrix
1565 - flg - the boolean flag
1566 
1567   Level: intermediate
1568 
1569   Notes:
1570   The default value is `PETSC_FALSE`.
1571   When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices
1572   if `flg` is different from the previously set value.
1573   Specifically, when `flg` is true it will just recreate the local matrices, while if
1574   `flg` is false will assemble the local matrices summing up repeated entries.
1575 
1576 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()`
1577 @*/
1578 PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg)
1579 {
1580   PetscFunctionBegin;
1581   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1582   PetscValidType(A, 1);
1583   PetscValidLogicalCollectiveBool(A, flg, 2);
1584   PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg));
1585   PetscFunctionReturn(PETSC_SUCCESS);
1586 }
1587 
1588 static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg)
1589 {
1590   Mat_IS                *matis = (Mat_IS *)A->data;
1591   Mat                    lA    = NULL;
1592   ISLocalToGlobalMapping lrmap, lcmap;
1593 
1594   PetscFunctionBegin;
1595   if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS);
1596   if (!matis->A) { /* matrix has not been preallocated yet */
1597     matis->allow_repeated = flg;
1598     PetscFunctionReturn(PETSC_SUCCESS);
1599   }
1600   PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references");
1601   if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */
1602     lA = matis->A;
1603     PetscCall(PetscObjectReference((PetscObject)lA));
1604   }
1605   /* In case flg is True, we only recreate the local matrix */
1606   matis->allow_repeated = flg;
1607   PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping));
1608   if (lA) { /* assemble previous local matrix if needed */
1609     Mat nA = matis->A;
1610 
1611     PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap));
1612     if (!lrmap && !lcmap) {
1613       PetscCall(MatISSetLocalMat(A, lA));
1614     } else {
1615       Mat            P = NULL, R = NULL;
1616       MatProductType ptype;
1617 
1618       if (lrmap == lcmap) {
1619         ptype = MATPRODUCT_PtAP;
1620         PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
1621         PetscCall(MatProductCreate(lA, P, NULL, &nA));
1622       } else {
1623         if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P));
1624         if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R));
1625         if (R && P) {
1626           ptype = MATPRODUCT_ABC;
1627           PetscCall(MatProductCreate(R, lA, P, &nA));
1628         } else if (R) {
1629           ptype = MATPRODUCT_AB;
1630           PetscCall(MatProductCreate(R, lA, NULL, &nA));
1631         } else {
1632           ptype = MATPRODUCT_AB;
1633           PetscCall(MatProductCreate(lA, P, NULL, &nA));
1634         }
1635       }
1636       PetscCall(MatProductSetType(nA, ptype));
1637       PetscCall(MatProductSetFromOptions(nA));
1638       PetscCall(MatProductSymbolic(nA));
1639       PetscCall(MatProductNumeric(nA));
1640       PetscCall(MatProductClear(nA));
1641       PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA));
1642       PetscCall(MatISSetLocalMat(A, nA));
1643       PetscCall(MatDestroy(&nA));
1644       PetscCall(MatDestroy(&P));
1645       PetscCall(MatDestroy(&R));
1646     }
1647   }
1648   PetscCall(MatDestroy(&lA));
1649   PetscFunctionReturn(PETSC_SUCCESS);
1650 }
1651 
1652 /*@
1653   MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()`
1654 
1655   Logically Collective
1656 
1657   Input Parameters:
1658 + A     - the matrix
1659 - store - the boolean flag
1660 
1661   Level: advanced
1662 
1663 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()`
1664 @*/
1665 PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1666 {
1667   PetscFunctionBegin;
1668   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1669   PetscValidType(A, 1);
1670   PetscValidLogicalCollectiveBool(A, store, 2);
1671   PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store));
1672   PetscFunctionReturn(PETSC_SUCCESS);
1673 }
1674 
1675 static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1676 {
1677   Mat_IS *matis = (Mat_IS *)A->data;
1678 
1679   PetscFunctionBegin;
1680   matis->storel2l = store;
1681   if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL));
1682   PetscFunctionReturn(PETSC_SUCCESS);
1683 }
1684 
1685 /*@
1686   MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1687 
1688   Logically Collective
1689 
1690   Input Parameters:
1691 + A   - the matrix
1692 - fix - the boolean flag
1693 
1694   Level: advanced
1695 
1696   Note:
1697   When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process.
1698 
1699 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY`
1700 @*/
1701 PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1702 {
1703   PetscFunctionBegin;
1704   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1705   PetscValidType(A, 1);
1706   PetscValidLogicalCollectiveBool(A, fix, 2);
1707   PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix));
1708   PetscFunctionReturn(PETSC_SUCCESS);
1709 }
1710 
1711 static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1712 {
1713   Mat_IS *matis = (Mat_IS *)A->data;
1714 
1715   PetscFunctionBegin;
1716   matis->locempty = fix;
1717   PetscFunctionReturn(PETSC_SUCCESS);
1718 }
1719 
1720 /*@
1721   MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix.
1722 
1723   Collective
1724 
1725   Input Parameters:
1726 + B     - the matrix
1727 . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1728            (same value is used for all local rows)
1729 . d_nnz - array containing the number of nonzeros in the various rows of the
1730            DIAGONAL portion of the local submatrix (possibly different for each row)
1731            or `NULL`, if `d_nz` is used to specify the nonzero structure.
1732            The size of this array is equal to the number of local rows, i.e `m`.
1733            For matrices that will be factored, you must leave room for (and set)
1734            the diagonal entry even if it is zero.
1735 . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1736            submatrix (same value is used for all local rows).
1737 - o_nnz - array containing the number of nonzeros in the various rows of the
1738            OFF-DIAGONAL portion of the local submatrix (possibly different for
1739            each row) or `NULL`, if `o_nz` is used to specify the nonzero
1740            structure. The size of this array is equal to the number
1741            of local rows, i.e `m`.
1742 
1743    If the *_nnz parameter is given then the *_nz parameter is ignored
1744 
1745   Level: intermediate
1746 
1747   Note:
1748   This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition
1749   from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local
1750   matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1751 
1752 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS`
1753 @*/
1754 PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1755 {
1756   PetscFunctionBegin;
1757   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1758   PetscValidType(B, 1);
1759   PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
1760   PetscFunctionReturn(PETSC_SUCCESS);
1761 }
1762 
1763 /* this is used by DMDA */
1764 PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1765 {
1766   Mat_IS  *matis = (Mat_IS *)B->data;
1767   PetscInt bs, i, nlocalcols;
1768 
1769   PetscFunctionBegin;
1770   PetscCall(MatSetUp(B));
1771   if (!d_nnz)
1772     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz;
1773   else
1774     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i];
1775 
1776   if (!o_nnz)
1777     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz;
1778   else
1779     for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i];
1780 
1781   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1782   PetscCall(MatGetSize(matis->A, NULL, &nlocalcols));
1783   PetscCall(MatGetBlockSize(matis->A, &bs));
1784   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
1785 
1786   for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols);
1787   PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata));
1788 #if defined(PETSC_HAVE_HYPRE)
1789   PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL));
1790 #endif
1791 
1792   for (i = 0; i < matis->sf->nleaves / bs; i++) {
1793     PetscInt b;
1794 
1795     matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs;
1796     for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs);
1797   }
1798   PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
1799 
1800   nlocalcols /= bs;
1801   for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i);
1802   PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata));
1803 
1804   /* for other matrix types */
1805   PetscCall(MatSetUp(matis->A));
1806   PetscFunctionReturn(PETSC_SUCCESS);
1807 }
1808 
1809 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1810 {
1811   Mat_IS         *matis = (Mat_IS *)A->data;
1812   PetscInt       *my_dnz, *my_onz, *dnz, *onz, *mat_ranges, *row_ownership;
1813   const PetscInt *global_indices_r, *global_indices_c;
1814   PetscInt        i, j, bs, rows, cols;
1815   PetscInt        lrows, lcols;
1816   PetscInt        local_rows, local_cols;
1817   PetscMPIInt     size;
1818   PetscBool       isdense, issbaij;
1819 
1820   PetscFunctionBegin;
1821   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1822   PetscCall(MatGetSize(A, &rows, &cols));
1823   PetscCall(MatGetBlockSize(A, &bs));
1824   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
1825   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isdense));
1826   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &issbaij));
1827   PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &global_indices_r));
1828   if (matis->rmapping != matis->cmapping) {
1829     PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &global_indices_c));
1830   } else global_indices_c = global_indices_r;
1831 
1832   if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A));
1833   /*
1834      An SF reduce is needed to sum up properly on shared rows.
1835      Note that generally preallocation is not exact, since it overestimates nonzeros
1836   */
1837   PetscCall(MatGetLocalSize(A, &lrows, &lcols));
1838   MatPreallocateBegin(PetscObjectComm((PetscObject)A), lrows, lcols, dnz, onz);
1839   /* All processes need to compute entire row ownership */
1840   PetscCall(PetscMalloc1(rows, &row_ownership));
1841   PetscCall(MatGetOwnershipRanges(A, (const PetscInt **)&mat_ranges));
1842   for (i = 0; i < size; i++) {
1843     for (j = mat_ranges[i]; j < mat_ranges[i + 1]; j++) row_ownership[j] = i;
1844   }
1845   PetscCall(MatGetOwnershipRangesColumn(A, (const PetscInt **)&mat_ranges));
1846 
1847   /*
1848      my_dnz and my_onz contains exact contribution to preallocation from each local mat
1849      then, they will be summed up properly. This way, preallocation is always sufficient
1850   */
1851   PetscCall(PetscCalloc2(local_rows, &my_dnz, local_rows, &my_onz));
1852   /* preallocation as a MATAIJ */
1853   if (isdense) { /* special case for dense local matrices */
1854     for (i = 0; i < local_rows; i++) {
1855       PetscInt owner = row_ownership[global_indices_r[i]];
1856       for (j = 0; j < local_cols; j++) {
1857         PetscInt index_col = global_indices_c[j];
1858         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1859           my_dnz[i] += 1;
1860         } else { /* offdiag block */
1861           my_onz[i] += 1;
1862         }
1863       }
1864     }
1865   } else if (matis->A->ops->getrowij) {
1866     const PetscInt *ii, *jj, *jptr;
1867     PetscBool       done;
1868     PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1869     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
1870     jptr = jj;
1871     for (i = 0; i < local_rows; i++) {
1872       PetscInt index_row = global_indices_r[i];
1873       for (j = 0; j < ii[i + 1] - ii[i]; j++, jptr++) {
1874         PetscInt owner     = row_ownership[index_row];
1875         PetscInt index_col = global_indices_c[*jptr];
1876         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1877           my_dnz[i] += 1;
1878         } else { /* offdiag block */
1879           my_onz[i] += 1;
1880         }
1881         /* same as before, interchanging rows and cols */
1882         if (issbaij && index_col != index_row) {
1883           owner = row_ownership[index_col];
1884           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1885             my_dnz[*jptr] += 1;
1886           } else {
1887             my_onz[*jptr] += 1;
1888           }
1889         }
1890       }
1891     }
1892     PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &local_rows, &ii, &jj, &done));
1893     PetscCheck(done, PetscObjectComm((PetscObject)matis->A), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
1894   } else { /* loop over rows and use MatGetRow */
1895     for (i = 0; i < local_rows; i++) {
1896       const PetscInt *cols;
1897       PetscInt        ncols, index_row = global_indices_r[i];
1898       PetscCall(MatGetRow(matis->A, i, &ncols, &cols, NULL));
1899       for (j = 0; j < ncols; j++) {
1900         PetscInt owner     = row_ownership[index_row];
1901         PetscInt index_col = global_indices_c[cols[j]];
1902         if (index_col > mat_ranges[owner] - 1 && index_col < mat_ranges[owner + 1]) { /* diag block */
1903           my_dnz[i] += 1;
1904         } else { /* offdiag block */
1905           my_onz[i] += 1;
1906         }
1907         /* same as before, interchanging rows and cols */
1908         if (issbaij && index_col != index_row) {
1909           owner = row_ownership[index_col];
1910           if (index_row > mat_ranges[owner] - 1 && index_row < mat_ranges[owner + 1]) {
1911             my_dnz[cols[j]] += 1;
1912           } else {
1913             my_onz[cols[j]] += 1;
1914           }
1915         }
1916       }
1917       PetscCall(MatRestoreRow(matis->A, i, &ncols, &cols, NULL));
1918     }
1919   }
1920   if (global_indices_c != global_indices_r) PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &global_indices_c));
1921   PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &global_indices_r));
1922   PetscCall(PetscFree(row_ownership));
1923 
1924   /* Reduce my_dnz and my_onz */
1925   if (maxreduce) {
1926     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
1927     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
1928     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_MAX));
1929     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_MAX));
1930   } else {
1931     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
1932     PetscCall(PetscSFReduceBegin(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
1933     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_dnz, dnz, MPI_SUM));
1934     PetscCall(PetscSFReduceEnd(matis->sf, MPIU_INT, my_onz, onz, MPI_SUM));
1935   }
1936   PetscCall(PetscFree2(my_dnz, my_onz));
1937 
1938   /* Resize preallocation if overestimated */
1939   for (i = 0; i < lrows; i++) {
1940     dnz[i] = PetscMin(dnz[i], lcols);
1941     onz[i] = PetscMin(onz[i], cols - lcols);
1942   }
1943 
1944   /* Set preallocation */
1945   PetscCall(MatSetBlockSizesFromMats(B, A, A));
1946   PetscCall(MatSeqAIJSetPreallocation(B, 0, dnz));
1947   PetscCall(MatMPIAIJSetPreallocation(B, 0, dnz, 0, onz));
1948   for (i = 0; i < lrows; i += bs) {
1949     PetscInt b, d = dnz[i], o = onz[i];
1950 
1951     for (b = 1; b < bs; b++) {
1952       d = PetscMax(d, dnz[i + b]);
1953       o = PetscMax(o, onz[i + b]);
1954     }
1955     dnz[i / bs] = PetscMin(d / bs + d % bs, lcols / bs);
1956     onz[i / bs] = PetscMin(o / bs + o % bs, (cols - lcols) / bs);
1957   }
1958   PetscCall(MatSeqBAIJSetPreallocation(B, bs, 0, dnz));
1959   PetscCall(MatMPIBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1960   PetscCall(MatMPISBAIJSetPreallocation(B, bs, 0, dnz, 0, onz));
1961   MatPreallocateEnd(dnz, onz);
1962   if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A));
1963   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
1964   PetscFunctionReturn(PETSC_SUCCESS);
1965 }
1966 
1967 PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1968 {
1969   Mat_IS            *matis = (Mat_IS *)mat->data;
1970   Mat                local_mat, MT;
1971   PetscInt           rbs, cbs, rows, cols, lrows, lcols;
1972   PetscInt           local_rows, local_cols;
1973   PetscBool          isseqdense, isseqsbaij, isseqaij, isseqbaij;
1974   PetscMPIInt        size;
1975   const PetscScalar *array;
1976 
1977   PetscFunctionBegin;
1978   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
1979   if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) {
1980     Mat      B;
1981     IS       irows = NULL, icols = NULL;
1982     PetscInt rbs, cbs;
1983 
1984     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
1985     PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
1986     if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
1987       IS              rows, cols;
1988       const PetscInt *ridxs, *cidxs;
1989       PetscInt        i, nw;
1990       PetscBT         work;
1991 
1992       PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs));
1993       PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw));
1994       nw = nw / rbs;
1995       PetscCall(PetscBTCreate(nw, &work));
1996       for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i]));
1997       for (i = 0; i < nw; i++)
1998         if (!PetscBTLookup(work, i)) break;
1999       if (i == nw) {
2000         PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows));
2001         PetscCall(ISSetPermutation(rows));
2002         PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows));
2003         PetscCall(ISDestroy(&rows));
2004       }
2005       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs));
2006       PetscCall(PetscBTDestroy(&work));
2007       if (irows && matis->rmapping != matis->cmapping) {
2008         PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs));
2009         PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw));
2010         nw = nw / cbs;
2011         PetscCall(PetscBTCreate(nw, &work));
2012         for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i]));
2013         for (i = 0; i < nw; i++)
2014           if (!PetscBTLookup(work, i)) break;
2015         if (i == nw) {
2016           PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols));
2017           PetscCall(ISSetPermutation(cols));
2018           PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols));
2019           PetscCall(ISDestroy(&cols));
2020         }
2021         PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs));
2022         PetscCall(PetscBTDestroy(&work));
2023       } else if (irows) {
2024         PetscCall(PetscObjectReference((PetscObject)irows));
2025         icols = irows;
2026       }
2027     } else {
2028       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows));
2029       PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols));
2030       if (irows) PetscCall(PetscObjectReference((PetscObject)irows));
2031       if (icols) PetscCall(PetscObjectReference((PetscObject)icols));
2032     }
2033     if (!irows || !icols) {
2034       PetscCall(ISDestroy(&icols));
2035       PetscCall(ISDestroy(&irows));
2036       goto general_assembly;
2037     }
2038     PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B));
2039     if (reuse != MAT_INPLACE_MATRIX) {
2040       PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M));
2041       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows));
2042       PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols));
2043     } else {
2044       Mat C;
2045 
2046       PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C));
2047       PetscCall(MatHeaderReplace(mat, &C));
2048     }
2049     PetscCall(MatDestroy(&B));
2050     PetscCall(ISDestroy(&icols));
2051     PetscCall(ISDestroy(&irows));
2052     PetscFunctionReturn(PETSC_SUCCESS);
2053   }
2054 general_assembly:
2055   PetscCall(MatGetSize(mat, &rows, &cols));
2056   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs));
2057   PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs));
2058   PetscCall(MatGetLocalSize(mat, &lrows, &lcols));
2059   PetscCall(MatGetSize(matis->A, &local_rows, &local_cols));
2060   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense));
2061   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij));
2062   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij));
2063   PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij));
2064   PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name);
2065   if (PetscDefined(USE_DEBUG)) {
2066     PetscBool lb[4], bb[4];
2067 
2068     lb[0] = isseqdense;
2069     lb[1] = isseqaij;
2070     lb[2] = isseqbaij;
2071     lb[3] = isseqsbaij;
2072     PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
2073     PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type");
2074   }
2075 
2076   if (reuse != MAT_REUSE_MATRIX) {
2077     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT));
2078     PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols));
2079     PetscCall(MatSetType(MT, mtype));
2080     PetscCall(MatSetBlockSizes(MT, rbs, cbs));
2081     PetscCall(MatISSetMPIXAIJPreallocation_Private(mat, MT, PETSC_FALSE));
2082   } else {
2083     PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols;
2084 
2085     /* some checks */
2086     MT = *M;
2087     PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs));
2088     PetscCall(MatGetSize(MT, &mrows, &mcols));
2089     PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols));
2090     PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows);
2091     PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols);
2092     PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows);
2093     PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols);
2094     PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs);
2095     PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs);
2096     PetscCall(MatZeroEntries(MT));
2097   }
2098 
2099   if (isseqsbaij || isseqbaij) {
2100     PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat));
2101     isseqaij = PETSC_TRUE;
2102   } else {
2103     PetscCall(PetscObjectReference((PetscObject)matis->A));
2104     local_mat = matis->A;
2105   }
2106 
2107   /* Set values */
2108   PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping));
2109   if (isseqdense) { /* special case for dense local matrices */
2110     PetscInt i, *dummy;
2111 
2112     PetscCall(PetscMalloc1(PetscMax(local_rows, local_cols), &dummy));
2113     for (i = 0; i < PetscMax(local_rows, local_cols); i++) dummy[i] = i;
2114     PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_FALSE));
2115     PetscCall(MatDenseGetArrayRead(local_mat, &array));
2116     PetscCall(MatSetValuesLocal(MT, local_rows, dummy, local_cols, dummy, array, ADD_VALUES));
2117     PetscCall(MatDenseRestoreArrayRead(local_mat, &array));
2118     PetscCall(PetscFree(dummy));
2119   } else if (isseqaij) {
2120     const PetscInt *blocks;
2121     PetscInt        i, nvtxs, *xadj, *adjncy, nb;
2122     PetscBool       done;
2123     PetscScalar    *sarray;
2124 
2125     PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
2126     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ");
2127     PetscCall(MatSeqAIJGetArray(local_mat, &sarray));
2128     PetscCall(MatGetVariableBlockSizes(local_mat, &nb, &blocks));
2129     if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
2130       PetscInt sum;
2131 
2132       for (i = 0, sum = 0; i < nb; i++) sum += blocks[i];
2133       if (sum == nvtxs) {
2134         PetscInt r;
2135 
2136         for (i = 0, r = 0; i < nb; i++) {
2137           PetscAssert(blocks[i] == xadj[r + 1] - xadj[r], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid block sizes prescribed for block %" PetscInt_FMT ": expected %" PetscInt_FMT ", got %" PetscInt_FMT, i, blocks[i], xadj[r + 1] - xadj[r]);
2138           PetscCall(MatSetValuesLocal(MT, blocks[i], adjncy + xadj[r], blocks[i], adjncy + xadj[r], sarray + xadj[r], ADD_VALUES));
2139           r += blocks[i];
2140         }
2141       } else {
2142         for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], adjncy + xadj[i], sarray + xadj[i], ADD_VALUES));
2143       }
2144     } else {
2145       for (i = 0; i < nvtxs; i++) PetscCall(MatSetValuesLocal(MT, 1, &i, xadj[i + 1] - xadj[i], PetscSafePointerPlusOffset(adjncy, xadj[i]), PetscSafePointerPlusOffset(sarray, xadj[i]), ADD_VALUES));
2146     }
2147     PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nvtxs, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
2148     PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ");
2149     PetscCall(MatSeqAIJRestoreArray(local_mat, &sarray));
2150   } else { /* very basic values insertion for all other matrix types */
2151     for (PetscInt i = 0; i < local_rows; i++) {
2152       PetscInt        j;
2153       const PetscInt *local_indices_cols;
2154 
2155       PetscCall(MatGetRow(local_mat, i, &j, &local_indices_cols, &array));
2156       PetscCall(MatSetValuesLocal(MT, 1, &i, j, local_indices_cols, array, ADD_VALUES));
2157       PetscCall(MatRestoreRow(local_mat, i, &j, &local_indices_cols, &array));
2158     }
2159   }
2160   PetscCall(MatDestroy(&local_mat));
2161   PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY));
2162   PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY));
2163   if (isseqdense) PetscCall(MatSetOption(MT, MAT_ROW_ORIENTED, PETSC_TRUE));
2164   if (reuse == MAT_INPLACE_MATRIX) {
2165     PetscCall(MatHeaderReplace(mat, &MT));
2166   } else if (reuse == MAT_INITIAL_MATRIX) {
2167     *M = MT;
2168   }
2169   PetscFunctionReturn(PETSC_SUCCESS);
2170 }
2171 
2172 static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat)
2173 {
2174   Mat_IS  *matis = (Mat_IS *)mat->data;
2175   PetscInt rbs, cbs, m, n, M, N;
2176   Mat      B, localmat;
2177 
2178   PetscFunctionBegin;
2179   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs));
2180   PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs));
2181   PetscCall(MatGetSize(mat, &M, &N));
2182   PetscCall(MatGetLocalSize(mat, &m, &n));
2183   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
2184   PetscCall(MatSetSizes(B, m, n, M, N));
2185   PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1));
2186   PetscCall(MatSetType(B, MATIS));
2187   PetscCall(MatISSetLocalMatType(B, matis->lmattype));
2188   PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated));
2189   PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping));
2190   PetscCall(MatDuplicate(matis->A, op, &localmat));
2191   PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping));
2192   PetscCall(MatISSetLocalMat(B, localmat));
2193   PetscCall(MatDestroy(&localmat));
2194   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2195   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2196   *newmat = B;
2197   PetscFunctionReturn(PETSC_SUCCESS);
2198 }
2199 
2200 static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg)
2201 {
2202   Mat_IS   *matis = (Mat_IS *)A->data;
2203   PetscBool local_sym;
2204 
2205   PetscFunctionBegin;
2206   PetscCall(MatIsHermitian(matis->A, tol, &local_sym));
2207   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2208   PetscFunctionReturn(PETSC_SUCCESS);
2209 }
2210 
2211 static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg)
2212 {
2213   Mat_IS   *matis = (Mat_IS *)A->data;
2214   PetscBool local_sym;
2215 
2216   PetscFunctionBegin;
2217   if (matis->rmapping != matis->cmapping) {
2218     *flg = PETSC_FALSE;
2219     PetscFunctionReturn(PETSC_SUCCESS);
2220   }
2221   PetscCall(MatIsSymmetric(matis->A, tol, &local_sym));
2222   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2223   PetscFunctionReturn(PETSC_SUCCESS);
2224 }
2225 
2226 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg)
2227 {
2228   Mat_IS   *matis = (Mat_IS *)A->data;
2229   PetscBool local_sym;
2230 
2231   PetscFunctionBegin;
2232   if (matis->rmapping != matis->cmapping) {
2233     *flg = PETSC_FALSE;
2234     PetscFunctionReturn(PETSC_SUCCESS);
2235   }
2236   PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym));
2237   PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2238   PetscFunctionReturn(PETSC_SUCCESS);
2239 }
2240 
2241 static PetscErrorCode MatDestroy_IS(Mat A)
2242 {
2243   Mat_IS *b = (Mat_IS *)A->data;
2244 
2245   PetscFunctionBegin;
2246   PetscCall(PetscFree(b->bdiag));
2247   PetscCall(PetscFree(b->lmattype));
2248   PetscCall(MatDestroy(&b->A));
2249   PetscCall(VecScatterDestroy(&b->cctx));
2250   PetscCall(VecScatterDestroy(&b->rctx));
2251   PetscCall(VecDestroy(&b->x));
2252   PetscCall(VecDestroy(&b->y));
2253   PetscCall(VecDestroy(&b->counter));
2254   PetscCall(ISDestroy(&b->getsub_ris));
2255   PetscCall(ISDestroy(&b->getsub_cis));
2256   if (b->sf != b->csf) {
2257     PetscCall(PetscSFDestroy(&b->csf));
2258     PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata));
2259   } else b->csf = NULL;
2260   PetscCall(PetscSFDestroy(&b->sf));
2261   PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata));
2262   PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping));
2263   PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping));
2264   PetscCall(MatDestroy(&b->dA));
2265   PetscCall(MatDestroy(&b->assembledA));
2266   PetscCall(PetscFree(A->data));
2267   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
2268   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL));
2269   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL));
2270   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL));
2271   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL));
2272   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL));
2273   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL));
2274   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL));
2275   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL));
2276   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL));
2277   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL));
2278   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL));
2279   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL));
2280   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL));
2281   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL));
2282   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL));
2283   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL));
2284   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
2285   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
2286   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL));
2287   PetscFunctionReturn(PETSC_SUCCESS);
2288 }
2289 
2290 static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y)
2291 {
2292   Mat_IS     *is   = (Mat_IS *)A->data;
2293   PetscScalar zero = 0.0;
2294 
2295   PetscFunctionBegin;
2296   /*  scatter the global vector x into the local work vector */
2297   PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2298   PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD));
2299 
2300   /* multiply the local matrix */
2301   PetscCall(MatMult(is->A, is->x, is->y));
2302 
2303   /* scatter product back into global memory */
2304   PetscCall(VecSet(y, zero));
2305   PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2306   PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE));
2307   PetscFunctionReturn(PETSC_SUCCESS);
2308 }
2309 
2310 static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2311 {
2312   Vec temp_vec;
2313 
2314   PetscFunctionBegin; /*  v3 = v2 + A * v1.*/
2315   if (v3 != v2) {
2316     PetscCall(MatMult(A, v1, v3));
2317     PetscCall(VecAXPY(v3, 1.0, v2));
2318   } else {
2319     PetscCall(VecDuplicate(v2, &temp_vec));
2320     PetscCall(MatMult(A, v1, temp_vec));
2321     PetscCall(VecAXPY(temp_vec, 1.0, v2));
2322     PetscCall(VecCopy(temp_vec, v3));
2323     PetscCall(VecDestroy(&temp_vec));
2324   }
2325   PetscFunctionReturn(PETSC_SUCCESS);
2326 }
2327 
2328 static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x)
2329 {
2330   Mat_IS *is = (Mat_IS *)A->data;
2331 
2332   PetscFunctionBegin;
2333   /*  scatter the global vector x into the local work vector */
2334   PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
2335   PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD));
2336 
2337   /* multiply the local matrix */
2338   PetscCall(MatMultTranspose(is->A, is->y, is->x));
2339 
2340   /* scatter product back into global vector */
2341   PetscCall(VecSet(x, 0));
2342   PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
2343   PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE));
2344   PetscFunctionReturn(PETSC_SUCCESS);
2345 }
2346 
2347 static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3)
2348 {
2349   Vec temp_vec;
2350 
2351   PetscFunctionBegin; /*  v3 = v2 + A' * v1.*/
2352   if (v3 != v2) {
2353     PetscCall(MatMultTranspose(A, v1, v3));
2354     PetscCall(VecAXPY(v3, 1.0, v2));
2355   } else {
2356     PetscCall(VecDuplicate(v2, &temp_vec));
2357     PetscCall(MatMultTranspose(A, v1, temp_vec));
2358     PetscCall(VecAXPY(temp_vec, 1.0, v2));
2359     PetscCall(VecCopy(temp_vec, v3));
2360     PetscCall(VecDestroy(&temp_vec));
2361   }
2362   PetscFunctionReturn(PETSC_SUCCESS);
2363 }
2364 
2365 static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer)
2366 {
2367   Mat_IS                *a = (Mat_IS *)A->data;
2368   PetscViewer            sviewer;
2369   PetscBool              isascii, isbinary, viewl2g = PETSC_FALSE, native;
2370   PetscViewerFormat      format;
2371   ISLocalToGlobalMapping rmap, cmap;
2372 
2373   PetscFunctionBegin;
2374   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2375   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2376   PetscCall(PetscViewerGetFormat(viewer, &format));
2377   native = (PetscBool)(format == PETSC_VIEWER_NATIVE);
2378   if (native) {
2379     rmap = A->rmap->mapping;
2380     cmap = A->cmap->mapping;
2381   } else {
2382     rmap = a->rmapping;
2383     cmap = a->cmapping;
2384   }
2385   if (isascii) {
2386     if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
2387     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE;
2388   } else if (isbinary) {
2389     PetscInt    tr[6], nr, nc;
2390     char        lmattype[64] = {'\0'};
2391     PetscMPIInt size;
2392     PetscBool   skipHeader;
2393     IS          is;
2394 
2395     PetscCall(PetscViewerSetUp(viewer));
2396     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2397     tr[0] = MAT_FILE_CLASSID;
2398     tr[1] = A->rmap->N;
2399     tr[2] = A->cmap->N;
2400     tr[3] = -size; /* AIJ stores nnz here */
2401     tr[4] = (PetscInt)(rmap == cmap);
2402     tr[5] = a->allow_repeated;
2403     PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype));
2404 
2405     PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT));
2406     PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR));
2407 
2408     /* first dump l2g info (we need the header for proper loading on different number of processes) */
2409     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
2410     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE));
2411     PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2412     if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2413 
2414     /* then the sizes of the local matrices */
2415     PetscCall(MatGetSize(a->A, &nr, &nc));
2416     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is));
2417     PetscCall(ISView(is, viewer));
2418     PetscCall(ISDestroy(&is));
2419     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is));
2420     PetscCall(ISView(is, viewer));
2421     PetscCall(ISDestroy(&is));
2422     PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader));
2423   }
2424   if (format == PETSC_VIEWER_ASCII_MATLAB) {
2425     char        name[64];
2426     PetscMPIInt size, rank;
2427 
2428     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2429     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
2430     if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank));
2431     else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat"));
2432     PetscCall(PetscObjectSetName((PetscObject)a->A, name));
2433   }
2434 
2435   /* Dump the local matrices */
2436   if (isbinary) { /* ViewerGetSubViewer does not work in parallel */
2437     PetscBool   isaij;
2438     PetscInt    nr, nc;
2439     Mat         lA, B;
2440     Mat_MPIAIJ *b;
2441 
2442     /* We create a temporary MPIAIJ matrix that stores the unassembled operator */
2443     PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij));
2444     if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA));
2445     else {
2446       PetscCall(PetscObjectReference((PetscObject)a->A));
2447       lA = a->A;
2448     }
2449     PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B));
2450     PetscCall(MatSetType(B, MATMPIAIJ));
2451     PetscCall(MatGetSize(lA, &nr, &nc));
2452     PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
2453     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
2454 
2455     b = (Mat_MPIAIJ *)B->data;
2456     PetscCall(MatDestroy(&b->A));
2457     b->A = lA;
2458 
2459     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2460     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2461     PetscCall(MatView(B, viewer));
2462     PetscCall(MatDestroy(&B));
2463   } else {
2464     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2465     PetscCall(MatView(a->A, sviewer));
2466     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
2467   }
2468 
2469   /* with ASCII, we dump the l2gmaps at the end */
2470   if (viewl2g) {
2471     if (format == PETSC_VIEWER_ASCII_MATLAB) {
2472       PetscCall(PetscObjectSetName((PetscObject)rmap, "row"));
2473       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2474       PetscCall(PetscObjectSetName((PetscObject)cmap, "col"));
2475       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2476     } else {
2477       PetscCall(ISLocalToGlobalMappingView(rmap, viewer));
2478       PetscCall(ISLocalToGlobalMappingView(cmap, viewer));
2479     }
2480   }
2481   PetscFunctionReturn(PETSC_SUCCESS);
2482 }
2483 
2484 static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer)
2485 {
2486   ISLocalToGlobalMapping rmap, cmap;
2487   MPI_Comm               comm = PetscObjectComm((PetscObject)A);
2488   PetscBool              isbinary, samel, allow, isbaij;
2489   PetscInt               tr[6], M, N, nr, nc, Asize, isn;
2490   const PetscInt        *idx;
2491   PetscMPIInt            size;
2492   char                   lmattype[64];
2493   Mat                    dA, lA;
2494   IS                     is;
2495 
2496   PetscFunctionBegin;
2497   PetscCheckSameComm(A, 1, viewer, 2);
2498   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2499   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
2500 
2501   PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT));
2502   PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file");
2503   PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2504   PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2505   PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2506   PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2507   PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file");
2508   M     = tr[1];
2509   N     = tr[2];
2510   Asize = -tr[3];
2511   samel = (PetscBool)tr[4];
2512   allow = (PetscBool)tr[5];
2513   PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR));
2514 
2515   /* if we are loading from a larger set of processes, allow repeated entries */
2516   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
2517   if (Asize > size) allow = PETSC_TRUE;
2518 
2519   /* set global sizes if not set already */
2520   if (A->rmap->N < 0) A->rmap->N = M;
2521   if (A->cmap->N < 0) A->cmap->N = N;
2522   PetscCall(PetscLayoutSetUp(A->rmap));
2523   PetscCall(PetscLayoutSetUp(A->cmap));
2524   PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N);
2525   PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N);
2526 
2527   /* load l2g maps */
2528   PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap));
2529   PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer));
2530   if (!samel) {
2531     PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap));
2532     PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer));
2533   } else {
2534     PetscCall(PetscObjectReference((PetscObject)rmap));
2535     cmap = rmap;
2536   }
2537 
2538   /* load sizes of local matrices */
2539   PetscCall(ISCreate(comm, &is));
2540   PetscCall(ISSetType(is, ISGENERAL));
2541   PetscCall(ISLoad(is, viewer));
2542   PetscCall(ISGetLocalSize(is, &isn));
2543   PetscCall(ISGetIndices(is, &idx));
2544   nr = 0;
2545   for (PetscInt i = 0; i < isn; i++) nr += idx[i];
2546   PetscCall(ISRestoreIndices(is, &idx));
2547   PetscCall(ISDestroy(&is));
2548   PetscCall(ISCreate(comm, &is));
2549   PetscCall(ISSetType(is, ISGENERAL));
2550   PetscCall(ISLoad(is, viewer));
2551   PetscCall(ISGetLocalSize(is, &isn));
2552   PetscCall(ISGetIndices(is, &idx));
2553   nc = 0;
2554   for (PetscInt i = 0; i < isn; i++) nc += idx[i];
2555   PetscCall(ISRestoreIndices(is, &idx));
2556   PetscCall(ISDestroy(&is));
2557 
2558   /* now load the unassembled operator */
2559   PetscCall(MatCreate(comm, &dA));
2560   PetscCall(MatSetType(dA, MATMPIAIJ));
2561   PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE));
2562   PetscCall(MatLoad(dA, viewer));
2563   PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL));
2564   PetscCall(PetscObjectReference((PetscObject)lA));
2565   PetscCall(MatDestroy(&dA));
2566 
2567   /* and convert to the desired format */
2568   PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, ""));
2569   if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE));
2570   PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA));
2571 
2572   /* assemble the MATIS object */
2573   PetscCall(MatISSetAllowRepeated(A, allow));
2574   PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
2575   PetscCall(MatISSetLocalMat(A, lA));
2576   PetscCall(MatDestroy(&lA));
2577   PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
2578   PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
2579   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2580   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2581   PetscFunctionReturn(PETSC_SUCCESS);
2582 }
2583 
2584 static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values)
2585 {
2586   Mat_IS            *is = (Mat_IS *)mat->data;
2587   MPI_Datatype       nodeType;
2588   const PetscScalar *lv;
2589   PetscInt           bs;
2590   PetscMPIInt        mbs;
2591 
2592   PetscFunctionBegin;
2593   PetscCall(MatGetBlockSize(mat, &bs));
2594   PetscCall(MatSetBlockSize(is->A, bs));
2595   PetscCall(MatInvertBlockDiagonal(is->A, &lv));
2596   if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag));
2597   PetscCall(PetscMPIIntCast(bs, &mbs));
2598   PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType));
2599   PetscCallMPI(MPI_Type_commit(&nodeType));
2600   PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
2601   PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE));
2602   PetscCallMPI(MPI_Type_free(&nodeType));
2603   if (values) *values = is->bdiag;
2604   PetscFunctionReturn(PETSC_SUCCESS);
2605 }
2606 
2607 static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2608 {
2609   Vec             cglobal, rglobal;
2610   IS              from;
2611   Mat_IS         *is = (Mat_IS *)A->data;
2612   PetscScalar     sum;
2613   const PetscInt *garray;
2614   PetscInt        nr, rbs, nc, cbs;
2615   VecType         rtype;
2616 
2617   PetscFunctionBegin;
2618   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
2619   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
2620   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
2621   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2622   PetscCall(VecDestroy(&is->x));
2623   PetscCall(VecDestroy(&is->y));
2624   PetscCall(VecDestroy(&is->counter));
2625   PetscCall(VecScatterDestroy(&is->rctx));
2626   PetscCall(VecScatterDestroy(&is->cctx));
2627   PetscCall(MatCreateVecs(is->A, &is->x, &is->y));
2628   PetscCall(VecBindToCPU(is->y, PETSC_TRUE));
2629   PetscCall(VecGetRootType_Private(is->y, &rtype));
2630   PetscCall(PetscFree(A->defaultvectype));
2631   PetscCall(PetscStrallocpy(rtype, &A->defaultvectype));
2632   PetscCall(MatCreateVecs(A, &cglobal, &rglobal));
2633   PetscCall(VecBindToCPU(rglobal, PETSC_TRUE));
2634   PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray));
2635   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from));
2636   PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx));
2637   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray));
2638   PetscCall(ISDestroy(&from));
2639   if (is->rmapping != is->cmapping) {
2640     PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray));
2641     PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from));
2642     PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx));
2643     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray));
2644     PetscCall(ISDestroy(&from));
2645   } else {
2646     PetscCall(PetscObjectReference((PetscObject)is->rctx));
2647     is->cctx = is->rctx;
2648   }
2649   PetscCall(VecDestroy(&cglobal));
2650 
2651   /* interface counter vector (local) */
2652   PetscCall(VecDuplicate(is->y, &is->counter));
2653   PetscCall(VecBindToCPU(is->counter, PETSC_TRUE));
2654   PetscCall(VecSet(is->y, 1.));
2655   PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
2656   PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE));
2657   PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
2658   PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD));
2659   PetscCall(VecBindToCPU(is->y, PETSC_FALSE));
2660   PetscCall(VecBindToCPU(is->counter, PETSC_FALSE));
2661 
2662   /* special functions for block-diagonal matrices */
2663   PetscCall(VecSum(rglobal, &sum));
2664   A->ops->invertblockdiagonal = NULL;
2665   if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
2666   PetscCall(VecDestroy(&rglobal));
2667 
2668   /* setup SF for general purpose shared indices based communications */
2669   PetscCall(MatISSetUpSF_IS(A));
2670   PetscFunctionReturn(PETSC_SUCCESS);
2671 }
2672 
2673 static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap)
2674 {
2675   Mat_IS                    *matis = (Mat_IS *)A->data;
2676   IS                         is;
2677   ISLocalToGlobalMappingType l2gtype;
2678   const PetscInt            *idxs;
2679   PetscHSetI                 ht;
2680   PetscInt                  *nidxs;
2681   PetscInt                   i, n, bs, c;
2682   PetscBool                  flg[] = {PETSC_FALSE, PETSC_FALSE};
2683 
2684   PetscFunctionBegin;
2685   PetscCall(ISLocalToGlobalMappingGetSize(map, &n));
2686   PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs));
2687   PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs));
2688   PetscCall(PetscHSetICreate(&ht));
2689   PetscCall(PetscMalloc1(n / bs, &nidxs));
2690   for (i = 0, c = 0; i < n / bs; i++) {
2691     PetscBool missing = PETSC_TRUE;
2692     if (idxs[i] < 0) {
2693       flg[0] = PETSC_TRUE;
2694       continue;
2695     }
2696     if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing));
2697     if (!missing) flg[1] = PETSC_TRUE;
2698     else nidxs[c++] = idxs[i];
2699   }
2700   PetscCall(PetscHSetIDestroy(&ht));
2701   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
2702   if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */
2703     *nmap = NULL;
2704     *lmap = NULL;
2705     PetscCall(PetscFree(nidxs));
2706     PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2707     PetscFunctionReturn(PETSC_SUCCESS);
2708   }
2709 
2710   /* New l2g map without negative indices (and repeated indices if not allowed) */
2711   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is));
2712   PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap));
2713   PetscCall(ISDestroy(&is));
2714   PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype));
2715   PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype));
2716 
2717   /* New local l2g map for repeated indices if not allowed */
2718   PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs));
2719   PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is));
2720   PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap));
2721   PetscCall(ISDestroy(&is));
2722   PetscCall(PetscFree(nidxs));
2723   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs));
2724   PetscFunctionReturn(PETSC_SUCCESS);
2725 }
2726 
2727 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2728 {
2729   Mat_IS                *is            = (Mat_IS *)A->data;
2730   ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL;
2731   PetscInt               nr, rbs, nc, cbs;
2732   PetscBool              cong, freem[] = {PETSC_FALSE, PETSC_FALSE};
2733 
2734   PetscFunctionBegin;
2735   if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2);
2736   if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3);
2737 
2738   PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping));
2739   PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
2740   PetscCall(PetscLayoutSetUp(A->rmap));
2741   PetscCall(PetscLayoutSetUp(A->cmap));
2742   PetscCall(MatHasCongruentLayouts(A, &cong));
2743 
2744   /* If NULL, local space matches global space */
2745   if (!rmapping) {
2746     IS is;
2747 
2748     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is));
2749     PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping));
2750     if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs));
2751     PetscCall(ISDestroy(&is));
2752     freem[0] = PETSC_TRUE;
2753     if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping;
2754   } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */
2755     PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping));
2756     if (rmapping == cmapping) {
2757       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2758       is->cmapping = is->rmapping;
2759       PetscCall(PetscObjectReference((PetscObject)localrmapping));
2760       localcmapping = localrmapping;
2761     }
2762   }
2763   if (!cmapping) {
2764     IS is;
2765 
2766     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is));
2767     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping));
2768     if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs));
2769     PetscCall(ISDestroy(&is));
2770     freem[1] = PETSC_TRUE;
2771   } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */
2772     PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping));
2773   }
2774   if (!is->rmapping) {
2775     PetscCall(PetscObjectReference((PetscObject)rmapping));
2776     is->rmapping = rmapping;
2777   }
2778   if (!is->cmapping) {
2779     PetscCall(PetscObjectReference((PetscObject)cmapping));
2780     is->cmapping = cmapping;
2781   }
2782 
2783   /* Clean up */
2784   is->lnnzstate = 0;
2785   PetscCall(MatDestroy(&is->dA));
2786   PetscCall(MatDestroy(&is->assembledA));
2787   PetscCall(MatDestroy(&is->A));
2788   if (is->csf != is->sf) {
2789     PetscCall(PetscSFDestroy(&is->csf));
2790     PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata));
2791   } else is->csf = NULL;
2792   PetscCall(PetscSFDestroy(&is->sf));
2793   PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata));
2794   PetscCall(PetscFree(is->bdiag));
2795 
2796   /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case
2797      (DOLFIN passes 2 different objects) */
2798   PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr));
2799   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs));
2800   PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc));
2801   PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs));
2802   if (is->rmapping != is->cmapping && cong) {
2803     PetscBool same = PETSC_FALSE;
2804     if (nr == nc && cbs == rbs) {
2805       const PetscInt *idxs1, *idxs2;
2806 
2807       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1));
2808       PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2));
2809       PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same));
2810       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1));
2811       PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2));
2812     }
2813     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2814     if (same) {
2815       PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping));
2816       PetscCall(PetscObjectReference((PetscObject)is->rmapping));
2817       is->cmapping = is->rmapping;
2818     }
2819   }
2820   PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs));
2821   PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs));
2822   /* Pass the user defined maps to the layout */
2823   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping));
2824   PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping));
2825   if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping));
2826   if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping));
2827 
2828   /* Create the local matrix A */
2829   PetscCall(MatCreate(PETSC_COMM_SELF, &is->A));
2830   PetscCall(MatSetType(is->A, is->lmattype));
2831   PetscCall(MatSetSizes(is->A, nr, nc, nr, nc));
2832   PetscCall(MatSetBlockSizes(is->A, rbs, cbs));
2833   PetscCall(MatSetOptionsPrefix(is->A, "is_"));
2834   PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix));
2835   PetscCall(PetscLayoutSetUp(is->A->rmap));
2836   PetscCall(PetscLayoutSetUp(is->A->cmap));
2837   PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping));
2838   PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping));
2839   PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping));
2840 
2841   /* setup scatters and local vectors for MatMult */
2842   if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A));
2843   A->preallocated = PETSC_TRUE;
2844   PetscFunctionReturn(PETSC_SUCCESS);
2845 }
2846 
2847 static PetscErrorCode MatSetUp_IS(Mat A)
2848 {
2849   ISLocalToGlobalMapping rmap, cmap;
2850 
2851   PetscFunctionBegin;
2852   PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap));
2853   if (!rmap && !cmap) PetscCall(MatSetLocalToGlobalMapping(A, NULL, NULL));
2854   PetscFunctionReturn(PETSC_SUCCESS);
2855 }
2856 
2857 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2858 {
2859   Mat_IS  *is = (Mat_IS *)mat->data;
2860   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
2861 
2862   PetscFunctionBegin;
2863   PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2864   if (m != n || rows != cols || is->cmapping != is->rmapping) {
2865     PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
2866     PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv));
2867   } else {
2868     PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv));
2869   }
2870   PetscFunctionReturn(PETSC_SUCCESS);
2871 }
2872 
2873 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2874 {
2875   Mat_IS  *is = (Mat_IS *)mat->data;
2876   PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION], cols_l[MATIS_MAX_ENTRIES_INSERTION];
2877 
2878   PetscFunctionBegin;
2879   PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l));
2880   if (m != n || rows != cols || is->cmapping != is->rmapping) {
2881     PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l));
2882     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv));
2883   } else {
2884     PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv));
2885   }
2886   PetscFunctionReturn(PETSC_SUCCESS);
2887 }
2888 
2889 static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2890 {
2891   Mat_IS *is = (Mat_IS *)A->data;
2892 
2893   PetscFunctionBegin;
2894   if (is->A->rmap->mapping || is->A->cmap->mapping) {
2895     PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv));
2896   } else {
2897     PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv));
2898   }
2899   PetscFunctionReturn(PETSC_SUCCESS);
2900 }
2901 
2902 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2903 {
2904   Mat_IS *is = (Mat_IS *)A->data;
2905 
2906   PetscFunctionBegin;
2907   if (is->A->rmap->mapping || is->A->cmap->mapping) {
2908     PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv));
2909   } else {
2910     PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv));
2911   }
2912   PetscFunctionReturn(PETSC_SUCCESS);
2913 }
2914 
2915 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns)
2916 {
2917   Mat_IS *is = (Mat_IS *)A->data;
2918 
2919   PetscFunctionBegin;
2920   if (!n) {
2921     is->pure_neumann = PETSC_TRUE;
2922   } else {
2923     PetscInt i;
2924     is->pure_neumann = PETSC_FALSE;
2925 
2926     if (columns) {
2927       PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL));
2928     } else {
2929       PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL));
2930     }
2931     if (diag != 0.) {
2932       const PetscScalar *array;
2933       PetscCall(VecGetArrayRead(is->counter, &array));
2934       for (i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES));
2935       PetscCall(VecRestoreArrayRead(is->counter, &array));
2936     }
2937     PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY));
2938     PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY));
2939   }
2940   PetscFunctionReturn(PETSC_SUCCESS);
2941 }
2942 
2943 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns)
2944 {
2945   Mat_IS   *matis = (Mat_IS *)A->data;
2946   PetscInt  nr, nl, len, i;
2947   PetscInt *lrows;
2948 
2949   PetscFunctionBegin;
2950   if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) {
2951     PetscBool cong;
2952 
2953     PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong));
2954     cong = (PetscBool)(cong && matis->sf == matis->csf);
2955     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");
2956     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");
2957     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");
2958   }
2959   /* get locally owned rows */
2960   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
2961   /* fix right-hand side if needed */
2962   if (x && b) {
2963     const PetscScalar *xx;
2964     PetscScalar       *bb;
2965 
2966     PetscCall(VecGetArrayRead(x, &xx));
2967     PetscCall(VecGetArray(b, &bb));
2968     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
2969     PetscCall(VecRestoreArrayRead(x, &xx));
2970     PetscCall(VecRestoreArray(b, &bb));
2971   }
2972   /* get rows associated to the local matrices */
2973   PetscCall(MatGetSize(matis->A, &nl, NULL));
2974   PetscCall(PetscArrayzero(matis->sf_leafdata, nl));
2975   PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n));
2976   for (i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1;
2977   PetscCall(PetscFree(lrows));
2978   PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2979   PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE));
2980   PetscCall(PetscMalloc1(nl, &lrows));
2981   for (i = 0, nr = 0; i < nl; i++)
2982     if (matis->sf_leafdata[i]) lrows[nr++] = i;
2983   PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns));
2984   PetscCall(PetscFree(lrows));
2985   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2986   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2987   PetscFunctionReturn(PETSC_SUCCESS);
2988 }
2989 
2990 static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2991 {
2992   PetscFunctionBegin;
2993   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE));
2994   PetscFunctionReturn(PETSC_SUCCESS);
2995 }
2996 
2997 static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2998 {
2999   PetscFunctionBegin;
3000   PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE));
3001   PetscFunctionReturn(PETSC_SUCCESS);
3002 }
3003 
3004 static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type)
3005 {
3006   Mat_IS *is = (Mat_IS *)A->data;
3007 
3008   PetscFunctionBegin;
3009   PetscCall(MatAssemblyBegin(is->A, type));
3010   PetscFunctionReturn(PETSC_SUCCESS);
3011 }
3012 
3013 static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type)
3014 {
3015   Mat_IS   *is = (Mat_IS *)A->data;
3016   PetscBool lnnz;
3017 
3018   PetscFunctionBegin;
3019   PetscCall(MatAssemblyEnd(is->A, type));
3020   /* fix for local empty rows/cols */
3021   if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
3022     Mat                    newlA;
3023     ISLocalToGlobalMapping rl2g, cl2g;
3024     IS                     nzr, nzc;
3025     PetscInt               nr, nc, nnzr, nnzc;
3026     PetscBool              lnewl2g, newl2g;
3027 
3028     PetscCall(MatGetSize(is->A, &nr, &nc));
3029     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr));
3030     if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr));
3031     PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc));
3032     if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc));
3033     PetscCall(ISGetSize(nzr, &nnzr));
3034     PetscCall(ISGetSize(nzc, &nnzc));
3035     if (nnzr != nr || nnzc != nc) { /* need new global l2g map */
3036       lnewl2g = PETSC_TRUE;
3037       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
3038 
3039       /* extract valid submatrix */
3040       PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA));
3041     } else { /* local matrix fully populated */
3042       lnewl2g = PETSC_FALSE;
3043       PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A)));
3044       PetscCall(PetscObjectReference((PetscObject)is->A));
3045       newlA = is->A;
3046     }
3047 
3048     /* attach new global l2g map if needed */
3049     if (newl2g) {
3050       IS              zr, zc;
3051       const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs;
3052       PetscInt       *nidxs, i;
3053 
3054       PetscCall(ISComplement(nzr, 0, nr, &zr));
3055       PetscCall(ISComplement(nzc, 0, nc, &zc));
3056       PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs));
3057       PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs));
3058       PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs));
3059       PetscCall(ISGetIndices(zr, &zridxs));
3060       PetscCall(ISGetIndices(zc, &zcidxs));
3061       PetscCall(ISGetLocalSize(zr, &nnzr));
3062       PetscCall(ISGetLocalSize(zc, &nnzc));
3063 
3064       PetscCall(PetscArraycpy(nidxs, ridxs, nr));
3065       for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1;
3066       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g));
3067       PetscCall(PetscArraycpy(nidxs, cidxs, nc));
3068       for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1;
3069       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g));
3070 
3071       PetscCall(ISRestoreIndices(zr, &zridxs));
3072       PetscCall(ISRestoreIndices(zc, &zcidxs));
3073       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs));
3074       PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs));
3075       PetscCall(ISDestroy(&nzr));
3076       PetscCall(ISDestroy(&nzc));
3077       PetscCall(ISDestroy(&zr));
3078       PetscCall(ISDestroy(&zc));
3079       PetscCall(PetscFree(nidxs));
3080       PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g));
3081       PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3082       PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3083     }
3084     PetscCall(MatISSetLocalMat(A, newlA));
3085     PetscCall(MatDestroy(&newlA));
3086     PetscCall(ISDestroy(&nzr));
3087     PetscCall(ISDestroy(&nzc));
3088     is->locempty = PETSC_FALSE;
3089   }
3090   lnnz          = (PetscBool)(is->A->nonzerostate == is->lnnzstate);
3091   is->lnnzstate = is->A->nonzerostate;
3092   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
3093   if (!lnnz) A->nonzerostate++;
3094   PetscFunctionReturn(PETSC_SUCCESS);
3095 }
3096 
3097 static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local)
3098 {
3099   Mat_IS *is = (Mat_IS *)mat->data;
3100 
3101   PetscFunctionBegin;
3102   *local = is->A;
3103   PetscFunctionReturn(PETSC_SUCCESS);
3104 }
3105 
3106 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local)
3107 {
3108   PetscFunctionBegin;
3109   *local = NULL;
3110   PetscFunctionReturn(PETSC_SUCCESS);
3111 }
3112 
3113 /*@
3114   MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix.
3115 
3116   Not Collective.
3117 
3118   Input Parameter:
3119 . mat - the matrix
3120 
3121   Output Parameter:
3122 . local - the local matrix
3123 
3124   Level: intermediate
3125 
3126   Notes:
3127   This can be called if you have precomputed the nonzero structure of the
3128   matrix and want to provide it to the inner matrix object to improve the performance
3129   of the `MatSetValues()` operation.
3130 
3131   Call `MatISRestoreLocalMat()` when finished with the local matrix.
3132 
3133 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()`
3134 @*/
3135 PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local)
3136 {
3137   PetscFunctionBegin;
3138   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3139   PetscAssertPointer(local, 2);
3140   PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local));
3141   PetscFunctionReturn(PETSC_SUCCESS);
3142 }
3143 
3144 /*@
3145   MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()`
3146 
3147   Not Collective.
3148 
3149   Input Parameters:
3150 + mat   - the matrix
3151 - local - the local matrix
3152 
3153   Level: intermediate
3154 
3155 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()`
3156 @*/
3157 PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local)
3158 {
3159   PetscFunctionBegin;
3160   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3161   PetscAssertPointer(local, 2);
3162   PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local));
3163   PetscFunctionReturn(PETSC_SUCCESS);
3164 }
3165 
3166 static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype)
3167 {
3168   Mat_IS *is = (Mat_IS *)mat->data;
3169 
3170   PetscFunctionBegin;
3171   if (is->A) PetscCall(MatSetType(is->A, mtype));
3172   PetscCall(PetscFree(is->lmattype));
3173   PetscCall(PetscStrallocpy(mtype, &is->lmattype));
3174   PetscFunctionReturn(PETSC_SUCCESS);
3175 }
3176 
3177 /*@
3178   MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS`
3179 
3180   Logically Collective.
3181 
3182   Input Parameters:
3183 + mat   - the matrix
3184 - mtype - the local matrix type
3185 
3186   Level: intermediate
3187 
3188 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType`
3189 @*/
3190 PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype)
3191 {
3192   PetscFunctionBegin;
3193   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3194   PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype));
3195   PetscFunctionReturn(PETSC_SUCCESS);
3196 }
3197 
3198 static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local)
3199 {
3200   Mat_IS   *is = (Mat_IS *)mat->data;
3201   PetscInt  nrows, ncols, orows, ocols;
3202   MatType   mtype, otype;
3203   PetscBool sametype = PETSC_TRUE;
3204 
3205   PetscFunctionBegin;
3206   if (is->A && !is->islocalref) {
3207     PetscCall(MatGetSize(is->A, &orows, &ocols));
3208     PetscCall(MatGetSize(local, &nrows, &ncols));
3209     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);
3210     PetscCall(MatGetType(local, &mtype));
3211     PetscCall(MatGetType(is->A, &otype));
3212     PetscCall(PetscStrcmp(mtype, otype, &sametype));
3213   }
3214   PetscCall(PetscObjectReference((PetscObject)local));
3215   PetscCall(MatDestroy(&is->A));
3216   is->A = local;
3217   PetscCall(MatGetType(is->A, &mtype));
3218   PetscCall(MatISSetLocalMatType(mat, mtype));
3219   if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat));
3220   is->lnnzstate = 0;
3221   PetscFunctionReturn(PETSC_SUCCESS);
3222 }
3223 
3224 /*@
3225   MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object.
3226 
3227   Not Collective
3228 
3229   Input Parameters:
3230 + mat   - the matrix
3231 - local - the local matrix
3232 
3233   Level: intermediate
3234 
3235 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()`
3236 @*/
3237 PetscErrorCode MatISSetLocalMat(Mat mat, Mat local)
3238 {
3239   PetscFunctionBegin;
3240   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3241   PetscValidHeaderSpecific(local, MAT_CLASSID, 2);
3242   PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local));
3243   PetscFunctionReturn(PETSC_SUCCESS);
3244 }
3245 
3246 static PetscErrorCode MatZeroEntries_IS(Mat A)
3247 {
3248   Mat_IS *a = (Mat_IS *)A->data;
3249 
3250   PetscFunctionBegin;
3251   PetscCall(MatZeroEntries(a->A));
3252   PetscFunctionReturn(PETSC_SUCCESS);
3253 }
3254 
3255 static PetscErrorCode MatScale_IS(Mat A, PetscScalar a)
3256 {
3257   Mat_IS *is = (Mat_IS *)A->data;
3258 
3259   PetscFunctionBegin;
3260   PetscCall(MatScale(is->A, a));
3261   PetscFunctionReturn(PETSC_SUCCESS);
3262 }
3263 
3264 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3265 {
3266   Mat_IS *is = (Mat_IS *)A->data;
3267 
3268   PetscFunctionBegin;
3269   /* get diagonal of the local matrix */
3270   PetscCall(MatGetDiagonal(is->A, is->y));
3271 
3272   /* scatter diagonal back into global vector */
3273   PetscCall(VecSet(v, 0));
3274   PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
3275   PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE));
3276   PetscFunctionReturn(PETSC_SUCCESS);
3277 }
3278 
3279 static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg)
3280 {
3281   Mat_IS *a = (Mat_IS *)A->data;
3282 
3283   PetscFunctionBegin;
3284   PetscCall(MatSetOption(a->A, op, flg));
3285   PetscFunctionReturn(PETSC_SUCCESS);
3286 }
3287 
3288 static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str)
3289 {
3290   Mat_IS *y = (Mat_IS *)Y->data;
3291   Mat_IS *x;
3292 
3293   PetscFunctionBegin;
3294   if (PetscDefined(USE_DEBUG)) {
3295     PetscBool ismatis;
3296     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis));
3297     PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
3298   }
3299   x = (Mat_IS *)X->data;
3300   PetscCall(MatAXPY(y->A, a, x->A, str));
3301   PetscFunctionReturn(PETSC_SUCCESS);
3302 }
3303 
3304 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat)
3305 {
3306   Mat                    lA;
3307   Mat_IS                *matis = (Mat_IS *)A->data;
3308   ISLocalToGlobalMapping rl2g, cl2g;
3309   IS                     is;
3310   const PetscInt        *rg, *rl;
3311   PetscInt               nrg;
3312   PetscInt               N, M, nrl, i, *idxs;
3313 
3314   PetscFunctionBegin;
3315   PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg));
3316   PetscCall(ISGetLocalSize(row, &nrl));
3317   PetscCall(ISGetIndices(row, &rl));
3318   PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg));
3319   if (PetscDefined(USE_DEBUG)) {
3320     for (i = 0; i < nrl; i++) PetscCheck(rl[i] < nrg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, rl[i], nrg);
3321   }
3322   PetscCall(PetscMalloc1(nrg, &idxs));
3323   /* map from [0,nrl) to row */
3324   for (i = 0; i < nrl; i++) idxs[i] = rl[i];
3325   for (i = nrl; i < nrg; i++) idxs[i] = -1;
3326   PetscCall(ISRestoreIndices(row, &rl));
3327   PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg));
3328   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is));
3329   PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g));
3330   PetscCall(ISDestroy(&is));
3331   /* compute new l2g map for columns */
3332   if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) {
3333     const PetscInt *cg, *cl;
3334     PetscInt        ncg;
3335     PetscInt        ncl;
3336 
3337     PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg));
3338     PetscCall(ISGetLocalSize(col, &ncl));
3339     PetscCall(ISGetIndices(col, &cl));
3340     PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg));
3341     if (PetscDefined(USE_DEBUG)) {
3342       for (i = 0; i < ncl; i++) PetscCheck(cl[i] < ncg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local column index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT, i, cl[i], ncg);
3343     }
3344     PetscCall(PetscMalloc1(ncg, &idxs));
3345     /* map from [0,ncl) to col */
3346     for (i = 0; i < ncl; i++) idxs[i] = cl[i];
3347     for (i = ncl; i < ncg; i++) idxs[i] = -1;
3348     PetscCall(ISRestoreIndices(col, &cl));
3349     PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg));
3350     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is));
3351     PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g));
3352     PetscCall(ISDestroy(&is));
3353   } else {
3354     PetscCall(PetscObjectReference((PetscObject)rl2g));
3355     cl2g = rl2g;
3356   }
3357   /* create the MATIS submatrix */
3358   PetscCall(MatGetSize(A, &M, &N));
3359   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat));
3360   PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N));
3361   PetscCall(MatSetType(*submat, MATIS));
3362   matis             = (Mat_IS *)((*submat)->data);
3363   matis->islocalref = PETSC_TRUE;
3364   PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g));
3365   PetscCall(MatISGetLocalMat(A, &lA));
3366   PetscCall(MatISSetLocalMat(*submat, lA));
3367   PetscCall(MatSetUp(*submat));
3368   PetscCall(MatAssemblyBegin(*submat, MAT_FINAL_ASSEMBLY));
3369   PetscCall(MatAssemblyEnd(*submat, MAT_FINAL_ASSEMBLY));
3370   PetscCall(ISLocalToGlobalMappingDestroy(&rl2g));
3371   PetscCall(ISLocalToGlobalMappingDestroy(&cl2g));
3372 
3373   /* remove unsupported ops */
3374   PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps)));
3375   (*submat)->ops->destroy               = MatDestroy_IS;
3376   (*submat)->ops->setvalueslocal        = MatSetValuesLocal_SubMat_IS;
3377   (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3378   (*submat)->ops->assemblybegin         = MatAssemblyBegin_IS;
3379   (*submat)->ops->assemblyend           = MatAssemblyEnd_IS;
3380   PetscFunctionReturn(PETSC_SUCCESS);
3381 }
3382 
3383 static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems *PetscOptionsObject)
3384 {
3385   Mat_IS   *a = (Mat_IS *)A->data;
3386   char      type[256];
3387   PetscBool flg;
3388 
3389   PetscFunctionBegin;
3390   PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options");
3391   PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL));
3392   PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL));
3393   PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL));
3394   PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL));
3395   PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL));
3396   PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL));
3397   PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL));
3398   PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL));
3399   PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg));
3400   if (flg) PetscCall(MatISSetLocalMatType(A, type));
3401   if (a->A) PetscCall(MatSetFromOptions(a->A));
3402   PetscOptionsHeadEnd();
3403   PetscFunctionReturn(PETSC_SUCCESS);
3404 }
3405 
3406 /*@
3407   MatCreateIS - Creates a "process" unassembled matrix.
3408 
3409   Collective.
3410 
3411   Input Parameters:
3412 + comm - MPI communicator that will share the matrix
3413 . bs   - block size of the matrix
3414 . m    - local size of left vector used in matrix vector products
3415 . n    - local size of right vector used in matrix vector products
3416 . M    - global size of left vector used in matrix vector products
3417 . N    - global size of right vector used in matrix vector products
3418 . rmap - local to global map for rows
3419 - cmap - local to global map for cols
3420 
3421   Output Parameter:
3422 . A - the resulting matrix
3423 
3424   Level: intermediate
3425 
3426   Notes:
3427   `m` and `n` are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors
3428   used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices.
3429 
3430   If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space.
3431 
3432 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()`
3433 @*/
3434 PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A)
3435 {
3436   PetscFunctionBegin;
3437   PetscCall(MatCreate(comm, A));
3438   PetscCall(MatSetSizes(*A, m, n, M, N));
3439   if (bs > 0) PetscCall(MatSetBlockSize(*A, bs));
3440   PetscCall(MatSetType(*A, MATIS));
3441   PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap));
3442   PetscFunctionReturn(PETSC_SUCCESS);
3443 }
3444 
3445 static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has)
3446 {
3447   Mat_IS      *a              = (Mat_IS *)A->data;
3448   MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP};
3449 
3450   PetscFunctionBegin;
3451   *has = PETSC_FALSE;
3452   if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS);
3453   *has = PETSC_TRUE;
3454   for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++)
3455     if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS);
3456   PetscCall(MatHasOperation(a->A, op, has));
3457   PetscFunctionReturn(PETSC_SUCCESS);
3458 }
3459 
3460 static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode)
3461 {
3462   Mat_IS *a = (Mat_IS *)A->data;
3463 
3464   PetscFunctionBegin;
3465   PetscCall(MatSetValuesCOO(a->A, v, imode));
3466   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
3467   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3468   PetscFunctionReturn(PETSC_SUCCESS);
3469 }
3470 
3471 static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3472 {
3473   Mat_IS *a = (Mat_IS *)A->data;
3474 
3475   PetscFunctionBegin;
3476   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3477   if (a->A->rmap->mapping || a->A->cmap->mapping) {
3478     PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j));
3479   } else {
3480     PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3481   }
3482   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3483   A->preallocated = PETSC_TRUE;
3484   PetscFunctionReturn(PETSC_SUCCESS);
3485 }
3486 
3487 static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
3488 {
3489   Mat_IS  *a = (Mat_IS *)A->data;
3490   PetscInt ncoo_i;
3491 
3492   PetscFunctionBegin;
3493   PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping");
3494   PetscCall(PetscIntCast(ncoo, &ncoo_i));
3495   PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i));
3496   PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j));
3497   PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j));
3498   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS));
3499   A->preallocated = PETSC_TRUE;
3500   PetscFunctionReturn(PETSC_SUCCESS);
3501 }
3502 
3503 static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA)
3504 {
3505   Mat_IS          *a = (Mat_IS *)A->data;
3506   PetscObjectState Astate, aAstate       = PETSC_INT_MIN;
3507   PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN;
3508 
3509   PetscFunctionBegin;
3510   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3511   Annzstate = A->nonzerostate;
3512   if (a->assembledA) {
3513     PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate));
3514     aAnnzstate = a->assembledA->nonzerostate;
3515   }
3516   if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA));
3517   if (Astate != aAstate || !a->assembledA) {
3518     MatType     aAtype;
3519     PetscMPIInt size;
3520     PetscInt    rbs, cbs, bs;
3521 
3522     /* the assembled form is used as temporary storage for parallel operations
3523        like createsubmatrices and the like, do not waste device memory */
3524     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
3525     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs));
3526     PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs));
3527     bs = rbs == cbs ? rbs : 1;
3528     if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype));
3529     else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ;
3530     else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ;
3531 
3532     PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA));
3533     PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate));
3534     a->assembledA->nonzerostate = Annzstate;
3535   }
3536   PetscCall(PetscObjectReference((PetscObject)a->assembledA));
3537   *tA = a->assembledA;
3538   if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA));
3539   PetscFunctionReturn(PETSC_SUCCESS);
3540 }
3541 
3542 static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA)
3543 {
3544   PetscFunctionBegin;
3545   PetscCall(MatDestroy(tA));
3546   *tA = NULL;
3547   PetscFunctionReturn(PETSC_SUCCESS);
3548 }
3549 
3550 static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA)
3551 {
3552   Mat_IS          *a = (Mat_IS *)A->data;
3553   PetscObjectState Astate, dAstate = PETSC_INT_MIN;
3554 
3555   PetscFunctionBegin;
3556   PetscCall(PetscObjectStateGet((PetscObject)A, &Astate));
3557   if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate));
3558   if (Astate != dAstate) {
3559     Mat     tA;
3560     MatType ltype;
3561 
3562     PetscCall(MatDestroy(&a->dA));
3563     PetscCall(MatISGetAssembled_Private(A, &tA));
3564     PetscCall(MatGetDiagonalBlock(tA, &a->dA));
3565     PetscCall(MatPropagateSymmetryOptions(tA, a->dA));
3566     PetscCall(MatGetType(a->A, &ltype));
3567     PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA));
3568     PetscCall(PetscObjectReference((PetscObject)a->dA));
3569     PetscCall(MatISRestoreAssembled_Private(A, &tA));
3570     PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate));
3571   }
3572   *dA = a->dA;
3573   PetscFunctionReturn(PETSC_SUCCESS);
3574 }
3575 
3576 static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[])
3577 {
3578   Mat tA;
3579 
3580   PetscFunctionBegin;
3581   PetscCall(MatISGetAssembled_Private(A, &tA));
3582   PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat));
3583   /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */
3584 #if 0
3585   {
3586     Mat_IS    *a = (Mat_IS*)A->data;
3587     MatType   ltype;
3588     VecType   vtype;
3589     char      *flg;
3590 
3591     PetscCall(MatGetType(a->A,&ltype));
3592     PetscCall(MatGetVecType(a->A,&vtype));
3593     PetscCall(PetscStrstr(vtype,"cuda",&flg));
3594     if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg));
3595     if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg));
3596     if (flg) {
3597       for (PetscInt i = 0; i < n; i++) {
3598         Mat sA = (*submat)[i];
3599 
3600         PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA));
3601         (*submat)[i] = sA;
3602       }
3603     }
3604   }
3605 #endif
3606   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3607   PetscFunctionReturn(PETSC_SUCCESS);
3608 }
3609 
3610 static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov)
3611 {
3612   Mat tA;
3613 
3614   PetscFunctionBegin;
3615   PetscCall(MatISGetAssembled_Private(A, &tA));
3616   PetscCall(MatIncreaseOverlap(tA, n, is, ov));
3617   PetscCall(MatISRestoreAssembled_Private(A, &tA));
3618   PetscFunctionReturn(PETSC_SUCCESS);
3619 }
3620 
3621 /*@
3622   MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object
3623 
3624   Not Collective
3625 
3626   Input Parameter:
3627 . A - the matrix
3628 
3629   Output Parameters:
3630 + rmapping - row mapping
3631 - cmapping - column mapping
3632 
3633   Level: advanced
3634 
3635   Note:
3636   The returned map can be different from the one used to construct the `MATIS` object, since it will not contain negative or repeated indices.
3637 
3638 .seealso: [](ch_matrices), `Mat`, `MatIS`, `MatSetLocalToGlobalMapping()`
3639 @*/
3640 PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
3641 {
3642   PetscFunctionBegin;
3643   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3644   PetscValidType(A, 1);
3645   if (rmapping) PetscAssertPointer(rmapping, 2);
3646   if (cmapping) PetscAssertPointer(cmapping, 3);
3647   PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping));
3648   PetscFunctionReturn(PETSC_SUCCESS);
3649 }
3650 
3651 static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c)
3652 {
3653   Mat_IS *a = (Mat_IS *)A->data;
3654 
3655   PetscFunctionBegin;
3656   if (r) *r = a->rmapping;
3657   if (c) *c = a->cmapping;
3658   PetscFunctionReturn(PETSC_SUCCESS);
3659 }
3660 
3661 static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs)
3662 {
3663   Mat_IS *a = (Mat_IS *)A->data;
3664 
3665   PetscFunctionBegin;
3666   if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs));
3667   PetscFunctionReturn(PETSC_SUCCESS);
3668 }
3669 
3670 /*MC
3671   MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`).
3672   This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly".
3673 
3674   Options Database Keys:
3675 + -mat_type is           - Set the matrix type to `MATIS`.
3676 . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps.
3677 . -mat_is_fixempty       - Fix local matrices in case of empty local rows/columns.
3678 - -mat_is_storel2l       - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`.
3679 
3680   Level: intermediate
3681 
3682   Notes:
3683   Options prefix for the inner matrix are given by `-is_mat_xxx`
3684 
3685   You must call `MatSetLocalToGlobalMapping()` before using this matrix type.
3686 
3687   You can do matrix preallocation on the local matrix after you obtain it with
3688   `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()`
3689 
3690 .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP`
3691 M*/
3692 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3693 {
3694   Mat_IS *a;
3695 
3696   PetscFunctionBegin;
3697   PetscCall(PetscNew(&a));
3698   PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype));
3699   A->data = (void *)a;
3700 
3701   /* matrix ops */
3702   PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps)));
3703   A->ops->mult                    = MatMult_IS;
3704   A->ops->multadd                 = MatMultAdd_IS;
3705   A->ops->multtranspose           = MatMultTranspose_IS;
3706   A->ops->multtransposeadd        = MatMultTransposeAdd_IS;
3707   A->ops->destroy                 = MatDestroy_IS;
3708   A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3709   A->ops->setvalues               = MatSetValues_IS;
3710   A->ops->setvaluesblocked        = MatSetValuesBlocked_IS;
3711   A->ops->setvalueslocal          = MatSetValuesLocal_IS;
3712   A->ops->setvaluesblockedlocal   = MatSetValuesBlockedLocal_IS;
3713   A->ops->zerorows                = MatZeroRows_IS;
3714   A->ops->zerorowscolumns         = MatZeroRowsColumns_IS;
3715   A->ops->assemblybegin           = MatAssemblyBegin_IS;
3716   A->ops->assemblyend             = MatAssemblyEnd_IS;
3717   A->ops->view                    = MatView_IS;
3718   A->ops->load                    = MatLoad_IS;
3719   A->ops->zeroentries             = MatZeroEntries_IS;
3720   A->ops->scale                   = MatScale_IS;
3721   A->ops->getdiagonal             = MatGetDiagonal_IS;
3722   A->ops->setoption               = MatSetOption_IS;
3723   A->ops->ishermitian             = MatIsHermitian_IS;
3724   A->ops->issymmetric             = MatIsSymmetric_IS;
3725   A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3726   A->ops->duplicate               = MatDuplicate_IS;
3727   A->ops->missingdiagonal         = MatMissingDiagonal_IS;
3728   A->ops->copy                    = MatCopy_IS;
3729   A->ops->getlocalsubmatrix       = MatGetLocalSubMatrix_IS;
3730   A->ops->createsubmatrix         = MatCreateSubMatrix_IS;
3731   A->ops->axpy                    = MatAXPY_IS;
3732   A->ops->diagonalset             = MatDiagonalSet_IS;
3733   A->ops->shift                   = MatShift_IS;
3734   A->ops->transpose               = MatTranspose_IS;
3735   A->ops->getinfo                 = MatGetInfo_IS;
3736   A->ops->diagonalscale           = MatDiagonalScale_IS;
3737   A->ops->setfromoptions          = MatSetFromOptions_IS;
3738   A->ops->setup                   = MatSetUp_IS;
3739   A->ops->hasoperation            = MatHasOperation_IS;
3740   A->ops->getdiagonalblock        = MatGetDiagonalBlock_IS;
3741   A->ops->createsubmatrices       = MatCreateSubMatrices_IS;
3742   A->ops->increaseoverlap         = MatIncreaseOverlap_IS;
3743   A->ops->setblocksizes           = MatSetBlockSizes_IS;
3744 
3745   /* special MATIS functions */
3746   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS));
3747   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS));
3748   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS));
3749   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS));
3750   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS));
3751   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS));
3752   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS));
3753   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS));
3754   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS));
3755   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ));
3756   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ));
3757   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ));
3758   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ));
3759   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ));
3760   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ));
3761   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ));
3762   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS));
3763   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS));
3764   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS));
3765   PetscFunctionReturn(PETSC_SUCCESS);
3766 }
3767