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