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