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