xref: /petsc/src/vec/is/utils/isltog.c (revision eb58fe77b0e5d125a3d55c974ef2bc19b73e6b04)
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 /*@C
92   ISGetPointSubrange - Configures the input `IS` to be a subrange for the traversal information given
93 
94   Not Collective
95 
96   Input Parameters:
97 + subpointIS - The `IS` object to be configured
98 . pStart     - The first index of the subrange
99 . pEnd       - One past the last index for the subrange
100 - points     - The indices for the entire range, from `ISGetPointRange()`
101 
102   Output Parameters:
103 . subpointIS - The `IS` object now configured to be a subrange
104 
105   Level: intermediate
106 
107   Note:
108   The input `IS` will now respond properly to calls to `ISGetPointRange()` and return the subrange.
109 
110 .seealso: [](sec_scatter), `IS`, `ISGetPointRange()`, `ISRestorePointRange()`, `ISGetIndices()`, `ISCreateStride()`
111 @*/
112 PetscErrorCode ISGetPointSubrange(IS subpointIS, PetscInt pStart, PetscInt pEnd, const PetscInt *points)
113 {
114   PetscFunctionBeginHot;
115   if (points) {
116     PetscCall(ISSetType(subpointIS, ISGENERAL));
117     PetscCall(ISGeneralSetIndices(subpointIS, pEnd - pStart, &points[pStart], PETSC_USE_POINTER));
118   } else {
119     PetscCall(ISSetType(subpointIS, ISSTRIDE));
120     PetscCall(ISStrideSetStride(subpointIS, pEnd - pStart, pStart, 1));
121   }
122   PetscFunctionReturn(PETSC_SUCCESS);
123 }
124 
125 /* -----------------------------------------------------------------------------------------*/
126 
127 /*
128     Creates the global mapping information in the ISLocalToGlobalMapping structure
129 
130     If the user has not selected how to handle the global to local mapping then use HASH for "large" problems
131 */
132 static PetscErrorCode ISGlobalToLocalMappingSetUp(ISLocalToGlobalMapping mapping)
133 {
134   PetscInt i, *idx = mapping->indices, n = mapping->n, end, start;
135 
136   PetscFunctionBegin;
137   if (mapping->data) PetscFunctionReturn(PETSC_SUCCESS);
138   end   = 0;
139   start = PETSC_MAX_INT;
140 
141   for (i = 0; i < n; i++) {
142     if (idx[i] < 0) continue;
143     if (idx[i] < start) start = idx[i];
144     if (idx[i] > end) end = idx[i];
145   }
146   if (start > end) {
147     start = 0;
148     end   = -1;
149   }
150   mapping->globalstart = start;
151   mapping->globalend   = end;
152   if (!((PetscObject)mapping)->type_name) {
153     if ((end - start) > PetscMax(4 * n, 1000000)) {
154       PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGHASH));
155     } else {
156       PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGBASIC));
157     }
158   }
159   PetscTryTypeMethod(mapping, globaltolocalmappingsetup);
160   PetscFunctionReturn(PETSC_SUCCESS);
161 }
162 
163 static PetscErrorCode ISGlobalToLocalMappingSetUp_Basic(ISLocalToGlobalMapping mapping)
164 {
165   PetscInt                      i, *idx = mapping->indices, n = mapping->n, end, start, *globals;
166   ISLocalToGlobalMapping_Basic *map;
167 
168   PetscFunctionBegin;
169   start = mapping->globalstart;
170   end   = mapping->globalend;
171   PetscCall(PetscNew(&map));
172   PetscCall(PetscMalloc1(end - start + 2, &globals));
173   map->globals = globals;
174   for (i = 0; i < end - start + 1; i++) globals[i] = -1;
175   for (i = 0; i < n; i++) {
176     if (idx[i] < 0) continue;
177     globals[idx[i] - start] = i;
178   }
179   mapping->data = (void *)map;
180   PetscFunctionReturn(PETSC_SUCCESS);
181 }
182 
183 static PetscErrorCode ISGlobalToLocalMappingSetUp_Hash(ISLocalToGlobalMapping mapping)
184 {
185   PetscInt                     i, *idx = mapping->indices, n = mapping->n;
186   ISLocalToGlobalMapping_Hash *map;
187 
188   PetscFunctionBegin;
189   PetscCall(PetscNew(&map));
190   PetscCall(PetscHMapICreate(&map->globalht));
191   for (i = 0; i < n; i++) {
192     if (idx[i] < 0) continue;
193     PetscCall(PetscHMapISet(map->globalht, idx[i], i));
194   }
195   mapping->data = (void *)map;
196   PetscFunctionReturn(PETSC_SUCCESS);
197 }
198 
199 static PetscErrorCode ISLocalToGlobalMappingDestroy_Basic(ISLocalToGlobalMapping mapping)
200 {
201   ISLocalToGlobalMapping_Basic *map = (ISLocalToGlobalMapping_Basic *)mapping->data;
202 
203   PetscFunctionBegin;
204   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
205   PetscCall(PetscFree(map->globals));
206   PetscCall(PetscFree(mapping->data));
207   PetscFunctionReturn(PETSC_SUCCESS);
208 }
209 
210 static PetscErrorCode ISLocalToGlobalMappingDestroy_Hash(ISLocalToGlobalMapping mapping)
211 {
212   ISLocalToGlobalMapping_Hash *map = (ISLocalToGlobalMapping_Hash *)mapping->data;
213 
214   PetscFunctionBegin;
215   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
216   PetscCall(PetscHMapIDestroy(&map->globalht));
217   PetscCall(PetscFree(mapping->data));
218   PetscFunctionReturn(PETSC_SUCCESS);
219 }
220 
221 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   PetscFunctionReturn(PETSC_SUCCESS);
233 }
234 
235 #define GTOLTYPE _Basic
236 #define GTOLNAME _Basic
237 #define GTOLBS   mapping->bs
238 #define GTOL(g, local) \
239   do { \
240     local = map->globals[g / bs - start]; \
241     if (local >= 0) local = bs * local + (g % bs); \
242   } while (0)
243 
244 #include <../src/vec/is/utils/isltog.h>
245 
246 #define GTOLTYPE _Basic
247 #define GTOLNAME Block_Basic
248 #define GTOLBS   1
249 #define GTOL(g, local) \
250   do { \
251     local = map->globals[g - start]; \
252   } while (0)
253 #include <../src/vec/is/utils/isltog.h>
254 
255 #define GTOLTYPE _Hash
256 #define GTOLNAME _Hash
257 #define GTOLBS   mapping->bs
258 #define GTOL(g, local) \
259   do { \
260     (void)PetscHMapIGet(map->globalht, g / bs, &local); \
261     if (local >= 0) local = bs * local + (g % bs); \
262   } while (0)
263 #include <../src/vec/is/utils/isltog.h>
264 
265 #define GTOLTYPE _Hash
266 #define GTOLNAME Block_Hash
267 #define GTOLBS   1
268 #define GTOL(g, local) \
269   do { \
270     (void)PetscHMapIGet(map->globalht, g, &local); \
271   } while (0)
272 #include <../src/vec/is/utils/isltog.h>
273 
274 /*@
275   ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object
276 
277   Not Collective
278 
279   Input Parameter:
280 . ltog - local to global mapping
281 
282   Output Parameter:
283 . nltog - the duplicated local to global mapping
284 
285   Level: advanced
286 
287 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
288 @*/
289 PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog)
290 {
291   ISLocalToGlobalMappingType l2gtype;
292 
293   PetscFunctionBegin;
294   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
295   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog));
296   PetscCall(ISLocalToGlobalMappingGetType(ltog, &l2gtype));
297   PetscCall(ISLocalToGlobalMappingSetType(*nltog, l2gtype));
298   PetscFunctionReturn(PETSC_SUCCESS);
299 }
300 
301 /*@
302   ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping
303 
304   Not Collective
305 
306   Input Parameter:
307 . mapping - local to global mapping
308 
309   Output Parameter:
310 . n - the number of entries in the local mapping, `ISLocalToGlobalMappingGetIndices()` returns an array of this length
311 
312   Level: advanced
313 
314 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
315 @*/
316 PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
320   PetscAssertPointer(n, 2);
321   *n = mapping->bs * mapping->n;
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 
325 /*@C
326   ISLocalToGlobalMappingViewFromOptions - View an `ISLocalToGlobalMapping` based on values in the options database
327 
328   Collective
329 
330   Input Parameters:
331 + A    - the local to global mapping object
332 . obj  - Optional object that provides the options prefix used for the options database query
333 - name - command line option
334 
335   Level: intermediate
336 
337   Note:
338   See `PetscObjectViewFromOptions()` for the available `PetscViewer` and `PetscViewerFormat`
339 
340 .seealso: [](sec_scatter), `PetscViewer`, ``ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()`
341 @*/
342 PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[])
343 {
344   PetscFunctionBegin;
345   PetscValidHeaderSpecific(A, IS_LTOGM_CLASSID, 1);
346   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
347   PetscFunctionReturn(PETSC_SUCCESS);
348 }
349 
350 /*@C
351   ISLocalToGlobalMappingView - View a local to global mapping
352 
353   Collective on viewer
354 
355   Input Parameters:
356 + mapping - local to global mapping
357 - viewer  - viewer
358 
359   Level: intermediate
360 
361 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
362 @*/
363 PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer)
364 {
365   PetscBool         iascii, isbinary;
366   PetscViewerFormat format;
367 
368   PetscFunctionBegin;
369   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
370   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer));
371   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
372 
373   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
374   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
375   PetscCall(PetscViewerGetFormat(viewer, &format));
376   if (iascii) {
377     if (format == PETSC_VIEWER_ASCII_MATLAB) {
378       const PetscInt *idxs;
379       IS              is;
380       const char     *name = ((PetscObject)mapping)->name;
381       char            iname[PETSC_MAX_PATH_LEN];
382 
383       PetscCall(PetscSNPrintf(iname, sizeof(iname), "%sl2g", name ? name : ""));
384       PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &idxs));
385       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mapping->n * mapping->bs, idxs, PETSC_USE_POINTER, &is));
386       PetscCall(PetscObjectSetName((PetscObject)is, iname));
387       PetscCall(ISView(is, viewer));
388       PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &idxs));
389       PetscCall(ISDestroy(&is));
390     } else {
391       PetscMPIInt rank;
392 
393       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank));
394       PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer));
395       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
396       for (PetscInt i = 0; i < mapping->n; i++) {
397         PetscInt bs = mapping->bs, g = mapping->indices[i];
398         if (bs == 1) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, g));
399         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));
400       }
401       PetscCall(PetscViewerFlush(viewer));
402       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
403     }
404   } else if (isbinary) {
405     PetscBool skipHeader;
406 
407     PetscCall(PetscViewerSetUp(viewer));
408     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
409     if (!skipHeader) {
410       PetscMPIInt size;
411       PetscInt    tr[3];
412 
413       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
414       tr[0] = IS_LTOGM_FILE_CLASSID;
415       tr[1] = mapping->bs;
416       tr[2] = size;
417       PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT));
418       PetscCall(PetscViewerBinaryWriteAll(viewer, &mapping->n, 1, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
419     }
420     /* write block indices */
421     PetscCall(PetscViewerBinaryWriteAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
422   }
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   ISLocalToGlobalMappingLoad - Loads a local-to-global mapping that has been stored in binary format.
428 
429   Collective on viewer
430 
431   Input Parameters:
432 + mapping - the newly loaded map, this needs to have been created with `ISLocalToGlobalMappingCreate()` or some related function before a call to `ISLocalToGlobalMappingLoad()`
433 - viewer  - binary file viewer, obtained from `PetscViewerBinaryOpen()`
434 
435   Level: intermediate
436 
437 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView()`, `ISLocalToGlobalMappingCreate()`
438 @*/
439 PetscErrorCode ISLocalToGlobalMappingLoad(ISLocalToGlobalMapping mapping, PetscViewer viewer)
440 {
441   PetscBool isbinary, skipHeader;
442 
443   PetscFunctionBegin;
444   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
445   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
446   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
447   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);
448 
449   /* reset previous data */
450   PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping));
451 
452   PetscCall(PetscViewerSetUp(viewer));
453   PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
454 
455   /* When skipping header, it assumes bs and n have been already set */
456   if (!skipHeader) {
457     MPI_Comm comm = PetscObjectComm((PetscObject)viewer);
458     PetscInt tr[3], nold = mapping->n, *sizes, nmaps = PETSC_DECIDE, st = 0;
459 
460     PetscCall(PetscViewerBinaryRead(viewer, tr, 3, NULL, PETSC_INT));
461     PetscCheck(tr[0] == IS_LTOGM_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a local-to-global map next in file");
462 
463     mapping->bs = tr[1];
464     PetscCall(PetscMalloc1(tr[2], &sizes));
465     PetscCall(PetscViewerBinaryRead(viewer, sizes, tr[2], NULL, PETSC_INT));
466 
467     /* consume the input, read multiple maps per process if needed */
468     PetscCall(PetscSplitOwnership(comm, &nmaps, &tr[2]));
469     PetscCallMPI(MPI_Exscan(&nmaps, &st, 1, MPIU_INT, MPI_SUM, comm));
470     mapping->n = 0;
471     for (PetscInt i = st; i < st + nmaps; i++) mapping->n += sizes[i];
472     PetscCall(PetscFree(sizes));
473 
474     if (nold != mapping->n) {
475       if (mapping->dealloc_indices) PetscCall(PetscFree(mapping->indices));
476       mapping->indices = NULL;
477     }
478   }
479 
480   /* read indices */
481   if (mapping->n && !mapping->indices) {
482     PetscCall(PetscMalloc1(mapping->n, &mapping->indices));
483     mapping->dealloc_indices = PETSC_TRUE;
484   }
485   PetscCall(PetscViewerBinaryReadAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
486   PetscFunctionReturn(PETSC_SUCCESS);
487 }
488 
489 /*@
490   ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
491   ordering and a global parallel ordering.
492 
493   Not Collective
494 
495   Input Parameter:
496 . is - index set containing the global numbers for each local number
497 
498   Output Parameter:
499 . mapping - new mapping data structure
500 
501   Level: advanced
502 
503   Note:
504   the block size of the `IS` determines the block size of the mapping
505 
506 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()`
507 @*/
508 PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping)
509 {
510   PetscInt        n, bs;
511   const PetscInt *indices;
512   MPI_Comm        comm;
513   PetscBool       isblock;
514 
515   PetscFunctionBegin;
516   PetscValidHeaderSpecific(is, IS_CLASSID, 1);
517   PetscAssertPointer(mapping, 2);
518 
519   PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
520   PetscCall(ISGetLocalSize(is, &n));
521   PetscCall(PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock));
522   if (!isblock) {
523     PetscCall(ISGetIndices(is, &indices));
524     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping));
525     PetscCall(ISRestoreIndices(is, &indices));
526   } else {
527     PetscCall(ISGetBlockSize(is, &bs));
528     PetscCall(ISBlockGetIndices(is, &indices));
529     PetscCall(ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping));
530     PetscCall(ISBlockRestoreIndices(is, &indices));
531   }
532   PetscFunctionReturn(PETSC_SUCCESS);
533 }
534 
535 /*@C
536   ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n)
537   ordering and a global parallel ordering.
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, (char *)(((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`.
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;
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(ISGetIndices(is, &idxin));
827   PetscCall(PetscMalloc1(n, &idxout));
828   PetscCall(ISLocalToGlobalMappingApply(mapping, n, idxin, idxout));
829   PetscCall(ISRestoreIndices(is, &idxin));
830   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idxout, PETSC_OWN_POINTER, newis));
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   Note:
1001   The output `IS` will be sequential, as it encodes a purely local operation
1002 
1003 .seealso: [](sec_scatter), `ISGlobalToLocalMapping`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
1004           `ISLocalToGlobalMappingDestroy()`
1005 @*/
1006 PetscErrorCode ISGlobalToLocalMappingApplyIS(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, IS is, IS *newis)
1007 {
1008   PetscInt        n, nout, *idxout;
1009   const PetscInt *idxin;
1010 
1011   PetscFunctionBegin;
1012   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1013   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
1014   PetscAssertPointer(newis, 4);
1015 
1016   PetscCall(ISGetLocalSize(is, &n));
1017   PetscCall(ISGetIndices(is, &idxin));
1018   if (type == IS_GTOLM_MASK) {
1019     PetscCall(PetscMalloc1(n, &idxout));
1020   } else {
1021     PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, NULL));
1022     PetscCall(PetscMalloc1(nout, &idxout));
1023   }
1024   PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, idxout));
1025   PetscCall(ISRestoreIndices(is, &idxin));
1026   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nout, idxout, PETSC_OWN_POINTER, newis));
1027   PetscFunctionReturn(PETSC_SUCCESS);
1028 }
1029 
1030 /*@
1031   ISGlobalToLocalMappingApplyBlock - Provides the local block numbering for a list of integers
1032   specified with a block global numbering.
1033 
1034   Not Collective
1035 
1036   Input Parameters:
1037 + mapping - mapping between local and global numbering
1038 . type    - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them)
1039            `IS_GTOLM_DROP` - drops the indices with no local value from the output list
1040 . n       - number of global indices to map
1041 - idx     - global indices to map
1042 
1043   Output Parameters:
1044 + nout   - number of indices in output array (if type == `IS_GTOLM_MASK` then nout = n)
1045 - idxout - local index of each global index, one must pass in an array long enough
1046              to hold all the indices. You can call `ISGlobalToLocalMappingApplyBlock()` with
1047              idxout == NULL to determine the required length (returned in nout)
1048              and then allocate the required space and call `ISGlobalToLocalMappingApplyBlock()`
1049              a second time to set the values.
1050 
1051   Level: advanced
1052 
1053   Notes:
1054   Either `nout` or `idxout` may be `NULL`. `idx` and `idxout` may be identical.
1055 
1056   For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` of
1057   `ISLOCALTOGLOBALMAPPINGBASIC` will be used;
1058   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.
1059   Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.
1060 
1061   Developer Notes:
1062   The manual page states that `idx` and `idxout` may be identical but the calling
1063   sequence declares `idx` as const so it cannot be the same as `idxout`.
1064 
1065 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
1066           `ISLocalToGlobalMappingDestroy()`
1067 @*/
1068 PetscErrorCode ISGlobalToLocalMappingApplyBlock(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[])
1069 {
1070   PetscFunctionBegin;
1071   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1072   if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping));
1073   PetscUseTypeMethod(mapping, globaltolocalmappingapplyblock, type, n, idx, nout, idxout);
1074   PetscFunctionReturn(PETSC_SUCCESS);
1075 }
1076 
1077 /*@C
1078   ISLocalToGlobalMappingGetBlockInfo - Gets the neighbor information
1079 
1080   Collective the first time it is called
1081 
1082   Input Parameter:
1083 . mapping - the mapping from local to global indexing
1084 
1085   Output Parameters:
1086 + nproc    - number of processes that are connected to the calling process
1087 . procs    - neighboring processes
1088 . numprocs - number of block indices for each process
1089 - indices  - block indices (in local numbering) shared with neighbors (sorted by global numbering)
1090 
1091   Level: advanced
1092 
1093 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1094           `ISLocalToGlobalMappingRestoreBlockInfo()`
1095 @*/
1096 PetscErrorCode ISLocalToGlobalMappingGetBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1097 {
1098   PetscFunctionBegin;
1099   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1100   PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping));
1101   if (nproc) *nproc = mapping->info_nproc;
1102   if (procs) *procs = mapping->info_procs;
1103   if (numprocs) *numprocs = mapping->info_numprocs;
1104   if (indices) *indices = mapping->info_indices;
1105   PetscFunctionReturn(PETSC_SUCCESS);
1106 }
1107 
1108 /*@C
1109   ISLocalToGlobalMappingGetBlockNodeInfo - Gets the neighbor information for each local block index
1110 
1111   Collective the first time it is called
1112 
1113   Input Parameter:
1114 . mapping - the mapping from local to global indexing
1115 
1116   Output Parameter:
1117 + n       - number of local block nodes
1118 . n_procs - an array storing the number of processes for each local block node (including self)
1119 - procs   - the processes' rank for each local block node (sorted, self is first)
1120 
1121   Level: advanced
1122 
1123   Notes:
1124   The user needs to call `ISLocalToGlobalMappingRestoreBlockNodeInfo()` when the data is no longer needed.
1125   The information returned by this function complements that of `ISLocalToGlobalMappingGetBlockInfo()`.
1126   The latter only provides local information, and the neighboring information
1127   cannot be inferred in the general case, unless the mapping is locally one-to-one on each process.
1128 
1129 .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1130           `ISLocalToGlobalMappingGetBlockInfo()`, `ISLocalToGlobalMappingRestoreBlockNodeInfo()`, `ISLocalToGlobalMappingGetNodeInfo()`
1131 @*/
1132 PetscErrorCode ISLocalToGlobalMappingGetBlockNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
1133 {
1134   PetscFunctionBegin;
1135   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1136   PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping));
1137   if (n) *n = mapping->n;
1138   if (n_procs) *n_procs = mapping->info_nodec;
1139   if (procs) *procs = mapping->info_nodei;
1140   PetscFunctionReturn(PETSC_SUCCESS);
1141 }
1142 
1143 /*@C
1144   ISLocalToGlobalMappingRestoreBlockNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockNodeInfo()`
1145 
1146   Not Collective
1147 
1148   Input Parameters:
1149 + mapping - the mapping from local to global indexing
1150 . n       - number of local block nodes
1151 . n_procs - an array storing the number of processes for each local block nodes (including self)
1152 - procs   - the processes' rank for each local block node (sorted, self is first)
1153 
1154   Level: advanced
1155 
1156 .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1157           `ISLocalToGlobalMappingGetBlockNodeInfo()`
1158 @*/
1159 PetscErrorCode ISLocalToGlobalMappingRestoreBlockNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
1160 {
1161   PetscFunctionBegin;
1162   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1163   if (n) *n = 0;
1164   if (n_procs) *n_procs = NULL;
1165   if (procs) *procs = NULL;
1166   PetscFunctionReturn(PETSC_SUCCESS);
1167 }
1168 
1169 static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping mapping)
1170 {
1171   PetscSF            sf;
1172   MPI_Comm           comm;
1173   const PetscSFNode *sfnode;
1174   PetscSFNode       *newsfnode;
1175   PetscLayout        layout;
1176   PetscHMapI         neighs;
1177   PetscHashIter      iter;
1178   PetscBool          missing;
1179   const PetscInt    *gidxs, *rootdegree;
1180   PetscInt          *mask, *mrootdata, *leafdata, *newleafdata, *leafrd, *tmpg;
1181   PetscInt           nroots, nleaves, newnleaves, bs, i, j, m, mnroots, p;
1182   PetscMPIInt        rank, size;
1183 
1184   PetscFunctionBegin;
1185   if (mapping->info_numprocs) PetscFunctionReturn(PETSC_SUCCESS);
1186   PetscCall(PetscObjectGetComm((PetscObject)mapping, &comm));
1187   PetscCallMPI(MPI_Comm_size(comm, &size));
1188   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1189 
1190   /* Get mapping indices */
1191   PetscCall(ISLocalToGlobalMappingGetBlockSize(mapping, &bs));
1192   PetscCall(ISLocalToGlobalMappingGetBlockIndices(mapping, &gidxs));
1193   PetscCall(ISLocalToGlobalMappingGetSize(mapping, &nleaves));
1194   nleaves /= bs;
1195 
1196   /* Create layout for global indices */
1197   for (i = 0, m = 0; i < nleaves; i++) m = PetscMax(m, gidxs[i]);
1198   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &m, 1, MPIU_INT, MPI_MAX, comm));
1199   PetscCall(PetscLayoutCreate(comm, &layout));
1200   PetscCall(PetscLayoutSetSize(layout, m + 1));
1201   PetscCall(PetscLayoutSetUp(layout));
1202 
1203   /* Create SF to share global indices */
1204   PetscCall(PetscSFCreate(comm, &sf));
1205   PetscCall(PetscSFSetGraphLayout(sf, layout, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
1206   PetscCall(PetscSFSetUp(sf));
1207   PetscCall(PetscLayoutDestroy(&layout));
1208 
1209   /* communicate root degree to leaves */
1210   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, &sfnode));
1211   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
1212   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
1213   for (i = 0, mnroots = 0; i < nroots; i++) mnroots += rootdegree[i];
1214   PetscCall(PetscMalloc3(2 * PetscMax(mnroots, nroots), &mrootdata, 2 * nleaves, &leafdata, nleaves, &leafrd));
1215   for (i = 0, m = 0; i < nroots; i++) {
1216     mrootdata[2 * i + 0] = rootdegree[i];
1217     mrootdata[2 * i + 1] = m;
1218     m += rootdegree[i];
1219   }
1220   PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE));
1221   PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE));
1222 
1223   /* allocate enough space to store ranks */
1224   for (i = 0, newnleaves = 0; i < nleaves; i++) {
1225     newnleaves += leafdata[2 * i];
1226     leafrd[i] = leafdata[2 * i];
1227   }
1228 
1229   /* create new SF nodes to collect multi-root data at leaves */
1230   PetscCall(PetscMalloc1(newnleaves, &newsfnode));
1231   for (i = 0, m = 0; i < nleaves; i++) {
1232     for (j = 0; j < leafrd[i]; j++) {
1233       newsfnode[m].rank  = sfnode[i].rank;
1234       newsfnode[m].index = leafdata[2 * i + 1] + j;
1235       m++;
1236     }
1237   }
1238 
1239   /* gather ranks at multi roots */
1240   for (i = 0; i < mnroots; i++) mrootdata[i] = -1;
1241   for (i = 0; i < nleaves; i++) leafdata[i] = (PetscInt)rank;
1242 
1243   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, leafdata, mrootdata));
1244   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, leafdata, mrootdata));
1245 
1246   /* set new multi-leaves graph into the SF */
1247   PetscCall(PetscSFSetGraph(sf, mnroots, newnleaves, NULL, PETSC_OWN_POINTER, newsfnode, PETSC_OWN_POINTER));
1248   PetscCall(PetscSFSetUp(sf));
1249 
1250   /* broadcast multi-root data to multi-leaves */
1251   PetscCall(PetscMalloc1(newnleaves, &newleafdata));
1252   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE));
1253   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE));
1254 
1255   /* sort sharing ranks */
1256   for (i = 0, m = 0; i < nleaves; i++) {
1257     PetscCall(PetscSortInt(leafrd[i], newleafdata + m));
1258     m += leafrd[i];
1259   }
1260 
1261   /* Number of neighbors and their ranks */
1262   PetscCall(PetscHMapICreate(&neighs));
1263   for (i = 0; i < newnleaves; i++) PetscCall(PetscHMapIPut(neighs, newleafdata[i], &iter, &missing));
1264   PetscCall(PetscHMapIGetSize(neighs, &mapping->info_nproc));
1265   PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_procs));
1266   PetscCall(PetscHMapIGetKeys(neighs, (i = 0, &i), mapping->info_procs));
1267   for (i = 0; i < mapping->info_nproc; i++) { /* put info for self first */
1268     if (mapping->info_procs[i] == rank) {
1269       PetscInt newr = mapping->info_procs[0];
1270 
1271       mapping->info_procs[0] = rank;
1272       mapping->info_procs[i] = newr;
1273       break;
1274     }
1275   }
1276   if (mapping->info_nproc) PetscCall(PetscSortInt(mapping->info_nproc - 1, mapping->info_procs + 1));
1277   PetscCall(PetscHMapIDestroy(&neighs));
1278 
1279   /* collect info data */
1280   PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_numprocs));
1281   PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_indices));
1282   for (i = 0; i < mapping->info_nproc + 1; i++) mapping->info_indices[i] = NULL;
1283 
1284   PetscCall(PetscMalloc1(nleaves, &mask));
1285   PetscCall(PetscMalloc1(nleaves, &tmpg));
1286   for (p = 0; p < mapping->info_nproc; p++) {
1287     PetscInt *tmp, trank = mapping->info_procs[p];
1288 
1289     PetscCall(PetscMemzero(mask, nleaves * sizeof(*mask)));
1290     for (i = 0, m = 0; i < nleaves; i++) {
1291       for (j = 0; j < leafrd[i]; j++) {
1292         if (newleafdata[m] == trank) mask[i]++;
1293         if (!p && newleafdata[m] != rank) mask[i]++;
1294         m++;
1295       }
1296     }
1297     for (i = 0, m = 0; i < nleaves; i++)
1298       if (mask[i] > (!p ? 1 : 0)) m++;
1299 
1300     PetscCall(PetscMalloc1(m, &tmp));
1301     for (i = 0, m = 0; i < nleaves; i++)
1302       if (mask[i] > (!p ? 1 : 0)) {
1303         tmp[m]  = i;
1304         tmpg[m] = gidxs[i];
1305         m++;
1306       }
1307     PetscCall(PetscSortIntWithArray(m, tmpg, tmp));
1308     mapping->info_indices[p]  = tmp;
1309     mapping->info_numprocs[p] = m;
1310   }
1311 
1312   /* Node info */
1313   PetscCall(PetscMalloc2(nleaves, &mapping->info_nodec, nleaves + 1, &mapping->info_nodei));
1314   PetscCall(PetscArraycpy(mapping->info_nodec, leafrd, nleaves));
1315   PetscCall(PetscMalloc1(newnleaves, &mapping->info_nodei[0]));
1316   for (i = 0; i < nleaves - 1; i++) mapping->info_nodei[i + 1] = mapping->info_nodei[i] + mapping->info_nodec[i];
1317   PetscCall(PetscArraycpy(mapping->info_nodei[0], newleafdata, newnleaves));
1318 
1319   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(mapping, &gidxs));
1320   PetscCall(PetscFree(tmpg));
1321   PetscCall(PetscFree(mask));
1322   PetscCall(PetscSFDestroy(&sf));
1323   PetscCall(PetscFree3(mrootdata, leafdata, leafrd));
1324   PetscCall(PetscFree(newleafdata));
1325   PetscFunctionReturn(PETSC_SUCCESS);
1326 }
1327 
1328 /*@C
1329   ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockInfo()`
1330 
1331   Not Collective
1332 
1333   Input Parameters:
1334 + mapping  - the mapping from local to global indexing
1335 . nproc    - number of processes that are connected to the calling process
1336 . procs    - neighboring processes
1337 . numprocs - number of block indices for each process
1338 - indices  - block indices (in local numbering) shared with neighbors (sorted by global numbering)
1339 
1340   Level: advanced
1341 
1342 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1343           `ISLocalToGlobalMappingGetInfo()`
1344 @*/
1345 PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1346 {
1347   PetscFunctionBegin;
1348   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1349   if (nproc) *nproc = 0;
1350   if (procs) *procs = NULL;
1351   if (numprocs) *numprocs = NULL;
1352   if (indices) *indices = NULL;
1353   PetscFunctionReturn(PETSC_SUCCESS);
1354 }
1355 
1356 /*@C
1357   ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each process
1358 
1359   Collective the first time it is called
1360 
1361   Input Parameter:
1362 . mapping - the mapping from local to global indexing
1363 
1364   Output Parameters:
1365 + nproc    - number of processes that are connected to the calling process
1366 . procs    - neighboring processes
1367 . numprocs - number of indices for each process
1368 - indices  - indices (in local numbering) shared with neighbors (sorted by global numbering)
1369 
1370   Level: advanced
1371 
1372   Note:
1373   The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed.
1374 
1375   Fortran Notes:
1376   There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that
1377   `procs`[], `numprocs`[] and `indices`[][] are large enough arrays, either by allocating them
1378   dynamically or defining static ones large enough.
1379 
1380 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1381           `ISLocalToGlobalMappingRestoreInfo()`, `ISLocalToGlobalMappingGetNodeInfo()`
1382 @*/
1383 PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1384 {
1385   PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k, n, *bprocs;
1386 
1387   PetscFunctionBegin;
1388   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1389   bs = mapping->bs;
1390   PetscCall(ISLocalToGlobalMappingGetBlockInfo(mapping, &n, &bprocs, &bnumprocs, &bindices));
1391   if (bs > 1) { /* we need to expand the cached info */
1392     if (indices) PetscCall(PetscCalloc1(n, indices));
1393     if (numprocs) PetscCall(PetscCalloc1(n, numprocs));
1394     if (indices || numprocs) {
1395       for (i = 0; i < n; i++) {
1396         if (indices) {
1397           PetscCall(PetscMalloc1(bs * bnumprocs[i], &(*indices)[i]));
1398           for (j = 0; j < bnumprocs[i]; j++) {
1399             for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k;
1400           }
1401         }
1402         if (numprocs) (*numprocs)[i] = bnumprocs[i] * bs;
1403       }
1404     }
1405   } else {
1406     if (numprocs) *numprocs = bnumprocs;
1407     if (indices) *indices = bindices;
1408   }
1409   if (nproc) *nproc = n;
1410   if (procs) *procs = bprocs;
1411   PetscFunctionReturn(PETSC_SUCCESS);
1412 }
1413 
1414 /*@C
1415   ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetInfo()`
1416 
1417   Not Collective
1418 
1419   Input Parameters:
1420 + mapping  - the mapping from local to global indexing
1421 . nproc    - number of processes that are connected to the calling process
1422 . procs    - neighboring processes
1423 . numprocs - number of indices for each process
1424 - indices  - indices (in local numbering) shared with neighbors (sorted by global numbering)
1425 
1426   Level: advanced
1427 
1428 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1429           `ISLocalToGlobalMappingGetInfo()`
1430 @*/
1431 PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1432 {
1433   PetscFunctionBegin;
1434   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1435   if (mapping->bs > 1) {
1436     if (numprocs) PetscCall(PetscFree(*numprocs));
1437     if (indices) {
1438       if (*indices)
1439         for (PetscInt i = 0; i < *nproc; i++) PetscCall(PetscFree((*indices)[i]));
1440       PetscCall(PetscFree(*indices));
1441     }
1442   }
1443   PetscFunctionReturn(PETSC_SUCCESS);
1444 }
1445 
1446 /*@C
1447   ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information of local nodes
1448 
1449   Collective the first time it is called
1450 
1451   Input Parameter:
1452 . mapping - the mapping from local to global indexing
1453 
1454   Output Parameters:
1455 + n       - number of local nodes
1456 . n_procs - an array storing the number of processes for each local node (including self)
1457 - procs   - the processes' rank for each local node (sorted, self is first)
1458 
1459   Level: advanced
1460 
1461   Note:
1462   The user needs to call `ISLocalToGlobalMappingRestoreNodeInfo()` when the data is no longer needed.
1463 
1464 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1465           `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`, `ISLocalToGlobalMappingGetBlockNodeInfo()`
1466 @*/
1467 PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
1468 {
1469   PetscInt **bprocs = NULL, *bn_procs = NULL, bs, i, j, k, bn;
1470 
1471   PetscFunctionBegin;
1472   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1473   bs = mapping->bs;
1474   PetscCall(ISLocalToGlobalMappingGetBlockNodeInfo(mapping, &bn, &bn_procs, &bprocs));
1475   if (bs > 1) { /* we need to expand the cached info */
1476     PetscInt *tn_procs;
1477     PetscInt  c;
1478 
1479     PetscCall(PetscMalloc1(bn * bs, &tn_procs));
1480     for (i = 0, c = 0; i < bn; i++) {
1481       for (k = 0; k < bs; k++) tn_procs[i * bs + k] = bn_procs[i];
1482       c += bs * bn_procs[i];
1483     }
1484     if (n) *n = bn * bs;
1485     if (procs) {
1486       PetscInt **tprocs;
1487       PetscInt   tn = bn * bs;
1488 
1489       PetscCall(PetscMalloc1(tn, &tprocs));
1490       if (tn) PetscCall(PetscMalloc1(c, &tprocs[0]));
1491       for (i = 0; i < tn - 1; i++) tprocs[i + 1] = tprocs[i] + tn_procs[i];
1492       for (i = 0; i < bn; i++) {
1493         for (k = 0; k < bs; k++) {
1494           for (j = 0; j < bn_procs[i]; j++) tprocs[i * bs + k][j] = bprocs[i][j];
1495         }
1496       }
1497       *procs = tprocs;
1498     }
1499     if (n_procs) *n_procs = tn_procs;
1500     else PetscCall(PetscFree(tn_procs));
1501   } else {
1502     if (n) *n = bn;
1503     if (n_procs) *n_procs = bn_procs;
1504     if (procs) *procs = bprocs;
1505   }
1506   PetscFunctionReturn(PETSC_SUCCESS);
1507 }
1508 
1509 /*@C
1510   ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetNodeInfo()`
1511 
1512   Not Collective
1513 
1514   Input Parameters:
1515 + mapping - the mapping from local to global indexing
1516 . n       - number of local nodes
1517 . n_procs - an array storing the number of processes for each local node (including self)
1518 - procs   - the processes' rank for each local node (sorted, self is first)
1519 
1520   Level: advanced
1521 
1522 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1523           `ISLocalToGlobalMappingGetInfo()`
1524 @*/
1525 PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
1526 {
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1);
1529   if (mapping->bs > 1) {
1530     if (n_procs) PetscCall(PetscFree(*n_procs));
1531     if (procs) {
1532       if (*procs) PetscCall(PetscFree((*procs)[0]));
1533       PetscCall(PetscFree(*procs));
1534     }
1535   }
1536   PetscCall(ISLocalToGlobalMappingRestoreBlockNodeInfo(mapping, n, n_procs, procs));
1537   PetscFunctionReturn(PETSC_SUCCESS);
1538 }
1539 
1540 /*MC
1541     ISLocalToGlobalMappingGetIndicesF90 - Get global indices for every local point that is mapped
1542 
1543     Synopsis:
1544     ISLocalToGlobalMappingGetIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)
1545 
1546     Not Collective
1547 
1548     Input Parameter:
1549 .   A - the matrix
1550 
1551     Output Parameter:
1552 .   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1553 
1554     Level: advanced
1555 
1556     Note:
1557     Use  `ISLocalToGlobalMappingGetIndicesF90()` when you no longer need access to the data
1558 
1559 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`,
1560           `ISLocalToGlobalMappingRestoreIndicesF90()`
1561 M*/
1562 
1563 /*MC
1564     ISLocalToGlobalMappingRestoreIndicesF90 - restores the global indices for every local point that is mapped obtained with `ISLocalToGlobalMappingGetIndicesF90()`
1565 
1566     Synopsis:
1567     ISLocalToGlobalMappingRestoreIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)
1568 
1569     Not Collective
1570 
1571     Input Parameters:
1572 +   A - the matrix
1573 -   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1574 
1575     Level: advanced
1576 
1577 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`,
1578           `ISLocalToGlobalMappingGetIndicesF90()`
1579 M*/
1580 
1581 /*@C
1582   ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped
1583 
1584   Not Collective
1585 
1586   Input Parameter:
1587 . ltog - local to global mapping
1588 
1589   Output Parameter:
1590 . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`
1591 
1592   Level: advanced
1593 
1594   Note:
1595   `ISLocalToGlobalMappingGetSize()` returns the length the this array
1596 
1597 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`,
1598           `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1599 @*/
1600 PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1601 {
1602   PetscFunctionBegin;
1603   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1604   PetscAssertPointer(array, 2);
1605   if (ltog->bs == 1) {
1606     *array = ltog->indices;
1607   } else {
1608     PetscInt       *jj, k, i, j, n = ltog->n, bs = ltog->bs;
1609     const PetscInt *ii;
1610 
1611     PetscCall(PetscMalloc1(bs * n, &jj));
1612     *array = jj;
1613     k      = 0;
1614     ii     = ltog->indices;
1615     for (i = 0; i < n; i++)
1616       for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j;
1617   }
1618   PetscFunctionReturn(PETSC_SUCCESS);
1619 }
1620 
1621 /*@C
1622   ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with `ISLocalToGlobalMappingGetIndices()`
1623 
1624   Not Collective
1625 
1626   Input Parameters:
1627 + ltog  - local to global mapping
1628 - array - array of indices
1629 
1630   Level: advanced
1631 
1632 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1633 @*/
1634 PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1635 {
1636   PetscFunctionBegin;
1637   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1638   PetscAssertPointer(array, 2);
1639   PetscCheck(ltog->bs != 1 || *array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
1640   if (ltog->bs > 1) PetscCall(PetscFree(*(void **)array));
1641   PetscFunctionReturn(PETSC_SUCCESS);
1642 }
1643 
1644 /*@C
1645   ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block
1646 
1647   Not Collective
1648 
1649   Input Parameter:
1650 . ltog - local to global mapping
1651 
1652   Output Parameter:
1653 . array - array of indices
1654 
1655   Level: advanced
1656 
1657 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1658 @*/
1659 PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1660 {
1661   PetscFunctionBegin;
1662   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1663   PetscAssertPointer(array, 2);
1664   *array = ltog->indices;
1665   PetscFunctionReturn(PETSC_SUCCESS);
1666 }
1667 
1668 /*@C
1669   ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with `ISLocalToGlobalMappingGetBlockIndices()`
1670 
1671   Not Collective
1672 
1673   Input Parameters:
1674 + ltog  - local to global mapping
1675 - array - array of indices
1676 
1677   Level: advanced
1678 
1679 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1680 @*/
1681 PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1682 {
1683   PetscFunctionBegin;
1684   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1685   PetscAssertPointer(array, 2);
1686   PetscCheck(*array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
1687   *array = NULL;
1688   PetscFunctionReturn(PETSC_SUCCESS);
1689 }
1690 
1691 /*@C
1692   ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings
1693 
1694   Not Collective
1695 
1696   Input Parameters:
1697 + comm  - communicator for the new mapping, must contain the communicator of every mapping to concatenate
1698 . n     - number of mappings to concatenate
1699 - ltogs - local to global mappings
1700 
1701   Output Parameter:
1702 . ltogcat - new mapping
1703 
1704   Level: advanced
1705 
1706   Note:
1707   This currently always returns a mapping with block size of 1
1708 
1709   Developer Notes:
1710   If all the input mapping have the same block size we could easily handle that as a special case
1711 
1712 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`
1713 @*/
1714 PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat)
1715 {
1716   PetscInt i, cnt, m, *idx;
1717 
1718   PetscFunctionBegin;
1719   PetscCheck(n >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Must have a non-negative number of mappings, given %" PetscInt_FMT, n);
1720   if (n > 0) PetscAssertPointer(ltogs, 3);
1721   for (i = 0; i < n; i++) PetscValidHeaderSpecific(ltogs[i], IS_LTOGM_CLASSID, 3);
1722   PetscAssertPointer(ltogcat, 4);
1723   for (cnt = 0, i = 0; i < n; i++) {
1724     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
1725     cnt += m;
1726   }
1727   PetscCall(PetscMalloc1(cnt, &idx));
1728   for (cnt = 0, i = 0; i < n; i++) {
1729     const PetscInt *subidx;
1730     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
1731     PetscCall(ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx));
1732     PetscCall(PetscArraycpy(&idx[cnt], subidx, m));
1733     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx));
1734     cnt += m;
1735   }
1736   PetscCall(ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat));
1737   PetscFunctionReturn(PETSC_SUCCESS);
1738 }
1739 
1740 /*MC
1741       ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
1742                                     used this is good for only small and moderate size problems.
1743 
1744    Options Database Key:
1745 .   -islocaltoglobalmapping_type basic - select this method
1746 
1747    Level: beginner
1748 
1749    Developer Note:
1750    This stores all the mapping information on each MPI rank.
1751 
1752 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH`
1753 M*/
1754 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog)
1755 {
1756   PetscFunctionBegin;
1757   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Basic;
1758   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Basic;
1759   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic;
1760   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Basic;
1761   PetscFunctionReturn(PETSC_SUCCESS);
1762 }
1763 
1764 /*MC
1765       ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
1766                                     used this is good for large memory problems.
1767 
1768    Options Database Key:
1769 .   -islocaltoglobalmapping_type hash - select this method
1770 
1771    Level: beginner
1772 
1773    Note:
1774     This is selected automatically for large problems if the user does not set the type.
1775 
1776 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGBASIC`
1777 M*/
1778 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog)
1779 {
1780   PetscFunctionBegin;
1781   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Hash;
1782   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Hash;
1783   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash;
1784   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Hash;
1785   PetscFunctionReturn(PETSC_SUCCESS);
1786 }
1787 
1788 /*@C
1789   ISLocalToGlobalMappingRegister -  Registers a method for applying a global to local mapping with an `ISLocalToGlobalMapping`
1790 
1791   Not Collective
1792 
1793   Input Parameters:
1794 + sname    - name of a new method
1795 - function - routine to create method context
1796 
1797   Example Usage:
1798 .vb
1799    ISLocalToGlobalMappingRegister("my_mapper", MyCreate);
1800 .ve
1801 
1802   Then, your mapping can be chosen with the procedural interface via
1803 $     ISLocalToGlobalMappingSetType(ltog, "my_mapper")
1804   or at runtime via the option
1805 $     -islocaltoglobalmapping_type my_mapper
1806 
1807   Level: advanced
1808 
1809   Note:
1810   `ISLocalToGlobalMappingRegister()` may be called multiple times to add several user-defined mappings.
1811 
1812 .seealso: [](sec_scatter), `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`,
1813           `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`
1814 @*/
1815 PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping))
1816 {
1817   PetscFunctionBegin;
1818   PetscCall(ISInitializePackage());
1819   PetscCall(PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function));
1820   PetscFunctionReturn(PETSC_SUCCESS);
1821 }
1822 
1823 /*@C
1824   ISLocalToGlobalMappingSetType - Sets the implementation type `ISLocalToGlobalMapping` will use
1825 
1826   Logically Collective
1827 
1828   Input Parameters:
1829 + ltog - the `ISLocalToGlobalMapping` object
1830 - type - a known method
1831 
1832   Options Database Key:
1833 . -islocaltoglobalmapping_type  <method> - Sets the method; use -help for a list of available methods (for instance, basic or hash)
1834 
1835   Level: intermediate
1836 
1837   Notes:
1838   See `ISLocalToGlobalMappingType` for available methods
1839 
1840   Normally, it is best to use the `ISLocalToGlobalMappingSetFromOptions()` command and
1841   then set the `ISLocalToGlobalMappingType` from the options database rather than by using
1842   this routine.
1843 
1844   Developer Notes:
1845   `ISLocalToGlobalMappingRegister()` is used to add new types to `ISLocalToGlobalMappingList` from which they
1846   are accessed by `ISLocalToGlobalMappingSetType()`.
1847 
1848 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()`
1849 @*/
1850 PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type)
1851 {
1852   PetscBool match;
1853   PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL;
1854 
1855   PetscFunctionBegin;
1856   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1857   if (type) PetscAssertPointer(type, 2);
1858 
1859   PetscCall(PetscObjectTypeCompare((PetscObject)ltog, type, &match));
1860   if (match) PetscFunctionReturn(PETSC_SUCCESS);
1861 
1862   /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */
1863   if (type) {
1864     PetscCall(PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r));
1865     PetscCheck(r, PetscObjectComm((PetscObject)ltog), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested ISLocalToGlobalMapping type %s", type);
1866   }
1867   /* Destroy the previous private LTOG context */
1868   PetscTryTypeMethod(ltog, destroy);
1869   ltog->ops->destroy = NULL;
1870 
1871   PetscCall(PetscObjectChangeTypeName((PetscObject)ltog, type));
1872   if (r) PetscCall((*r)(ltog));
1873   PetscFunctionReturn(PETSC_SUCCESS);
1874 }
1875 
1876 /*@C
1877   ISLocalToGlobalMappingGetType - Get the type of the `ISLocalToGlobalMapping`
1878 
1879   Not Collective
1880 
1881   Input Parameter:
1882 . ltog - the `ISLocalToGlobalMapping` object
1883 
1884   Output Parameter:
1885 . type - the type
1886 
1887   Level: intermediate
1888 
1889 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`
1890 @*/
1891 PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type)
1892 {
1893   PetscFunctionBegin;
1894   PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1);
1895   PetscAssertPointer(type, 2);
1896   *type = ((PetscObject)ltog)->type_name;
1897   PetscFunctionReturn(PETSC_SUCCESS);
1898 }
1899 
1900 PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE;
1901 
1902 /*@C
1903   ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the `IS` package.
1904 
1905   Not Collective
1906 
1907   Level: advanced
1908 
1909 .seealso: [](sec_scatter), `ISRegister()`, `ISLocalToGlobalRegister()`
1910 @*/
1911 PetscErrorCode ISLocalToGlobalMappingRegisterAll(void)
1912 {
1913   PetscFunctionBegin;
1914   if (ISLocalToGlobalMappingRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
1915   ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE;
1916   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic));
1917   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash));
1918   PetscFunctionReturn(PETSC_SUCCESS);
1919 }
1920