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