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