xref: /petsc/src/vec/is/utils/isltog.c (revision 21e3ffae2f3b73c0bd738cf6d0a809700fc04bb0)
1 
2 #include <petsc/private/isimpl.h> /*I "petscis.h"  I*/
3 #include <petsc/private/hashmapi.h>
4 #include <petscsf.h>
5 #include <petscviewer.h>
6 
7 PetscClassId          IS_LTOGM_CLASSID;
8 static PetscErrorCode ISLocalToGlobalMappingGetBlockInfo_Private(ISLocalToGlobalMapping, PetscInt *, PetscInt **, PetscInt **, PetscInt ***);
9 
10 typedef struct {
11   PetscInt *globals;
12 } ISLocalToGlobalMapping_Basic;
13 
14 typedef struct {
15   PetscHMapI globalht;
16 } ISLocalToGlobalMapping_Hash;
17 
18 /*@C
19   ISGetPointRange - Returns a description of the points in an `IS` suitable for traversal
20 
21   Not collective
22 
23   Input Parameter:
24 . pointIS - The `IS` object
25 
26   Output Parameters:
27 + pStart - The first index, see notes
28 . pEnd   - One past the last index, see notes
29 - points - The indices, see notes
30 
31   Level: intermediate
32 
33   Notes:
34   If the `IS` contains contiguous indices in an `ISSTRIDE`, then the indices are contained in [pStart, pEnd) and points = NULL. Otherwise, pStart = 0, pEnd = numIndices, and points is an array of the indices. This supports the following pattern
35 .vb
36   ISGetPointRange(is, &pStart, &pEnd, &points);
37   for (p = pStart; p < pEnd; ++p) {
38     const PetscInt point = points ? points[p] : p;
39   }
40   ISRestorePointRange(is, &pstart, &pEnd, &points);
41 .ve
42 
43 .seealso: [](sec_scatter), `IS`, `ISRestorePointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()`
44 @*/
45 PetscErrorCode ISGetPointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt **points)
46 {
47   PetscInt  numCells, step = 1;
48   PetscBool isStride;
49 
50   PetscFunctionBeginHot;
51   *pStart = 0;
52   *points = NULL;
53   PetscCall(ISGetLocalSize(pointIS, &numCells));
54   PetscCall(PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride));
55   if (isStride) PetscCall(ISStrideGetInfo(pointIS, pStart, &step));
56   *pEnd = *pStart + numCells;
57   if (!isStride || step != 1) PetscCall(ISGetIndices(pointIS, points));
58   PetscFunctionReturn(PETSC_SUCCESS);
59 }
60 
61 /*@C
62   ISRestorePointRange - Destroys the traversal description created with `ISGetPointRange()`
63 
64   Not collective
65 
66   Input Parameters:
67 + pointIS - The `IS` object
68 . pStart  - The first index, from `ISGetPointRange()`
69 . pEnd    - One past the last index, from `ISGetPointRange()`
70 - points  - The indices, from `ISGetPointRange()`
71 
72   Level: intermediate
73 
74 .seealso: [](sec_scatter), `IS`, `ISGetPointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()`
75 @*/
76 PetscErrorCode ISRestorePointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt **points)
77 {
78   PetscInt  step = 1;
79   PetscBool isStride;
80 
81   PetscFunctionBeginHot;
82   PetscCall(PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride));
83   if (isStride) PetscCall(ISStrideGetInfo(pointIS, pStart, &step));
84   if (!isStride || step != 1) PetscCall(ISGetIndices(pointIS, points));
85   PetscFunctionReturn(PETSC_SUCCESS);
86 }
87 
88 /*@C
89   ISGetPointSubrange - Configures the input `IS` to be a subrange for the traversal information given
90 
91   Not collective
92 
93   Input Parameters:
94 + subpointIS - The `IS` object to be configured
95 . pStar   t  - The first index of the subrange
96 . pEnd       - One past the last index for the subrange
97 - points     - The indices for the entire range, from `ISGetPointRange()`
98 
99   Output Parameters:
100 . subpointIS - The `IS` object now configured to be a subrange
101 
102   Level: intermediate
103 
104   Note:
105   The input `IS` will now respond properly to calls to `ISGetPointRange()` and return the subrange.
106 
107 .seealso: [](sec_scatter), `IS`, `ISGetPointRange()`, `ISRestorePointRange()`, `ISGetIndices()`, `ISCreateStride()`
108 @*/
109 PetscErrorCode ISGetPointSubrange(IS subpointIS, PetscInt pStart, PetscInt pEnd, const PetscInt *points)
110 {
111   PetscFunctionBeginHot;
112   if (points) {
113     PetscCall(ISSetType(subpointIS, ISGENERAL));
114     PetscCall(ISGeneralSetIndices(subpointIS, pEnd - pStart, &points[pStart], PETSC_USE_POINTER));
115   } else {
116     PetscCall(ISSetType(subpointIS, ISSTRIDE));
117     PetscCall(ISStrideSetStride(subpointIS, pEnd - pStart, pStart, 1));
118   }
119   PetscFunctionReturn(PETSC_SUCCESS);
120 }
121 
122 /* -----------------------------------------------------------------------------------------*/
123 
124 /*
125     Creates the global mapping information in the ISLocalToGlobalMapping structure
126 
127     If the user has not selected how to handle the global to local mapping then use HASH for "large" problems
128 */
129 static PetscErrorCode ISGlobalToLocalMappingSetUp(ISLocalToGlobalMapping mapping)
130 {
131   PetscInt i, *idx = mapping->indices, n = mapping->n, end, start;
132 
133   PetscFunctionBegin;
134   if (mapping->data) PetscFunctionReturn(PETSC_SUCCESS);
135   end   = 0;
136   start = PETSC_MAX_INT;
137 
138   for (i = 0; i < n; i++) {
139     if (idx[i] < 0) continue;
140     if (idx[i] < start) start = idx[i];
141     if (idx[i] > end) end = idx[i];
142   }
143   if (start > end) {
144     start = 0;
145     end   = -1;
146   }
147   mapping->globalstart = start;
148   mapping->globalend   = end;
149   if (!((PetscObject)mapping)->type_name) {
150     if ((end - start) > PetscMax(4 * n, 1000000)) {
151       PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGHASH));
152     } else {
153       PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGBASIC));
154     }
155   }
156   PetscTryTypeMethod(mapping, globaltolocalmappingsetup);
157   PetscFunctionReturn(PETSC_SUCCESS);
158 }
159 
160 static PetscErrorCode ISGlobalToLocalMappingSetUp_Basic(ISLocalToGlobalMapping mapping)
161 {
162   PetscInt                      i, *idx = mapping->indices, n = mapping->n, end, start, *globals;
163   ISLocalToGlobalMapping_Basic *map;
164 
165   PetscFunctionBegin;
166   start = mapping->globalstart;
167   end   = mapping->globalend;
168   PetscCall(PetscNew(&map));
169   PetscCall(PetscMalloc1(end - start + 2, &globals));
170   map->globals = globals;
171   for (i = 0; i < end - start + 1; i++) globals[i] = -1;
172   for (i = 0; i < n; i++) {
173     if (idx[i] < 0) continue;
174     globals[idx[i] - start] = i;
175   }
176   mapping->data = (void *)map;
177   PetscFunctionReturn(PETSC_SUCCESS);
178 }
179 
180 static PetscErrorCode ISGlobalToLocalMappingSetUp_Hash(ISLocalToGlobalMapping mapping)
181 {
182   PetscInt                     i, *idx = mapping->indices, n = mapping->n;
183   ISLocalToGlobalMapping_Hash *map;
184 
185   PetscFunctionBegin;
186   PetscCall(PetscNew(&map));
187   PetscCall(PetscHMapICreate(&map->globalht));
188   for (i = 0; i < n; i++) {
189     if (idx[i] < 0) continue;
190     PetscCall(PetscHMapISet(map->globalht, idx[i], i));
191   }
192   mapping->data = (void *)map;
193   PetscFunctionReturn(PETSC_SUCCESS);
194 }
195 
196 static PetscErrorCode ISLocalToGlobalMappingDestroy_Basic(ISLocalToGlobalMapping mapping)
197 {
198   ISLocalToGlobalMapping_Basic *map = (ISLocalToGlobalMapping_Basic *)mapping->data;
199 
200   PetscFunctionBegin;
201   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
202   PetscCall(PetscFree(map->globals));
203   PetscCall(PetscFree(mapping->data));
204   PetscFunctionReturn(PETSC_SUCCESS);
205 }
206 
207 static PetscErrorCode ISLocalToGlobalMappingDestroy_Hash(ISLocalToGlobalMapping mapping)
208 {
209   ISLocalToGlobalMapping_Hash *map = (ISLocalToGlobalMapping_Hash *)mapping->data;
210 
211   PetscFunctionBegin;
212   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
213   PetscCall(PetscHMapIDestroy(&map->globalht));
214   PetscCall(PetscFree(mapping->data));
215   PetscFunctionReturn(PETSC_SUCCESS);
216 }
217 
218 #define GTOLTYPE _Basic
219 #define GTOLNAME _Basic
220 #define GTOLBS   mapping->bs
221 #define GTOL(g, local) \
222   do { \
223     local = map->globals[g / bs - start]; \
224     if (local >= 0) local = bs * local + (g % bs); \
225   } while (0)
226 
227 #include <../src/vec/is/utils/isltog.h>
228 
229 #define GTOLTYPE _Basic
230 #define GTOLNAME Block_Basic
231 #define GTOLBS   1
232 #define GTOL(g, local) \
233   do { \
234     local = map->globals[g - start]; \
235   } while (0)
236 #include <../src/vec/is/utils/isltog.h>
237 
238 #define GTOLTYPE _Hash
239 #define GTOLNAME _Hash
240 #define GTOLBS   mapping->bs
241 #define GTOL(g, local) \
242   do { \
243     (void)PetscHMapIGet(map->globalht, g / bs, &local); \
244     if (local >= 0) local = bs * local + (g % bs); \
245   } while (0)
246 #include <../src/vec/is/utils/isltog.h>
247 
248 #define GTOLTYPE _Hash
249 #define GTOLNAME Block_Hash
250 #define GTOLBS   1
251 #define GTOL(g, local) \
252   do { \
253     (void)PetscHMapIGet(map->globalht, g, &local); \
254   } while (0)
255 #include <../src/vec/is/utils/isltog.h>
256 
257 /*@
258     ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object
259 
260     Not Collective
261 
262     Input Parameter:
263 .   ltog - local to global mapping
264 
265     Output Parameter:
266 .   nltog - the duplicated local to global mapping
267 
268     Level: advanced
269 
270 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
271 @*/
272 PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog)
273 {
274   ISLocalToGlobalMappingType l2gtype;
275 
276   PetscFunctionBegin;
277   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
278   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog));
279   PetscCall(ISLocalToGlobalMappingGetType(ltog, &l2gtype));
280   PetscCall(ISLocalToGlobalMappingSetType(*nltog, l2gtype));
281   PetscFunctionReturn(PETSC_SUCCESS);
282 }
283 
284 /*@
285     ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping
286 
287     Not Collective
288 
289     Input Parameter:
290 .   ltog - local to global mapping
291 
292     Output Parameter:
293 .   n - the number of entries in the local mapping, `ISLocalToGlobalMappingGetIndices()` returns an array of this length
294 
295     Level: advanced
296 
297 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
298 @*/
299 PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n)
300 {
301   PetscFunctionBegin;
302   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
303   PetscValidIntPointer(n, 2);
304   *n = mapping->bs * mapping->n;
305   PetscFunctionReturn(PETSC_SUCCESS);
306 }
307 
308 /*@C
309    ISLocalToGlobalMappingViewFromOptions - View an `ISLocalToGlobalMapping` based on values in the options database
310 
311    Collective
312 
313    Input Parameters:
314 +  A - the local to global mapping object
315 .  obj - Optional object
316 -  name - command line option
317 
318    Level: intermediate
319 
320 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()`
321 @*/
322 PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[])
323 {
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(A, IS_LTOGM_CLASSID, 1);
326   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
327   PetscFunctionReturn(PETSC_SUCCESS);
328 }
329 
330 /*@C
331     ISLocalToGlobalMappingView - View a local to global mapping
332 
333     Not Collective
334 
335     Input Parameters:
336 +   ltog - local to global mapping
337 -   viewer - viewer
338 
339     Level: advanced
340 
341 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
342 @*/
343 PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer)
344 {
345   PetscInt    i;
346   PetscMPIInt rank;
347   PetscBool   iascii;
348 
349   PetscFunctionBegin;
350   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
351   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer));
352   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
353 
354   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank));
355   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
356   if (iascii) {
357     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer));
358     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
359     for (i = 0; i < mapping->n; i++) {
360       PetscInt bs = mapping->bs, g = mapping->indices[i];
361       if (bs == 1) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, g));
362       else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":%" PetscInt_FMT " %" PetscInt_FMT ":%" PetscInt_FMT "\n", rank, i * bs, (i + 1) * bs, g * bs, (g + 1) * bs));
363     }
364     PetscCall(PetscViewerFlush(viewer));
365     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
366   }
367   PetscFunctionReturn(PETSC_SUCCESS);
368 }
369 
370 /*@
371     ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
372     ordering and a global parallel ordering.
373 
374     Not collective
375 
376     Input Parameter:
377 .   is - index set containing the global numbers for each local number
378 
379     Output Parameter:
380 .   mapping - new mapping data structure
381 
382     Level: advanced
383 
384     Note:
385     the block size of the `IS` determines the block size of the mapping
386 
387 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()`
388 @*/
389 PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping)
390 {
391   PetscInt        n, bs;
392   const PetscInt *indices;
393   MPI_Comm        comm;
394   PetscBool       isblock;
395 
396   PetscFunctionBegin;
397   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
398   PetscValidPointer(mapping, 2);
399 
400   PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
401   PetscCall(ISGetLocalSize(is, &n));
402   PetscCall(PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock));
403   if (!isblock) {
404     PetscCall(ISGetIndices(is, &indices));
405     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping));
406     PetscCall(ISRestoreIndices(is, &indices));
407   } else {
408     PetscCall(ISGetBlockSize(is, &bs));
409     PetscCall(ISBlockGetIndices(is, &indices));
410     PetscCall(ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping));
411     PetscCall(ISBlockRestoreIndices(is, &indices));
412   }
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 /*@C
417     ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n)
418     ordering and a global parallel ordering.
419 
420     Collective
421 
422     Input Parameters:
423 +   sf - star forest mapping contiguous local indices to (rank, offset)
424 -   start - first global index on this process, or `PETSC_DECIDE` to compute contiguous global numbering automatically
425 
426     Output Parameter:
427 .   mapping - new mapping data structure
428 
429     Level: advanced
430 
431     Notes:
432     If any processor calls this with start = `PETSC_DECIDE` then all processors must, otherwise the program will hang.
433 
434 .seealso: [](sec_scatter), `PetscSF`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`
435 @*/
436 PetscErrorCode ISLocalToGlobalMappingCreateSF(PetscSF sf, PetscInt start, ISLocalToGlobalMapping *mapping)
437 {
438   PetscInt i, maxlocal, nroots, nleaves, *globals, *ltog;
439   MPI_Comm comm;
440 
441   PetscFunctionBegin;
442   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
443   PetscValidPointer(mapping, 3);
444   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
445   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL));
446   if (start == PETSC_DECIDE) {
447     start = 0;
448     PetscCallMPI(MPI_Exscan(&nroots, &start, 1, MPIU_INT, MPI_SUM, comm));
449   } else PetscCheck(start >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "start must be nonnegative or PETSC_DECIDE");
450   PetscCall(PetscSFGetLeafRange(sf, NULL, &maxlocal));
451   ++maxlocal;
452   PetscCall(PetscMalloc1(nroots, &globals));
453   PetscCall(PetscMalloc1(maxlocal, &ltog));
454   for (i = 0; i < nroots; i++) globals[i] = start + i;
455   for (i = 0; i < maxlocal; i++) ltog[i] = -1;
456   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globals, ltog, MPI_REPLACE));
457   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globals, ltog, MPI_REPLACE));
458   PetscCall(ISLocalToGlobalMappingCreate(comm, 1, maxlocal, ltog, PETSC_OWN_POINTER, mapping));
459   PetscCall(PetscFree(globals));
460   PetscFunctionReturn(PETSC_SUCCESS);
461 }
462 
463 /*@
464     ISLocalToGlobalMappingSetBlockSize - Sets the blocksize of the mapping
465 
466     Not collective
467 
468     Input Parameters:
469 +   mapping - mapping data structure
470 -   bs - the blocksize
471 
472     Level: advanced
473 
474 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`
475 @*/
476 PetscErrorCode ISLocalToGlobalMappingSetBlockSize(ISLocalToGlobalMapping mapping, PetscInt bs)
477 {
478   PetscInt       *nid;
479   const PetscInt *oid;
480   PetscInt        i, cn, on, obs, nn;
481 
482   PetscFunctionBegin;
483   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
484   PetscCheck(bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid block size %" PetscInt_FMT, bs);
485   if (bs == mapping->bs) PetscFunctionReturn(PETSC_SUCCESS);
486   on  = mapping->n;
487   obs = mapping->bs;
488   oid = mapping->indices;
489   nn  = (on * obs) / bs;
490   PetscCheck((on * obs) % bs == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block size %" PetscInt_FMT " is inconsistent with block size %" PetscInt_FMT " and number of block indices %" PetscInt_FMT, bs, obs, on);
491 
492   PetscCall(PetscMalloc1(nn, &nid));
493   PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &oid));
494   for (i = 0; i < nn; i++) {
495     PetscInt j;
496     for (j = 0, cn = 0; j < bs - 1; j++) {
497       if (oid[i * bs + j] < 0) {
498         cn++;
499         continue;
500       }
501       PetscCheck(oid[i * bs + j] == oid[i * bs + j + 1] - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block sizes %" PetscInt_FMT " and %" PetscInt_FMT " are incompatible with the block indices: non consecutive indices %" PetscInt_FMT " %" PetscInt_FMT, bs, obs, oid[i * bs + j], oid[i * bs + j + 1]);
502     }
503     if (oid[i * bs + j] < 0) cn++;
504     if (cn) {
505       PetscCheck(cn == bs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block sizes %" PetscInt_FMT " and %" PetscInt_FMT " are incompatible with the block indices: invalid number of negative entries in block %" PetscInt_FMT, bs, obs, cn);
506       nid[i] = -1;
507     } else {
508       nid[i] = oid[i * bs] / bs;
509     }
510   }
511   PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &oid));
512 
513   mapping->n  = nn;
514   mapping->bs = bs;
515   PetscCall(PetscFree(mapping->indices));
516   mapping->indices     = nid;
517   mapping->globalstart = 0;
518   mapping->globalend   = 0;
519 
520   /* reset the cached information */
521   PetscCall(PetscFree(mapping->info_procs));
522   PetscCall(PetscFree(mapping->info_numprocs));
523   if (mapping->info_indices) {
524     PetscInt i;
525 
526     PetscCall(PetscFree((mapping->info_indices)[0]));
527     for (i = 1; i < mapping->info_nproc; i++) PetscCall(PetscFree(mapping->info_indices[i]));
528     PetscCall(PetscFree(mapping->info_indices));
529   }
530   mapping->info_cached = PETSC_FALSE;
531 
532   PetscTryTypeMethod(mapping, destroy);
533   PetscFunctionReturn(PETSC_SUCCESS);
534 }
535 
536 /*@
537     ISLocalToGlobalMappingGetBlockSize - Gets the blocksize of the mapping
538     ordering and a global parallel ordering.
539 
540     Not Collective
541 
542     Input Parameters:
543 .   mapping - mapping data structure
544 
545     Output Parameter:
546 .   bs - the blocksize
547 
548     Level: advanced
549 
550 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`
551 @*/
552 PetscErrorCode ISLocalToGlobalMappingGetBlockSize(ISLocalToGlobalMapping mapping, PetscInt *bs)
553 {
554   PetscFunctionBegin;
555   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
556   *bs = mapping->bs;
557   PetscFunctionReturn(PETSC_SUCCESS);
558 }
559 
560 /*@
561     ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n)
562     ordering and a global parallel ordering.
563 
564     Not Collective, but communicator may have more than one process
565 
566     Input Parameters:
567 +   comm - MPI communicator
568 .   bs - the block size
569 .   n - the number of local elements divided by the block size, or equivalently the number of block indices
570 .   indices - the global index for each local element, these do not need to be in increasing order (sorted), these values should not be scaled (i.e. multiplied) by the blocksize bs
571 -   mode - see PetscCopyMode
572 
573     Output Parameter:
574 .   mapping - new mapping data structure
575 
576     Level: advanced
577 
578     Notes:
579     There is one integer value in indices per block and it represents the actual indices bs*idx + j, where j=0,..,bs-1
580 
581     For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType`
582     of `ISLOCALTOGLOBALMAPPINGBASIC` will be used; this uses more memory but is faster; this approach is not scalable for extremely large mappings.
583 
584     For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable.
585     Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.
586 
587 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`, `ISLOCALTOGLOBALMAPPINGBASIC`, `ISLOCALTOGLOBALMAPPINGHASH`
588           `ISLocalToGlobalMappingSetType()`, `ISLocalToGlobalMappingType`
589 @*/
590 PetscErrorCode ISLocalToGlobalMappingCreate(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscInt indices[], PetscCopyMode mode, ISLocalToGlobalMapping *mapping)
591 {
592   PetscInt *in;
593 
594   PetscFunctionBegin;
595   if (n) PetscValidIntPointer(indices, 4);
596   PetscValidPointer(mapping, 6);
597 
598   *mapping = NULL;
599   PetscCall(ISInitializePackage());
600 
601   PetscCall(PetscHeaderCreate(*mapping, IS_LTOGM_CLASSID, "ISLocalToGlobalMapping", "Local to global mapping", "IS", comm, ISLocalToGlobalMappingDestroy, ISLocalToGlobalMappingView));
602   (*mapping)->n  = n;
603   (*mapping)->bs = bs;
604   if (mode == PETSC_COPY_VALUES) {
605     PetscCall(PetscMalloc1(n, &in));
606     PetscCall(PetscArraycpy(in, indices, n));
607     (*mapping)->indices         = in;
608     (*mapping)->dealloc_indices = PETSC_TRUE;
609   } else if (mode == PETSC_OWN_POINTER) {
610     (*mapping)->indices         = (PetscInt *)indices;
611     (*mapping)->dealloc_indices = PETSC_TRUE;
612   } else if (mode == PETSC_USE_POINTER) {
613     (*mapping)->indices = (PetscInt *)indices;
614   } else SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid mode %d", mode);
615   PetscFunctionReturn(PETSC_SUCCESS);
616 }
617 
618 PetscFunctionList ISLocalToGlobalMappingList = NULL;
619 
620 /*@
621    ISLocalToGlobalMappingSetFromOptions - Set mapping options from the options database.
622 
623    Not collective
624 
625    Input Parameters:
626 .  mapping - mapping data structure
627 
628    Level: advanced
629 
630 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`, `ISLOCALTOGLOBALMAPPINGBASIC`, `ISLOCALTOGLOBALMAPPINGHASH`
631           `ISLocalToGlobalMappingSetType()`, `ISLocalToGlobalMappingType`
632 @*/
633 PetscErrorCode ISLocalToGlobalMappingSetFromOptions(ISLocalToGlobalMapping mapping)
634 {
635   char                       type[256];
636   ISLocalToGlobalMappingType defaulttype = "Not set";
637   PetscBool                  flg;
638 
639   PetscFunctionBegin;
640   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
641   PetscCall(ISLocalToGlobalMappingRegisterAll());
642   PetscObjectOptionsBegin((PetscObject)mapping);
643   PetscCall(PetscOptionsFList("-islocaltoglobalmapping_type", "ISLocalToGlobalMapping method", "ISLocalToGlobalMappingSetType", ISLocalToGlobalMappingList, (char *)(((PetscObject)mapping)->type_name) ? ((PetscObject)mapping)->type_name : defaulttype, type, 256, &flg));
644   if (flg) PetscCall(ISLocalToGlobalMappingSetType(mapping, type));
645   PetscOptionsEnd();
646   PetscFunctionReturn(PETSC_SUCCESS);
647 }
648 
649 /*@
650    ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n)
651    ordering and a global parallel ordering.
652 
653    Note Collective
654 
655    Input Parameters:
656 .  mapping - mapping data structure
657 
658    Level: advanced
659 
660 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`
661 @*/
662 PetscErrorCode ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping *mapping)
663 {
664   PetscFunctionBegin;
665   if (!*mapping) PetscFunctionReturn(PETSC_SUCCESS);
666   PetscValidHeaderSpecific((*mapping), IS_LTOGM_CLASSID, 1);
667   if (--((PetscObject)(*mapping))->refct > 0) {
668     *mapping = NULL;
669     PetscFunctionReturn(PETSC_SUCCESS);
670   }
671   if ((*mapping)->dealloc_indices) PetscCall(PetscFree((*mapping)->indices));
672   PetscCall(PetscFree((*mapping)->info_procs));
673   PetscCall(PetscFree((*mapping)->info_numprocs));
674   if ((*mapping)->info_indices) {
675     PetscInt i;
676 
677     PetscCall(PetscFree(((*mapping)->info_indices)[0]));
678     for (i = 1; i < (*mapping)->info_nproc; i++) PetscCall(PetscFree(((*mapping)->info_indices)[i]));
679     PetscCall(PetscFree((*mapping)->info_indices));
680   }
681   if ((*mapping)->info_nodei) PetscCall(PetscFree(((*mapping)->info_nodei)[0]));
682   PetscCall(PetscFree2((*mapping)->info_nodec, (*mapping)->info_nodei));
683   if ((*mapping)->ops->destroy) PetscCall((*(*mapping)->ops->destroy)(*mapping));
684   PetscCall(PetscHeaderDestroy(mapping));
685   *mapping = NULL;
686   PetscFunctionReturn(PETSC_SUCCESS);
687 }
688 
689 /*@
690     ISLocalToGlobalMappingApplyIS - Creates from an `IS` in the local numbering
691     a new index set using the global numbering defined in an `ISLocalToGlobalMapping`
692     context.
693 
694     Collective
695 
696     Input Parameters:
697 +   mapping - mapping between local and global numbering
698 -   is - index set in local numbering
699 
700     Output Parameter:
701 .   newis - index set in global numbering
702 
703     Level: advanced
704 
705     Note:
706     The output `IS` will have the same communicator of the input `IS`.
707 
708 .seealso: [](sec_scatter), `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
709           `ISLocalToGlobalMappingDestroy()`, `ISGlobalToLocalMappingApply()`
710 @*/
711 PetscErrorCode ISLocalToGlobalMappingApplyIS(ISLocalToGlobalMapping mapping, IS is, IS *newis)
712 {
713   PetscInt        n, *idxout;
714   const PetscInt *idxin;
715 
716   PetscFunctionBegin;
717   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
718   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
719   PetscValidPointer(newis, 3);
720 
721   PetscCall(ISGetLocalSize(is, &n));
722   PetscCall(ISGetIndices(is, &idxin));
723   PetscCall(PetscMalloc1(n, &idxout));
724   PetscCall(ISLocalToGlobalMappingApply(mapping, n, idxin, idxout));
725   PetscCall(ISRestoreIndices(is, &idxin));
726   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idxout, PETSC_OWN_POINTER, newis));
727   PetscFunctionReturn(PETSC_SUCCESS);
728 }
729 
730 /*@
731    ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering
732    and converts them to the global numbering.
733 
734    Not collective
735 
736    Input Parameters:
737 +  mapping - the local to global mapping context
738 .  N - number of integers
739 -  in - input indices in local numbering
740 
741    Output Parameter:
742 .  out - indices in global numbering
743 
744    Level: advanced
745 
746    Note:
747    The in and out array parameters may be identical.
748 
749 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`,
750           `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`,
751           `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()`
752 @*/
753 PetscErrorCode ISLocalToGlobalMappingApply(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[])
754 {
755   PetscInt i, bs, Nmax;
756 
757   PetscFunctionBegin;
758   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
759   bs   = mapping->bs;
760   Nmax = bs * mapping->n;
761   if (bs == 1) {
762     const PetscInt *idx = mapping->indices;
763     for (i = 0; i < N; i++) {
764       if (in[i] < 0) {
765         out[i] = in[i];
766         continue;
767       }
768       PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i);
769       out[i] = idx[in[i]];
770     }
771   } else {
772     const PetscInt *idx = mapping->indices;
773     for (i = 0; i < N; i++) {
774       if (in[i] < 0) {
775         out[i] = in[i];
776         continue;
777       }
778       PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i);
779       out[i] = idx[in[i] / bs] * bs + (in[i] % bs);
780     }
781   }
782   PetscFunctionReturn(PETSC_SUCCESS);
783 }
784 
785 /*@
786    ISLocalToGlobalMappingApplyBlock - Takes a list of integers in a local block numbering and converts them to the global block numbering
787 
788    Not collective
789 
790    Input Parameters:
791 +  mapping - the local to global mapping context
792 .  N - number of integers
793 -  in - input indices in local block numbering
794 
795    Output Parameter:
796 .  out - indices in global block numbering
797 
798    Level: advanced
799 
800    Note:
801    The in and out array parameters may be identical.
802 
803    Example:
804      If the index values are {0,1,6,7} set with a call to `ISLocalToGlobalMappingCreate`(`PETSC_COMM_SELF`,2,2,{0,3}) then the mapping applied to 0
805      (the first block) would produce 0 and the mapping applied to 1 (the second block) would produce 3.
806 
807 .seealso: [](sec_scatter), `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`,
808           `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`,
809           `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()`
810 @*/
811 PetscErrorCode ISLocalToGlobalMappingApplyBlock(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[])
812 {
813   PetscInt        i, Nmax;
814   const PetscInt *idx;
815 
816   PetscFunctionBegin;
817   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
818   Nmax = mapping->n;
819   idx  = mapping->indices;
820   for (i = 0; i < N; i++) {
821     if (in[i] < 0) {
822       out[i] = in[i];
823       continue;
824     }
825     PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local block index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i);
826     out[i] = idx[in[i]];
827   }
828   PetscFunctionReturn(PETSC_SUCCESS);
829 }
830 
831 /*@
832     ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers
833     specified with a global numbering.
834 
835     Not collective
836 
837     Input Parameters:
838 +   mapping - mapping between local and global numbering
839 .   type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them)
840            `IS_GTOLM_DROP` - drops the indices with no local value from the output list
841 .   n - number of global indices to map
842 -   idx - global indices to map
843 
844     Output Parameters:
845 +   nout - number of indices in output array (if type == `IS_GTOLM_MASK` then nout = n)
846 -   idxout - local index of each global index, one must pass in an array long enough
847              to hold all the indices. You can call `ISGlobalToLocalMappingApply()` with
848              idxout == NULL to determine the required length (returned in nout)
849              and then allocate the required space and call `ISGlobalToLocalMappingApply()`
850              a second time to set the values.
851 
852     Level: advanced
853 
854     Notes:
855     Either nout or idxout may be NULL. idx and idxout may be identical.
856 
857     For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` of `ISLOCALTOGLOBALMAPPINGBASIC` will be used;
858     this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable.
859     Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.
860 
861     Developer Note:
862     The manual page states that idx and idxout may be identical but the calling
863     sequence declares idx as const so it cannot be the same as idxout.
864 
865 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`,
866           `ISLocalToGlobalMappingDestroy()`
867 @*/
868 PetscErrorCode ISGlobalToLocalMappingApply(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[])
869 {
870   PetscFunctionBegin;
871   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
872   if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping));
873   PetscUseTypeMethod(mapping, globaltolocalmappingapply, type, n, idx, nout, idxout);
874   PetscFunctionReturn(PETSC_SUCCESS);
875 }
876 
877 /*@
878     ISGlobalToLocalMappingApplyIS - Creates from an `IS` in the global numbering
879     a new index set using the local numbering defined in an `ISLocalToGlobalMapping`
880     context.
881 
882     Not collective
883 
884     Input Parameters:
885 +   mapping - mapping between local and global numbering
886 .   type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them)
887            `IS_GTOLM_DROP` - drops the indices with no local value from the output list
888 -   is - index set in global numbering
889 
890     Output Parameters:
891 .   newis - index set in local numbering
892 
893     Level: advanced
894 
895     Note:
896     The output `IS` will be sequential, as it encodes a purely local operation
897 
898 .seealso: [](sec_scatter), `ISGlobalToLocalMapping`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
899           `ISLocalToGlobalMappingDestroy()`
900 @*/
901 PetscErrorCode ISGlobalToLocalMappingApplyIS(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, IS is, IS *newis)
902 {
903   PetscInt        n, nout, *idxout;
904   const PetscInt *idxin;
905 
906   PetscFunctionBegin;
907   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
908   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
909   PetscValidPointer(newis, 4);
910 
911   PetscCall(ISGetLocalSize(is, &n));
912   PetscCall(ISGetIndices(is, &idxin));
913   if (type == IS_GTOLM_MASK) {
914     PetscCall(PetscMalloc1(n, &idxout));
915   } else {
916     PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, NULL));
917     PetscCall(PetscMalloc1(nout, &idxout));
918   }
919   PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, idxout));
920   PetscCall(ISRestoreIndices(is, &idxin));
921   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nout, idxout, PETSC_OWN_POINTER, newis));
922   PetscFunctionReturn(PETSC_SUCCESS);
923 }
924 
925 /*@
926     ISGlobalToLocalMappingApplyBlock - Provides the local block numbering for a list of integers
927     specified with a block global numbering.
928 
929     Not collective
930 
931     Input Parameters:
932 +   mapping - mapping between local and global numbering
933 .   type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them)
934            `IS_GTOLM_DROP` - drops the indices with no local value from the output list
935 .   n - number of global indices to map
936 -   idx - global indices to map
937 
938     Output Parameters:
939 +   nout - number of indices in output array (if type == `IS_GTOLM_MASK` then nout = n)
940 -   idxout - local index of each global index, one must pass in an array long enough
941              to hold all the indices. You can call `ISGlobalToLocalMappingApplyBlock()` with
942              idxout == NULL to determine the required length (returned in nout)
943              and then allocate the required space and call `ISGlobalToLocalMappingApplyBlock()`
944              a second time to set the values.
945 
946     Level: advanced
947 
948     Notes:
949     Either nout or idxout may be NULL. idx and idxout may be identical.
950 
951     For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` of `ISLOCALTOGLOBALMAPPINGBASIC` will be used;
952     this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable.
953     Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.
954 
955     Developer Note:
956     The manual page states that idx and idxout may be identical but the calling
957     sequence declares idx as const so it cannot be the same as idxout.
958 
959 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
960           `ISLocalToGlobalMappingDestroy()`
961 @*/
962 PetscErrorCode ISGlobalToLocalMappingApplyBlock(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[])
963 {
964   PetscFunctionBegin;
965   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
966   if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping));
967   PetscUseTypeMethod(mapping, globaltolocalmappingapplyblock, type, n, idx, nout, idxout);
968   PetscFunctionReturn(PETSC_SUCCESS);
969 }
970 
971 /*@C
972     ISLocalToGlobalMappingGetBlockInfo - Gets the neighbor information for each processor and
973      each index shared by more than one processor
974 
975     Collective
976 
977     Input Parameter:
978 .   mapping - the mapping from local to global indexing
979 
980     Output Parameters:
981 +   nproc - number of processors that are connected to this one
982 .   proc - neighboring processors
983 .   numproc - number of indices for each subdomain (processor)
984 -   indices - indices of nodes (in local numbering) shared with neighbors (sorted by global numbering)
985 
986     Level: advanced
987 
988     Fortran Usage:
989 .vb
990         PetscInt indices[nproc][numprocmax],ierr)
991         ISLocalToGlobalMpngGetInfoSize(ISLocalToGlobalMapping,PetscInt nproc,PetscInt numprocmax,ierr) followed by
992         ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping,PetscInt nproc, PetscInt procs[nproc],PetscInt numprocs[nproc],
993 .ve
994 
995    Fortran Note:
996         There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that procs[], numprocs[] and
997         indices[][] are large enough arrays, either by allocating them dynamically or defining static ones large enough.
998 
999 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1000           `ISLocalToGlobalMappingRestoreInfo()`
1001 @*/
1002 PetscErrorCode ISLocalToGlobalMappingGetBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1003 {
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1006   if (mapping->info_cached) {
1007     *nproc    = mapping->info_nproc;
1008     *procs    = mapping->info_procs;
1009     *numprocs = mapping->info_numprocs;
1010     *indices  = mapping->info_indices;
1011   } else {
1012     PetscCall(ISLocalToGlobalMappingGetBlockInfo_Private(mapping, nproc, procs, numprocs, indices));
1013   }
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016 
1017 static PetscErrorCode ISLocalToGlobalMappingGetBlockInfo_Private(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1018 {
1019   PetscMPIInt  size, rank, tag1, tag2, tag3, *len, *source, imdex;
1020   PetscInt     i, n = mapping->n, Ng, ng, max = 0, *lindices = mapping->indices;
1021   PetscInt    *nprocs, *owner, nsends, *sends, j, *starts, nmax, nrecvs, *recvs, proc;
1022   PetscInt     cnt, scale, *ownedsenders, *nownedsenders, rstart;
1023   PetscInt     node, nownedm, nt, *sends2, nsends2, *starts2, *lens2, *dest, nrecvs2, *starts3, *recvs2, k, *bprocs, *tmp;
1024   PetscInt     first_procs, first_numprocs, *first_indices;
1025   MPI_Request *recv_waits, *send_waits;
1026   MPI_Status   recv_status, *send_status, *recv_statuses;
1027   MPI_Comm     comm;
1028   PetscBool    debug = PETSC_FALSE;
1029 
1030   PetscFunctionBegin;
1031   PetscCall(PetscObjectGetComm((PetscObject)mapping, &comm));
1032   PetscCallMPI(MPI_Comm_size(comm, &size));
1033   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1034   if (size == 1) {
1035     *nproc = 0;
1036     *procs = NULL;
1037     PetscCall(PetscNew(numprocs));
1038     (*numprocs)[0] = 0;
1039     PetscCall(PetscNew(indices));
1040     (*indices)[0] = NULL;
1041     /* save info for reuse */
1042     mapping->info_nproc    = *nproc;
1043     mapping->info_procs    = *procs;
1044     mapping->info_numprocs = *numprocs;
1045     mapping->info_indices  = *indices;
1046     mapping->info_cached   = PETSC_TRUE;
1047     PetscFunctionReturn(PETSC_SUCCESS);
1048   }
1049 
1050   PetscCall(PetscOptionsGetBool(((PetscObject)mapping)->options, NULL, "-islocaltoglobalmappinggetinfo_debug", &debug, NULL));
1051 
1052   /*
1053     Notes on ISLocalToGlobalMappingGetBlockInfo
1054 
1055     globally owned node - the nodes that have been assigned to this processor in global
1056            numbering, just for this routine.
1057 
1058     nontrivial globally owned node - node assigned to this processor that is on a subdomain
1059            boundary (i.e. is has more than one local owner)
1060 
1061     locally owned node - node that exists on this processors subdomain
1062 
1063     nontrivial locally owned node - node that is not in the interior (i.e. has more than one
1064            local subdomain
1065   */
1066   PetscCall(PetscObjectGetNewTag((PetscObject)mapping, &tag1));
1067   PetscCall(PetscObjectGetNewTag((PetscObject)mapping, &tag2));
1068   PetscCall(PetscObjectGetNewTag((PetscObject)mapping, &tag3));
1069 
1070   for (i = 0; i < n; i++) {
1071     if (lindices[i] > max) max = lindices[i];
1072   }
1073   PetscCall(MPIU_Allreduce(&max, &Ng, 1, MPIU_INT, MPI_MAX, comm));
1074   Ng++;
1075   PetscCallMPI(MPI_Comm_size(comm, &size));
1076   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1077   scale = Ng / size + 1;
1078   ng    = scale;
1079   if (rank == size - 1) ng = Ng - scale * (size - 1);
1080   ng     = PetscMax(1, ng);
1081   rstart = scale * rank;
1082 
1083   /* determine ownership ranges of global indices */
1084   PetscCall(PetscMalloc1(2 * size, &nprocs));
1085   PetscCall(PetscArrayzero(nprocs, 2 * size));
1086 
1087   /* determine owners of each local node  */
1088   PetscCall(PetscMalloc1(n, &owner));
1089   for (i = 0; i < n; i++) {
1090     proc                 = lindices[i] / scale; /* processor that globally owns this index */
1091     nprocs[2 * proc + 1] = 1;                   /* processor globally owns at least one of ours */
1092     owner[i]             = proc;
1093     nprocs[2 * proc]++; /* count of how many that processor globally owns of ours */
1094   }
1095   nsends = 0;
1096   for (i = 0; i < size; i++) nsends += nprocs[2 * i + 1];
1097   PetscCall(PetscInfo(mapping, "Number of global owners for my local data %" PetscInt_FMT "\n", nsends));
1098 
1099   /* inform other processors of number of messages and max length*/
1100   PetscCall(PetscMaxSum(comm, nprocs, &nmax, &nrecvs));
1101   PetscCall(PetscInfo(mapping, "Number of local owners for my global data %" PetscInt_FMT "\n", nrecvs));
1102 
1103   /* post receives for owned rows */
1104   PetscCall(PetscMalloc1((2 * nrecvs + 1) * (nmax + 1), &recvs));
1105   PetscCall(PetscMalloc1(nrecvs + 1, &recv_waits));
1106   for (i = 0; i < nrecvs; i++) PetscCallMPI(MPI_Irecv(recvs + 2 * nmax * i, 2 * nmax, MPIU_INT, MPI_ANY_SOURCE, tag1, comm, recv_waits + i));
1107 
1108   /* pack messages containing lists of local nodes to owners */
1109   PetscCall(PetscMalloc1(2 * n + 1, &sends));
1110   PetscCall(PetscMalloc1(size + 1, &starts));
1111   starts[0] = 0;
1112   for (i = 1; i < size; i++) starts[i] = starts[i - 1] + 2 * nprocs[2 * i - 2];
1113   for (i = 0; i < n; i++) {
1114     sends[starts[owner[i]]++] = lindices[i];
1115     sends[starts[owner[i]]++] = i;
1116   }
1117   PetscCall(PetscFree(owner));
1118   starts[0] = 0;
1119   for (i = 1; i < size; i++) starts[i] = starts[i - 1] + 2 * nprocs[2 * i - 2];
1120 
1121   /* send the messages */
1122   PetscCall(PetscMalloc1(nsends + 1, &send_waits));
1123   PetscCall(PetscMalloc1(nsends + 1, &dest));
1124   cnt = 0;
1125   for (i = 0; i < size; i++) {
1126     if (nprocs[2 * i]) {
1127       PetscCallMPI(MPI_Isend(sends + starts[i], 2 * nprocs[2 * i], MPIU_INT, i, tag1, comm, send_waits + cnt));
1128       dest[cnt] = i;
1129       cnt++;
1130     }
1131   }
1132   PetscCall(PetscFree(starts));
1133 
1134   /* wait on receives */
1135   PetscCall(PetscMalloc1(nrecvs + 1, &source));
1136   PetscCall(PetscMalloc1(nrecvs + 1, &len));
1137   cnt = nrecvs;
1138   PetscCall(PetscCalloc1(ng + 1, &nownedsenders));
1139   while (cnt) {
1140     PetscCallMPI(MPI_Waitany(nrecvs, recv_waits, &imdex, &recv_status));
1141     /* unpack receives into our local space */
1142     PetscCallMPI(MPI_Get_count(&recv_status, MPIU_INT, &len[imdex]));
1143     source[imdex] = recv_status.MPI_SOURCE;
1144     len[imdex]    = len[imdex] / 2;
1145     /* count how many local owners for each of my global owned indices */
1146     for (i = 0; i < len[imdex]; i++) nownedsenders[recvs[2 * imdex * nmax + 2 * i] - rstart]++;
1147     cnt--;
1148   }
1149   PetscCall(PetscFree(recv_waits));
1150 
1151   /* count how many globally owned indices are on an edge multiplied by how many processors own them. */
1152   nownedm = 0;
1153   for (i = 0; i < ng; i++) {
1154     if (nownedsenders[i] > 1) nownedm += nownedsenders[i];
1155   }
1156 
1157   /* create single array to contain rank of all local owners of each globally owned index */
1158   PetscCall(PetscMalloc1(nownedm + 1, &ownedsenders));
1159   PetscCall(PetscMalloc1(ng + 1, &starts));
1160   starts[0] = 0;
1161   for (i = 1; i < ng; i++) {
1162     if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1163     else starts[i] = starts[i - 1];
1164   }
1165 
1166   /* for each nontrivial globally owned node list all arriving processors */
1167   for (i = 0; i < nrecvs; i++) {
1168     for (j = 0; j < len[i]; j++) {
1169       node = recvs[2 * i * nmax + 2 * j] - rstart;
1170       if (nownedsenders[node] > 1) ownedsenders[starts[node]++] = source[i];
1171     }
1172   }
1173 
1174   if (debug) { /* -----------------------------------  */
1175     starts[0] = 0;
1176     for (i = 1; i < ng; i++) {
1177       if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1178       else starts[i] = starts[i - 1];
1179     }
1180     for (i = 0; i < ng; i++) {
1181       if (nownedsenders[i] > 1) {
1182         PetscCall(PetscSynchronizedPrintf(comm, "[%d] global node %" PetscInt_FMT " local owner processors: ", rank, i + rstart));
1183         for (j = 0; j < nownedsenders[i]; j++) PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", ownedsenders[starts[i] + j]));
1184         PetscCall(PetscSynchronizedPrintf(comm, "\n"));
1185       }
1186     }
1187     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT));
1188   } /* -----------------------------------  */
1189 
1190   /* wait on original sends */
1191   if (nsends) {
1192     PetscCall(PetscMalloc1(nsends, &send_status));
1193     PetscCallMPI(MPI_Waitall(nsends, send_waits, send_status));
1194     PetscCall(PetscFree(send_status));
1195   }
1196   PetscCall(PetscFree(send_waits));
1197   PetscCall(PetscFree(sends));
1198   PetscCall(PetscFree(nprocs));
1199 
1200   /* pack messages to send back to local owners */
1201   starts[0] = 0;
1202   for (i = 1; i < ng; i++) {
1203     if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1204     else starts[i] = starts[i - 1];
1205   }
1206   nsends2 = nrecvs;
1207   PetscCall(PetscMalloc1(nsends2 + 1, &nprocs)); /* length of each message */
1208   for (i = 0; i < nrecvs; i++) {
1209     nprocs[i] = 1;
1210     for (j = 0; j < len[i]; j++) {
1211       node = recvs[2 * i * nmax + 2 * j] - rstart;
1212       if (nownedsenders[node] > 1) nprocs[i] += 2 + nownedsenders[node];
1213     }
1214   }
1215   nt = 0;
1216   for (i = 0; i < nsends2; i++) nt += nprocs[i];
1217 
1218   PetscCall(PetscMalloc1(nt + 1, &sends2));
1219   PetscCall(PetscMalloc1(nsends2 + 1, &starts2));
1220 
1221   starts2[0] = 0;
1222   for (i = 1; i < nsends2; i++) starts2[i] = starts2[i - 1] + nprocs[i - 1];
1223   /*
1224      Each message is 1 + nprocs[i] long, and consists of
1225        (0) the number of nodes being sent back
1226        (1) the local node number,
1227        (2) the number of processors sharing it,
1228        (3) the processors sharing it
1229   */
1230   for (i = 0; i < nsends2; i++) {
1231     cnt                = 1;
1232     sends2[starts2[i]] = 0;
1233     for (j = 0; j < len[i]; j++) {
1234       node = recvs[2 * i * nmax + 2 * j] - rstart;
1235       if (nownedsenders[node] > 1) {
1236         sends2[starts2[i]]++;
1237         sends2[starts2[i] + cnt++] = recvs[2 * i * nmax + 2 * j + 1];
1238         sends2[starts2[i] + cnt++] = nownedsenders[node];
1239         PetscCall(PetscArraycpy(&sends2[starts2[i] + cnt], &ownedsenders[starts[node]], nownedsenders[node]));
1240         cnt += nownedsenders[node];
1241       }
1242     }
1243   }
1244 
1245   /* receive the message lengths */
1246   nrecvs2 = nsends;
1247   PetscCall(PetscMalloc1(nrecvs2 + 1, &lens2));
1248   PetscCall(PetscMalloc1(nrecvs2 + 1, &starts3));
1249   PetscCall(PetscMalloc1(nrecvs2 + 1, &recv_waits));
1250   for (i = 0; i < nrecvs2; i++) PetscCallMPI(MPI_Irecv(&lens2[i], 1, MPIU_INT, dest[i], tag2, comm, recv_waits + i));
1251 
1252   /* send the message lengths */
1253   for (i = 0; i < nsends2; i++) PetscCallMPI(MPI_Send(&nprocs[i], 1, MPIU_INT, source[i], tag2, comm));
1254 
1255   /* wait on receives of lens */
1256   if (nrecvs2) {
1257     PetscCall(PetscMalloc1(nrecvs2, &recv_statuses));
1258     PetscCallMPI(MPI_Waitall(nrecvs2, recv_waits, recv_statuses));
1259     PetscCall(PetscFree(recv_statuses));
1260   }
1261   PetscCall(PetscFree(recv_waits));
1262 
1263   starts3[0] = 0;
1264   nt         = 0;
1265   for (i = 0; i < nrecvs2 - 1; i++) {
1266     starts3[i + 1] = starts3[i] + lens2[i];
1267     nt += lens2[i];
1268   }
1269   if (nrecvs2) nt += lens2[nrecvs2 - 1];
1270 
1271   PetscCall(PetscMalloc1(nt + 1, &recvs2));
1272   PetscCall(PetscMalloc1(nrecvs2 + 1, &recv_waits));
1273   for (i = 0; i < nrecvs2; i++) PetscCallMPI(MPI_Irecv(recvs2 + starts3[i], lens2[i], MPIU_INT, dest[i], tag3, comm, recv_waits + i));
1274 
1275   /* send the messages */
1276   PetscCall(PetscMalloc1(nsends2 + 1, &send_waits));
1277   for (i = 0; i < nsends2; i++) PetscCallMPI(MPI_Isend(sends2 + starts2[i], nprocs[i], MPIU_INT, source[i], tag3, comm, send_waits + i));
1278 
1279   /* wait on receives */
1280   if (nrecvs2) {
1281     PetscCall(PetscMalloc1(nrecvs2, &recv_statuses));
1282     PetscCallMPI(MPI_Waitall(nrecvs2, recv_waits, recv_statuses));
1283     PetscCall(PetscFree(recv_statuses));
1284   }
1285   PetscCall(PetscFree(recv_waits));
1286   PetscCall(PetscFree(nprocs));
1287 
1288   if (debug) { /* -----------------------------------  */
1289     cnt = 0;
1290     for (i = 0; i < nrecvs2; i++) {
1291       nt = recvs2[cnt++];
1292       for (j = 0; j < nt; j++) {
1293         PetscCall(PetscSynchronizedPrintf(comm, "[%d] local node %" PetscInt_FMT " number of subdomains %" PetscInt_FMT ": ", rank, recvs2[cnt], recvs2[cnt + 1]));
1294         for (k = 0; k < recvs2[cnt + 1]; k++) PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", recvs2[cnt + 2 + k]));
1295         cnt += 2 + recvs2[cnt + 1];
1296         PetscCall(PetscSynchronizedPrintf(comm, "\n"));
1297       }
1298     }
1299     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT));
1300   } /* -----------------------------------  */
1301 
1302   /* count number subdomains for each local node */
1303   PetscCall(PetscCalloc1(size, &nprocs));
1304   cnt = 0;
1305   for (i = 0; i < nrecvs2; i++) {
1306     nt = recvs2[cnt++];
1307     for (j = 0; j < nt; j++) {
1308       for (k = 0; k < recvs2[cnt + 1]; k++) nprocs[recvs2[cnt + 2 + k]]++;
1309       cnt += 2 + recvs2[cnt + 1];
1310     }
1311   }
1312   nt = 0;
1313   for (i = 0; i < size; i++) nt += (nprocs[i] > 0);
1314   *nproc = nt;
1315   PetscCall(PetscMalloc1(nt + 1, procs));
1316   PetscCall(PetscMalloc1(nt + 1, numprocs));
1317   PetscCall(PetscMalloc1(nt + 1, indices));
1318   for (i = 0; i < nt + 1; i++) (*indices)[i] = NULL;
1319   PetscCall(PetscMalloc1(size, &bprocs));
1320   cnt = 0;
1321   for (i = 0; i < size; i++) {
1322     if (nprocs[i] > 0) {
1323       bprocs[i]        = cnt;
1324       (*procs)[cnt]    = i;
1325       (*numprocs)[cnt] = nprocs[i];
1326       PetscCall(PetscMalloc1(nprocs[i], &(*indices)[cnt]));
1327       cnt++;
1328     }
1329   }
1330 
1331   /* make the list of subdomains for each nontrivial local node */
1332   PetscCall(PetscArrayzero(*numprocs, nt));
1333   cnt = 0;
1334   for (i = 0; i < nrecvs2; i++) {
1335     nt = recvs2[cnt++];
1336     for (j = 0; j < nt; j++) {
1337       for (k = 0; k < recvs2[cnt + 1]; k++) (*indices)[bprocs[recvs2[cnt + 2 + k]]][(*numprocs)[bprocs[recvs2[cnt + 2 + k]]]++] = recvs2[cnt];
1338       cnt += 2 + recvs2[cnt + 1];
1339     }
1340   }
1341   PetscCall(PetscFree(bprocs));
1342   PetscCall(PetscFree(recvs2));
1343 
1344   /* sort the node indexing by their global numbers */
1345   nt = *nproc;
1346   for (i = 0; i < nt; i++) {
1347     PetscCall(PetscMalloc1((*numprocs)[i], &tmp));
1348     for (j = 0; j < (*numprocs)[i]; j++) tmp[j] = lindices[(*indices)[i][j]];
1349     PetscCall(PetscSortIntWithArray((*numprocs)[i], tmp, (*indices)[i]));
1350     PetscCall(PetscFree(tmp));
1351   }
1352 
1353   if (debug) { /* -----------------------------------  */
1354     nt = *nproc;
1355     for (i = 0; i < nt; i++) {
1356       PetscCall(PetscSynchronizedPrintf(comm, "[%d] subdomain %" PetscInt_FMT " number of indices %" PetscInt_FMT ": ", rank, (*procs)[i], (*numprocs)[i]));
1357       for (j = 0; j < (*numprocs)[i]; j++) PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", (*indices)[i][j]));
1358       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
1359     }
1360     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT));
1361   } /* -----------------------------------  */
1362 
1363   /* wait on sends */
1364   if (nsends2) {
1365     PetscCall(PetscMalloc1(nsends2, &send_status));
1366     PetscCallMPI(MPI_Waitall(nsends2, send_waits, send_status));
1367     PetscCall(PetscFree(send_status));
1368   }
1369 
1370   PetscCall(PetscFree(starts3));
1371   PetscCall(PetscFree(dest));
1372   PetscCall(PetscFree(send_waits));
1373 
1374   PetscCall(PetscFree(nownedsenders));
1375   PetscCall(PetscFree(ownedsenders));
1376   PetscCall(PetscFree(starts));
1377   PetscCall(PetscFree(starts2));
1378   PetscCall(PetscFree(lens2));
1379 
1380   PetscCall(PetscFree(source));
1381   PetscCall(PetscFree(len));
1382   PetscCall(PetscFree(recvs));
1383   PetscCall(PetscFree(nprocs));
1384   PetscCall(PetscFree(sends2));
1385 
1386   /* put the information about myself as the first entry in the list */
1387   first_procs    = (*procs)[0];
1388   first_numprocs = (*numprocs)[0];
1389   first_indices  = (*indices)[0];
1390   for (i = 0; i < *nproc; i++) {
1391     if ((*procs)[i] == rank) {
1392       (*procs)[0]    = (*procs)[i];
1393       (*numprocs)[0] = (*numprocs)[i];
1394       (*indices)[0]  = (*indices)[i];
1395       (*procs)[i]    = first_procs;
1396       (*numprocs)[i] = first_numprocs;
1397       (*indices)[i]  = first_indices;
1398       break;
1399     }
1400   }
1401 
1402   /* save info for reuse */
1403   mapping->info_nproc    = *nproc;
1404   mapping->info_procs    = *procs;
1405   mapping->info_numprocs = *numprocs;
1406   mapping->info_indices  = *indices;
1407   mapping->info_cached   = PETSC_TRUE;
1408   PetscFunctionReturn(PETSC_SUCCESS);
1409 }
1410 
1411 /*@C
1412     ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockInfo()`
1413 
1414     Collective
1415 
1416     Input Parameter:
1417 .   mapping - the mapping from local to global indexing
1418 
1419     Output Parameters:
1420 +   nproc - number of processors that are connected to this one
1421 .   proc - neighboring processors
1422 .   numproc - number of indices for each processor
1423 -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
1424 
1425     Level: advanced
1426 
1427 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1428           `ISLocalToGlobalMappingGetInfo()`
1429 @*/
1430 PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1431 {
1432   PetscFunctionBegin;
1433   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1434   if (mapping->info_free) {
1435     PetscCall(PetscFree(*numprocs));
1436     if (*indices) {
1437       PetscInt i;
1438 
1439       PetscCall(PetscFree((*indices)[0]));
1440       for (i = 1; i < *nproc; i++) PetscCall(PetscFree((*indices)[i]));
1441       PetscCall(PetscFree(*indices));
1442     }
1443   }
1444   *nproc    = 0;
1445   *procs    = NULL;
1446   *numprocs = NULL;
1447   *indices  = NULL;
1448   PetscFunctionReturn(PETSC_SUCCESS);
1449 }
1450 
1451 /*@C
1452     ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each processor and
1453      each index shared by more than one processor
1454 
1455     Collective
1456 
1457     Input Parameter:
1458 .   mapping - the mapping from local to global indexing
1459 
1460     Output Parameters:
1461 +   nproc - number of processors that are connected to this one
1462 .   proc - neighboring processors
1463 .   numproc - number of indices for each subdomain (processor)
1464 -   indices - indices of nodes (in local numbering) shared with neighbors (sorted by global numbering)
1465 
1466     Level: advanced
1467 
1468     Note:
1469     The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed.
1470 
1471     Fortran Usage:
1472 .vb
1473         PetscInt indices[nproc][numprocmax],ierr)
1474         ISLocalToGlobalMpngGetInfoSize(ISLocalToGlobalMapping,PetscInt nproc,PetscInt numprocmax,ierr) followed by
1475         ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping,PetscInt nproc, PetscInt procs[nproc],PetscInt numprocs[nproc],
1476 .ve
1477 
1478     Fortran Note:
1479         There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that procs[], numprocs[] and
1480         indices[][] are large enough arrays, either by allocating them dynamically or defining static ones large enough.
1481 
1482 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1483           `ISLocalToGlobalMappingRestoreInfo()`
1484 @*/
1485 PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1486 {
1487   PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k;
1488 
1489   PetscFunctionBegin;
1490   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1491   bs = mapping->bs;
1492   PetscCall(ISLocalToGlobalMappingGetBlockInfo(mapping, nproc, procs, &bnumprocs, &bindices));
1493   if (bs > 1) { /* we need to expand the cached info */
1494     PetscCall(PetscCalloc1(*nproc, &*indices));
1495     PetscCall(PetscCalloc1(*nproc, &*numprocs));
1496     for (i = 0; i < *nproc; i++) {
1497       PetscCall(PetscMalloc1(bs * bnumprocs[i], &(*indices)[i]));
1498       for (j = 0; j < bnumprocs[i]; j++) {
1499         for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k;
1500       }
1501       (*numprocs)[i] = bnumprocs[i] * bs;
1502     }
1503     mapping->info_free = PETSC_TRUE;
1504   } else {
1505     *numprocs = bnumprocs;
1506     *indices  = bindices;
1507   }
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 /*@C
1512     ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetInfo()`
1513 
1514     Collective
1515 
1516     Input Parameter:
1517 .   mapping - the mapping from local to global indexing
1518 
1519     Output Parameters:
1520 +   nproc - number of processors that are connected to this one
1521 .   proc - neighboring processors
1522 .   numproc - number of indices for each processor
1523 -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
1524 
1525     Level: advanced
1526 
1527 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1528           `ISLocalToGlobalMappingGetInfo()`
1529 @*/
1530 PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1531 {
1532   PetscFunctionBegin;
1533   PetscCall(ISLocalToGlobalMappingRestoreBlockInfo(mapping, nproc, procs, numprocs, indices));
1534   PetscFunctionReturn(PETSC_SUCCESS);
1535 }
1536 
1537 /*@C
1538     ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information for each MPI rank
1539 
1540     Collective
1541 
1542     Input Parameter:
1543 .   mapping - the mapping from local to global indexing
1544 
1545     Output Parameters:
1546 +   nnodes - number of local nodes (same `ISLocalToGlobalMappingGetSize()`)
1547 .   count - number of neighboring processors per node
1548 -   indices - indices of processes sharing the node (sorted)
1549 
1550     Level: advanced
1551 
1552     Note:
1553     The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed.
1554 
1555 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1556           `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`
1557 @*/
1558 PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *nnodes, PetscInt *count[], PetscInt **indices[])
1559 {
1560   PetscInt n;
1561 
1562   PetscFunctionBegin;
1563   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1564   PetscCall(ISLocalToGlobalMappingGetSize(mapping, &n));
1565   if (!mapping->info_nodec) {
1566     PetscInt i, m, n_neigh, *neigh, *n_shared, **shared;
1567 
1568     PetscCall(PetscMalloc2(n + 1, &mapping->info_nodec, n, &mapping->info_nodei));
1569     PetscCall(ISLocalToGlobalMappingGetInfo(mapping, &n_neigh, &neigh, &n_shared, &shared));
1570     for (i = 0; i < n; i++) mapping->info_nodec[i] = 1;
1571     m                      = n;
1572     mapping->info_nodec[n] = 0;
1573     for (i = 1; i < n_neigh; i++) {
1574       PetscInt j;
1575 
1576       m += n_shared[i];
1577       for (j = 0; j < n_shared[i]; j++) mapping->info_nodec[shared[i][j]] += 1;
1578     }
1579     if (n) PetscCall(PetscMalloc1(m, &mapping->info_nodei[0]));
1580     for (i = 1; i < n; i++) mapping->info_nodei[i] = mapping->info_nodei[i - 1] + mapping->info_nodec[i - 1];
1581     PetscCall(PetscArrayzero(mapping->info_nodec, n));
1582     for (i = 0; i < n; i++) {
1583       mapping->info_nodec[i]    = 1;
1584       mapping->info_nodei[i][0] = neigh[0];
1585     }
1586     for (i = 1; i < n_neigh; i++) {
1587       PetscInt j;
1588 
1589       for (j = 0; j < n_shared[i]; j++) {
1590         PetscInt k = shared[i][j];
1591 
1592         mapping->info_nodei[k][mapping->info_nodec[k]] = neigh[i];
1593         mapping->info_nodec[k] += 1;
1594       }
1595     }
1596     for (i = 0; i < n; i++) PetscCall(PetscSortRemoveDupsInt(&mapping->info_nodec[i], mapping->info_nodei[i]));
1597     PetscCall(ISLocalToGlobalMappingRestoreInfo(mapping, &n_neigh, &neigh, &n_shared, &shared));
1598   }
1599   if (nnodes) *nnodes = n;
1600   if (count) *count = mapping->info_nodec;
1601   if (indices) *indices = mapping->info_nodei;
1602   PetscFunctionReturn(PETSC_SUCCESS);
1603 }
1604 
1605 /*@C
1606     ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetNodeInfo()`
1607 
1608     Collective
1609 
1610     Input Parameter:
1611 .   mapping - the mapping from local to global indexing
1612 
1613     Output Parameters:
1614 +   nnodes - number of local nodes
1615 .   count - number of neighboring processors per node
1616 -   indices - indices of processes sharing the node (sorted)
1617 
1618     Level: advanced
1619 
1620 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1621           `ISLocalToGlobalMappingGetInfo()`
1622 @*/
1623 PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *nnodes, PetscInt *count[], PetscInt **indices[])
1624 {
1625   PetscFunctionBegin;
1626   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1627   if (nnodes) *nnodes = 0;
1628   if (count) *count = NULL;
1629   if (indices) *indices = NULL;
1630   PetscFunctionReturn(PETSC_SUCCESS);
1631 }
1632 
1633 /*MC
1634     ISLocalToGlobalMappingGetIndicesF90 - Get global indices for every local point that is mapped
1635 
1636     Synopsis:
1637     ISLocalToGlobalMappingGetIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)
1638 
1639     Not Collective
1640 
1641     Input Parameter:
1642 .   A - the matrix
1643 
1644     Output Parameters:
1645 .   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1646 
1647     Level: advanced
1648 
1649     Note:
1650     Use  `ISLocalToGlobalMappingGetIndicesF90()` when you no longer need access to the data
1651 
1652 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`, `ISLocalToGlobalMappingRestoreIndicesF90()`
1653 M*/
1654 
1655 /*MC
1656     ISLocalToGlobalMappingRestoreIndicesF90 - restores the global indices for every local point that is mapped obtained with `ISLocalToGlobalMappingGetIndicesF90()`
1657 
1658     Synopsis:
1659     ISLocalToGlobalMappingRestoreIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)
1660 
1661     Not Collective
1662 
1663     Input Parameters:
1664 +   A - the matrix
1665 -   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1666 
1667     Level: advanced
1668 
1669 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`, `ISLocalToGlobalMappingGetIndicesF90()`
1670 M*/
1671 
1672 /*@C
1673    ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped
1674 
1675    Not Collective
1676 
1677    Input Parameter:
1678 . ltog - local to global mapping
1679 
1680    Output Parameter:
1681 . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1682 
1683    Level: advanced
1684 
1685    Note:
1686     `ISLocalToGlobalMappingGetSize()` returns the length the this array
1687 
1688 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`, `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1689 @*/
1690 PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1691 {
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1694   PetscValidPointer(array, 2);
1695   if (ltog->bs == 1) {
1696     *array = ltog->indices;
1697   } else {
1698     PetscInt       *jj, k, i, j, n = ltog->n, bs = ltog->bs;
1699     const PetscInt *ii;
1700 
1701     PetscCall(PetscMalloc1(bs * n, &jj));
1702     *array = jj;
1703     k      = 0;
1704     ii     = ltog->indices;
1705     for (i = 0; i < n; i++)
1706       for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j;
1707   }
1708   PetscFunctionReturn(PETSC_SUCCESS);
1709 }
1710 
1711 /*@C
1712    ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with `ISLocalToGlobalMappingGetIndices()`
1713 
1714    Not Collective
1715 
1716    Input Parameters:
1717 + ltog - local to global mapping
1718 - array - array of indices
1719 
1720    Level: advanced
1721 
1722 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1723 @*/
1724 PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1725 {
1726   PetscFunctionBegin;
1727   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1728   PetscValidPointer(array, 2);
1729   PetscCheck(ltog->bs != 1 || *array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
1730 
1731   if (ltog->bs > 1) PetscCall(PetscFree(*(void **)array));
1732   PetscFunctionReturn(PETSC_SUCCESS);
1733 }
1734 
1735 /*@C
1736    ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block
1737 
1738    Not Collective
1739 
1740    Input Parameter:
1741 . ltog - local to global mapping
1742 
1743    Output Parameter:
1744 . array - array of indices
1745 
1746    Level: advanced
1747 
1748 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1749 @*/
1750 PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1751 {
1752   PetscFunctionBegin;
1753   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1754   PetscValidPointer(array, 2);
1755   *array = ltog->indices;
1756   PetscFunctionReturn(PETSC_SUCCESS);
1757 }
1758 
1759 /*@C
1760    ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with `ISLocalToGlobalMappingGetBlockIndices()`
1761 
1762    Not Collective
1763 
1764    Input Parameters:
1765 + ltog - local to global mapping
1766 - array - array of indices
1767 
1768    Level: advanced
1769 
1770 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1771 @*/
1772 PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1773 {
1774   PetscFunctionBegin;
1775   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1776   PetscValidPointer(array, 2);
1777   PetscCheck(*array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
1778   *array = NULL;
1779   PetscFunctionReturn(PETSC_SUCCESS);
1780 }
1781 
1782 /*@C
1783    ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings
1784 
1785    Not Collective
1786 
1787    Input Parameters:
1788 + comm - communicator for the new mapping, must contain the communicator of every mapping to concatenate
1789 . n - number of mappings to concatenate
1790 - ltogs - local to global mappings
1791 
1792    Output Parameter:
1793 . ltogcat - new mapping
1794 
1795    Level: advanced
1796 
1797    Note:
1798    This currently always returns a mapping with block size of 1
1799 
1800    Developer Note:
1801    If all the input mapping have the same block size we could easily handle that as a special case
1802 
1803 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`
1804 @*/
1805 PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat)
1806 {
1807   PetscInt i, cnt, m, *idx;
1808 
1809   PetscFunctionBegin;
1810   PetscCheck(n >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Must have a non-negative number of mappings, given %" PetscInt_FMT, n);
1811   if (n > 0) PetscValidPointer(ltogs, 3);
1812   for (i = 0; i < n; i++) PetscValidHeaderSpecific(ltogs[i], IS_LTOGM_CLASSID, 3);
1813   PetscValidPointer(ltogcat, 4);
1814   for (cnt = 0, i = 0; i < n; i++) {
1815     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
1816     cnt += m;
1817   }
1818   PetscCall(PetscMalloc1(cnt, &idx));
1819   for (cnt = 0, i = 0; i < n; i++) {
1820     const PetscInt *subidx;
1821     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
1822     PetscCall(ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx));
1823     PetscCall(PetscArraycpy(&idx[cnt], subidx, m));
1824     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx));
1825     cnt += m;
1826   }
1827   PetscCall(ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat));
1828   PetscFunctionReturn(PETSC_SUCCESS);
1829 }
1830 
1831 /*MC
1832       ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
1833                                     used this is good for only small and moderate size problems.
1834 
1835    Options Database Keys:
1836 .   -islocaltoglobalmapping_type basic - select this method
1837 
1838    Level: beginner
1839 
1840    Developer Note:
1841    This stores all the mapping information on each MPI rank.
1842 
1843 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH`
1844 M*/
1845 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog)
1846 {
1847   PetscFunctionBegin;
1848   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Basic;
1849   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Basic;
1850   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic;
1851   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Basic;
1852   PetscFunctionReturn(PETSC_SUCCESS);
1853 }
1854 
1855 /*MC
1856       ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
1857                                     used this is good for large memory problems.
1858 
1859    Options Database Keys:
1860 .   -islocaltoglobalmapping_type hash - select this method
1861 
1862    Level: beginner
1863 
1864    Note:
1865     This is selected automatically for large problems if the user does not set the type.
1866 
1867 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGBASIC`
1868 M*/
1869 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog)
1870 {
1871   PetscFunctionBegin;
1872   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Hash;
1873   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Hash;
1874   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash;
1875   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Hash;
1876   PetscFunctionReturn(PETSC_SUCCESS);
1877 }
1878 
1879 /*@C
1880     ISLocalToGlobalMappingRegister -  Registers a method for applying a global to local mapping with an `ISLocalToGlobalMapping`
1881 
1882    Not Collective
1883 
1884    Input Parameters:
1885 +  sname - name of a new method
1886 -  routine_create - routine to create method context
1887 
1888    Sample usage:
1889 .vb
1890    ISLocalToGlobalMappingRegister("my_mapper",MyCreate);
1891 .ve
1892 
1893    Then, your mapping can be chosen with the procedural interface via
1894 $     ISLocalToGlobalMappingSetType(ltog,"my_mapper")
1895    or at runtime via the option
1896 $     -islocaltoglobalmapping_type my_mapper
1897 
1898    Level: advanced
1899 
1900    Note:
1901    `ISLocalToGlobalMappingRegister()` may be called multiple times to add several user-defined mappings.
1902 
1903 .seealso: [](sec_scatter), `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`,
1904           `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`
1905 @*/
1906 PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping))
1907 {
1908   PetscFunctionBegin;
1909   PetscCall(ISInitializePackage());
1910   PetscCall(PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function));
1911   PetscFunctionReturn(PETSC_SUCCESS);
1912 }
1913 
1914 /*@C
1915    ISLocalToGlobalMappingSetType - Sets the implementation type `ISLocalToGlobalMapping` will use
1916 
1917    Logically Collective
1918 
1919    Input Parameters:
1920 +  ltog - the `ISLocalToGlobalMapping` object
1921 -  type - a known method
1922 
1923    Options Database Key:
1924 .  -islocaltoglobalmapping_type  <method> - Sets the method; use -help for a list of available methods (for instance, basic or hash)
1925 
1926   Level: intermediate
1927 
1928    Notes:
1929    See "petsc/include/petscis.h" for available methods
1930 
1931   Normally, it is best to use the `ISLocalToGlobalMappingSetFromOptions()` command and
1932   then set the `ISLocalToGlobalMappingType` from the options database rather than by using
1933   this routine.
1934 
1935   Developer Note:
1936   `ISLocalToGlobalMappingRegister()` is used to add new types to `ISLocalToGlobalMappingList` from which they
1937   are accessed by `ISLocalToGlobalMappingSetType()`.
1938 
1939 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()`
1940 @*/
1941 PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type)
1942 {
1943   PetscBool match;
1944   PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL;
1945 
1946   PetscFunctionBegin;
1947   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1948   if (type) PetscValidCharPointer(type, 2);
1949 
1950   PetscCall(PetscObjectTypeCompare((PetscObject)ltog, type, &match));
1951   if (match) PetscFunctionReturn(PETSC_SUCCESS);
1952 
1953   /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */
1954   if (type) {
1955     PetscCall(PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r));
1956     PetscCheck(r, PetscObjectComm((PetscObject)ltog), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested ISLocalToGlobalMapping type %s", type);
1957   }
1958   /* Destroy the previous private LTOG context */
1959   PetscTryTypeMethod(ltog, destroy);
1960   ltog->ops->destroy = NULL;
1961 
1962   PetscCall(PetscObjectChangeTypeName((PetscObject)ltog, type));
1963   if (r) PetscCall((*r)(ltog));
1964   PetscFunctionReturn(PETSC_SUCCESS);
1965 }
1966 
1967 /*@C
1968    ISLocalToGlobalMappingGetType - Get the type of the `ISLocalToGlobalMapping`
1969 
1970    Not Collective
1971 
1972    Input Parameter:
1973 .  ltog - the `ISLocalToGlobalMapping` object
1974 
1975    Output Parameter:
1976 .  type - the type
1977 
1978    Level: intermediate
1979 
1980 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`
1981 @*/
1982 PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type)
1983 {
1984   PetscFunctionBegin;
1985   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1986   PetscValidPointer(type, 2);
1987   *type = ((PetscObject)ltog)->type_name;
1988   PetscFunctionReturn(PETSC_SUCCESS);
1989 }
1990 
1991 PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE;
1992 
1993 /*@C
1994   ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the `IS` package.
1995 
1996   Not Collective
1997 
1998   Level: advanced
1999 
2000 .seealso: [](sec_scatter), `ISRegister()`, `ISLocalToGlobalRegister()`
2001 @*/
2002 PetscErrorCode ISLocalToGlobalMappingRegisterAll(void)
2003 {
2004   PetscFunctionBegin;
2005   if (ISLocalToGlobalMappingRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
2006   ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE;
2007   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic));
2008   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash));
2009   PetscFunctionReturn(PETSC_SUCCESS);
2010 }
2011