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