Actual source code: isltog.c

      1: #include <petsc/private/isimpl.h>
      2: #include <petsc/private/hashmapi.h>
      3: #include <petscsf.h>
      4: #include <petscviewer.h>
      5: #include <petscbt.h>

      7: PetscClassId          IS_LTOGM_CLASSID;
      8: static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping);

     10: typedef struct {
     11:   PetscInt *globals;
     12: } ISLocalToGlobalMapping_Basic;

     14: typedef struct {
     15:   PetscHMapI globalht;
     16: } ISLocalToGlobalMapping_Hash;

     18: /*@C
     19:   ISGetPointRange - Returns a description of the points in an `IS` suitable for traversal

     21:   Not Collective

     23:   Input Parameter:
     24: . pointIS - The `IS` object

     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

     31:   Level: intermediate

     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`

     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;

     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: }

     64: /*@C
     65:   ISRestorePointRange - Destroys the traversal description created with `ISGetPointRange()`

     67:   Not Collective

     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()`

     75:   Level: intermediate

     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;

     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: }

     91: /*@
     92:   ISGetPointSubrange - Configures the input `IS` to be a subrange for the traversal information given

     94:   Not Collective

     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()`

    102:   Output Parameters:
    103: . subpointIS - The `IS` object now configured to be a subrange

    105:   Level: intermediate

    107:   Note:
    108:   The input `IS` will now respond properly to calls to `ISGetPointRange()` and return the subrange.

    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: }

    125: /* -----------------------------------------------------------------------------------------*/

    127: /*
    128:     Creates the global mapping information in the ISLocalToGlobalMapping structure

    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;

    136:   PetscFunctionBegin;
    137:   if (mapping->data) PetscFunctionReturn(PETSC_SUCCESS);
    138:   end   = 0;
    139:   start = PETSC_INT_MAX;

    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: }

    163: static PetscErrorCode ISGlobalToLocalMappingSetUp_Basic(ISLocalToGlobalMapping mapping)
    164: {
    165:   PetscInt                      i, *idx = mapping->indices, n = mapping->n, end, start, *globals;
    166:   ISLocalToGlobalMapping_Basic *map;

    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: }

    183: static PetscErrorCode ISGlobalToLocalMappingSetUp_Hash(ISLocalToGlobalMapping mapping)
    184: {
    185:   PetscInt                     i, *idx = mapping->indices, n = mapping->n;
    186:   ISLocalToGlobalMapping_Hash *map;

    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: }

    199: static PetscErrorCode ISLocalToGlobalMappingDestroy_Basic(ISLocalToGlobalMapping mapping)
    200: {
    201:   ISLocalToGlobalMapping_Basic *map = (ISLocalToGlobalMapping_Basic *)mapping->data;

    203:   PetscFunctionBegin;
    204:   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
    205:   PetscCall(PetscFree(map->globals));
    206:   PetscCall(PetscFree(mapping->data));
    207:   PetscFunctionReturn(PETSC_SUCCESS);
    208: }

    210: static PetscErrorCode ISLocalToGlobalMappingDestroy_Hash(ISLocalToGlobalMapping mapping)
    211: {
    212:   ISLocalToGlobalMapping_Hash *map = (ISLocalToGlobalMapping_Hash *)mapping->data;

    214:   PetscFunctionBegin;
    215:   if (!map) PetscFunctionReturn(PETSC_SUCCESS);
    216:   PetscCall(PetscHMapIDestroy(&map->globalht));
    217:   PetscCall(PetscFree(mapping->data));
    218:   PetscFunctionReturn(PETSC_SUCCESS);
    219: }

    221: static PetscErrorCode ISLocalToGlobalMappingResetBlockInfo_Private(ISLocalToGlobalMapping mapping)
    222: {
    223:   PetscFunctionBegin;
    224:   PetscCall(PetscFree(mapping->info_procs));
    225:   PetscCall(PetscFree(mapping->info_numprocs));
    226:   if (mapping->info_indices) {
    227:     for (PetscInt i = 0; i < mapping->info_nproc; i++) PetscCall(PetscFree(mapping->info_indices[i]));
    228:     PetscCall(PetscFree(mapping->info_indices));
    229:   }
    230:   if (mapping->info_nodei) PetscCall(PetscFree(mapping->info_nodei[0]));
    231:   PetscCall(PetscFree2(mapping->info_nodec, mapping->info_nodei));
    232:   PetscCall(PetscSFDestroy(&mapping->multileaves_sf));
    233:   PetscFunctionReturn(PETSC_SUCCESS);
    234: }

    236: #define GTOLTYPE _Basic
    237: #define GTOLNAME _Basic
    238: #define GTOLBS   mapping->bs
    239: #define GTOL(g, local) \
    240:   do { \
    241:     local = map->globals[g / bs - start]; \
    242:     if (local >= 0) local = bs * local + (g % bs); \
    243:   } while (0)

    245: #include <../src/vec/is/utils/isltog.h>

    247: #define GTOLTYPE _Basic
    248: #define GTOLNAME Block_Basic
    249: #define GTOLBS   1
    250: #define GTOL(g, local) \
    251:   do { \
    252:     local = map->globals[g - start]; \
    253:   } while (0)
    254: #include <../src/vec/is/utils/isltog.h>

    256: #define GTOLTYPE _Hash
    257: #define GTOLNAME _Hash
    258: #define GTOLBS   mapping->bs
    259: #define GTOL(g, local) \
    260:   do { \
    261:     (void)PetscHMapIGet(map->globalht, g / bs, &local); \
    262:     if (local >= 0) local = bs * local + (g % bs); \
    263:   } while (0)
    264: #include <../src/vec/is/utils/isltog.h>

    266: #define GTOLTYPE _Hash
    267: #define GTOLNAME Block_Hash
    268: #define GTOLBS   1
    269: #define GTOL(g, local) \
    270:   do { \
    271:     (void)PetscHMapIGet(map->globalht, g, &local); \
    272:   } while (0)
    273: #include <../src/vec/is/utils/isltog.h>

    275: /*@
    276:   ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object

    278:   Not Collective

    280:   Input Parameter:
    281: . ltog - local to global mapping

    283:   Output Parameter:
    284: . nltog - the duplicated local to global mapping

    286:   Level: advanced

    288: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
    289: @*/
    290: PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog)
    291: {
    292:   ISLocalToGlobalMappingType l2gtype;

    294:   PetscFunctionBegin;
    296:   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog));
    297:   PetscCall(ISLocalToGlobalMappingGetType(ltog, &l2gtype));
    298:   PetscCall(ISLocalToGlobalMappingSetType(*nltog, l2gtype));
    299:   PetscFunctionReturn(PETSC_SUCCESS);
    300: }

    302: /*@
    303:   ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping

    305:   Not Collective

    307:   Input Parameter:
    308: . mapping - local to global mapping

    310:   Output Parameter:
    311: . n - the number of entries in the local mapping, `ISLocalToGlobalMappingGetIndices()` returns an array of this length

    313:   Level: advanced

    315: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
    316: @*/
    317: PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n)
    318: {
    319:   PetscFunctionBegin;
    321:   PetscAssertPointer(n, 2);
    322:   *n = mapping->bs * mapping->n;
    323:   PetscFunctionReturn(PETSC_SUCCESS);
    324: }

    326: /*@
    327:   ISLocalToGlobalMappingViewFromOptions - View an `ISLocalToGlobalMapping` based on values in the options database

    329:   Collective

    331:   Input Parameters:
    332: + A    - the local to global mapping object
    333: . obj  - Optional object that provides the options prefix used for the options database query
    334: - name - command line option

    336:   Level: intermediate

    338:   Note:
    339:   See `PetscObjectViewFromOptions()` for the available `PetscViewer` and `PetscViewerFormat`

    341: .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()`
    342: @*/
    343: PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[])
    344: {
    345:   PetscFunctionBegin;
    347:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
    348:   PetscFunctionReturn(PETSC_SUCCESS);
    349: }

    351: /*@
    352:   ISLocalToGlobalMappingView - View a local to global mapping

    354:   Collective on viewer

    356:   Input Parameters:
    357: + mapping - local to global mapping
    358: - viewer  - viewer

    360:   Level: intermediate

    362: .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
    363: @*/
    364: PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer)
    365: {
    366:   PetscBool         iascii, isbinary;
    367:   PetscViewerFormat format;

    369:   PetscFunctionBegin;
    371:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer));

    374:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    375:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
    376:   PetscCall(PetscViewerGetFormat(viewer, &format));
    377:   if (iascii) {
    378:     if (format == PETSC_VIEWER_ASCII_MATLAB) {
    379:       const PetscInt *idxs;
    380:       IS              is;
    381:       const char     *name = ((PetscObject)mapping)->name;
    382:       char            iname[PETSC_MAX_PATH_LEN];

    384:       PetscCall(PetscSNPrintf(iname, sizeof(iname), "%sl2g", name ? name : ""));
    385:       PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &idxs));
    386:       PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mapping->n * mapping->bs, idxs, PETSC_USE_POINTER, &is));
    387:       PetscCall(PetscObjectSetName((PetscObject)is, iname));
    388:       PetscCall(ISView(is, viewer));
    389:       PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &idxs));
    390:       PetscCall(ISDestroy(&is));
    391:     } else {
    392:       PetscMPIInt rank;

    394:       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank));
    395:       PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer));
    396:       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
    397:       for (PetscInt i = 0; i < mapping->n; i++) {
    398:         PetscInt bs = mapping->bs, g = mapping->indices[i];
    399:         if (bs == 1) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, g));
    400:         else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":%" PetscInt_FMT " %" PetscInt_FMT ":%" PetscInt_FMT "\n", rank, i * bs, (i + 1) * bs, g * bs, (g + 1) * bs));
    401:       }
    402:       PetscCall(PetscViewerFlush(viewer));
    403:       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
    404:     }
    405:   } else if (isbinary) {
    406:     PetscBool skipHeader;

    408:     PetscCall(PetscViewerSetUp(viewer));
    409:     PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));
    410:     if (!skipHeader) {
    411:       PetscMPIInt size;
    412:       PetscInt    tr[3];

    414:       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
    415:       tr[0] = IS_LTOGM_FILE_CLASSID;
    416:       tr[1] = mapping->bs;
    417:       tr[2] = size;
    418:       PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT));
    419:       PetscCall(PetscViewerBinaryWriteAll(viewer, &mapping->n, 1, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
    420:     }
    421:     /* write block indices */
    422:     PetscCall(PetscViewerBinaryWriteAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
    423:   }
    424:   PetscFunctionReturn(PETSC_SUCCESS);
    425: }

    427: /*@
    428:   ISLocalToGlobalMappingLoad - Loads a local-to-global mapping that has been stored in binary format.

    430:   Collective on viewer

    432:   Input Parameters:
    433: + mapping - the newly loaded map, this needs to have been created with `ISLocalToGlobalMappingCreate()` or some related function before a call to `ISLocalToGlobalMappingLoad()`
    434: - viewer  - binary file viewer, obtained from `PetscViewerBinaryOpen()`

    436:   Level: intermediate

    438: .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView()`, `ISLocalToGlobalMappingCreate()`
    439: @*/
    440: PetscErrorCode ISLocalToGlobalMappingLoad(ISLocalToGlobalMapping mapping, PetscViewer viewer)
    441: {
    442:   PetscBool isbinary, skipHeader;

    444:   PetscFunctionBegin;
    447:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
    448:   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name);

    450:   /* reset previous data */
    451:   PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping));

    453:   PetscCall(PetscViewerSetUp(viewer));
    454:   PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader));

    456:   /* When skipping header, it assumes bs and n have been already set */
    457:   if (!skipHeader) {
    458:     MPI_Comm comm = PetscObjectComm((PetscObject)viewer);
    459:     PetscInt tr[3], nold = mapping->n, *sizes, nmaps = PETSC_DECIDE, st = 0;

    461:     PetscCall(PetscViewerBinaryRead(viewer, tr, 3, NULL, PETSC_INT));
    462:     PetscCheck(tr[0] == IS_LTOGM_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a local-to-global map next in file");

    464:     mapping->bs = tr[1];
    465:     PetscCall(PetscMalloc1(tr[2], &sizes));
    466:     PetscCall(PetscViewerBinaryRead(viewer, sizes, tr[2], NULL, PETSC_INT));

    468:     /* consume the input, read multiple maps per process if needed */
    469:     PetscCall(PetscSplitOwnership(comm, &nmaps, &tr[2]));
    470:     PetscCallMPI(MPI_Exscan(&nmaps, &st, 1, MPIU_INT, MPI_SUM, comm));
    471:     mapping->n = 0;
    472:     for (PetscInt i = st; i < st + nmaps; i++) mapping->n += sizes[i];
    473:     PetscCall(PetscFree(sizes));

    475:     if (nold != mapping->n) {
    476:       if (mapping->dealloc_indices) PetscCall(PetscFree(mapping->indices));
    477:       mapping->indices = NULL;
    478:     }
    479:   }

    481:   /* read indices */
    482:   if (mapping->n && !mapping->indices) {
    483:     PetscCall(PetscMalloc1(mapping->n, &mapping->indices));
    484:     mapping->dealloc_indices = PETSC_TRUE;
    485:   }
    486:   PetscCall(PetscViewerBinaryReadAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT));
    487:   PetscFunctionReturn(PETSC_SUCCESS);
    488: }

    490: /*@
    491:   ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
    492:   ordering and a global parallel ordering.

    494:   Not Collective

    496:   Input Parameter:
    497: . is - index set containing the global numbers for each local number

    499:   Output Parameter:
    500: . mapping - new mapping data structure

    502:   Level: advanced

    504:   Note:
    505:   the block size of the `IS` determines the block size of the mapping

    507: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()`
    508: @*/
    509: PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping)
    510: {
    511:   PetscInt        n, bs;
    512:   const PetscInt *indices;
    513:   MPI_Comm        comm;
    514:   PetscBool       isblock;

    516:   PetscFunctionBegin;
    518:   PetscAssertPointer(mapping, 2);

    520:   PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
    521:   PetscCall(ISGetLocalSize(is, &n));
    522:   PetscCall(PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock));
    523:   if (!isblock) {
    524:     PetscCall(ISGetIndices(is, &indices));
    525:     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping));
    526:     PetscCall(ISRestoreIndices(is, &indices));
    527:   } else {
    528:     PetscCall(ISGetBlockSize(is, &bs));
    529:     PetscCall(ISBlockGetIndices(is, &indices));
    530:     PetscCall(ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping));
    531:     PetscCall(ISBlockRestoreIndices(is, &indices));
    532:   }
    533:   PetscFunctionReturn(PETSC_SUCCESS);
    534: }

    536: /*@
    537:   ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n) ordering and a global parallel ordering induced by a star forest.

    539:   Collective

    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

    545:   Output Parameter:
    546: . mapping - new mapping data structure

    548:   Level: advanced

    550:   Note:
    551:   If a process calls this function with `start` = `PETSC_DECIDE` then all processes must, otherwise the program will hang.

    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;

    560:   PetscFunctionBegin;
    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: }

    582: /*@
    583:   ISLocalToGlobalMappingSetBlockSize - Sets the blocksize of the mapping

    585:   Not Collective

    587:   Input Parameters:
    588: + mapping - mapping data structure
    589: - bs      - the blocksize

    591:   Level: advanced

    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;

    601:   PetscFunctionBegin;
    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);

    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));

    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;

    639:   /* reset the cached information */
    640:   PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping));
    641:   PetscTryTypeMethod(mapping, destroy);
    642:   PetscFunctionReturn(PETSC_SUCCESS);
    643: }

    645: /*@
    646:   ISLocalToGlobalMappingGetBlockSize - Gets the blocksize of the mapping
    647:   ordering and a global parallel ordering.

    649:   Not Collective

    651:   Input Parameter:
    652: . mapping - mapping data structure

    654:   Output Parameter:
    655: . bs - the blocksize

    657:   Level: advanced

    659: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`
    660: @*/
    661: PetscErrorCode ISLocalToGlobalMappingGetBlockSize(ISLocalToGlobalMapping mapping, PetscInt *bs)
    662: {
    663:   PetscFunctionBegin;
    665:   *bs = mapping->bs;
    666:   PetscFunctionReturn(PETSC_SUCCESS);
    667: }

    669: /*@
    670:   ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n)
    671:   ordering and a global parallel ordering.

    673:   Not Collective, but communicator may have more than one process

    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

    682:   Output Parameter:
    683: . mapping - new mapping data structure

    685:   Level: advanced

    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

    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.

    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.

    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;

    705:   PetscFunctionBegin;
    706:   if (n) PetscAssertPointer(indices, 4);
    707:   PetscAssertPointer(mapping, 6);

    709:   *mapping = NULL;
    710:   PetscCall(ISInitializePackage());

    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: }

    729: PetscFunctionList ISLocalToGlobalMappingList = NULL;

    731: /*@
    732:   ISLocalToGlobalMappingSetFromOptions - Set mapping options from the options database.

    734:   Not Collective

    736:   Input Parameter:
    737: . mapping - mapping data structure

    739:   Options Database Key:
    740: . -islocaltoglobalmapping_type - <basic,hash> nonscalable and scalable versions

    742:   Level: advanced

    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;

    754:   PetscFunctionBegin;
    756:   PetscCall(ISLocalToGlobalMappingRegisterAll());
    757:   PetscObjectOptionsBegin((PetscObject)mapping);
    758:   PetscCall(PetscOptionsFList("-islocaltoglobalmapping_type", "ISLocalToGlobalMapping method", "ISLocalToGlobalMappingSetType", ISLocalToGlobalMappingList, ((PetscObject)mapping)->type_name ? ((PetscObject)mapping)->type_name : defaulttype, type, 256, &flg));
    759:   if (flg) PetscCall(ISLocalToGlobalMappingSetType(mapping, type));
    760:   PetscOptionsEnd();
    761:   PetscFunctionReturn(PETSC_SUCCESS);
    762: }

    764: /*@
    765:   ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n)
    766:   ordering and a global parallel ordering.

    768:   Not Collective

    770:   Input Parameter:
    771: . mapping - mapping data structure

    773:   Level: advanced

    775: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`
    776: @*/
    777: PetscErrorCode ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping *mapping)
    778: {
    779:   PetscFunctionBegin;
    780:   if (!*mapping) PetscFunctionReturn(PETSC_SUCCESS);
    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: }

    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.

    798:   Collective

    800:   Input Parameters:
    801: + mapping - mapping between local and global numbering
    802: - is      - index set in local numbering

    804:   Output Parameter:
    805: . newis - index set in global numbering

    807:   Level: advanced

    809:   Note:
    810:   The output `IS` will have the same communicator as the input `IS`.

    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;

    820:   PetscFunctionBegin;
    823:   PetscAssertPointer(newis, 3);

    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: }

    834: /*@
    835:   ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering
    836:   and converts them to the global numbering.

    838:   Not Collective

    840:   Input Parameters:
    841: + mapping - the local to global mapping context
    842: . N       - number of integers
    843: - in      - input indices in local numbering

    845:   Output Parameter:
    846: . out - indices in global numbering

    848:   Level: advanced

    850:   Note:
    851:   The `in` and `out` array parameters may be identical.

    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;

    861:   PetscFunctionBegin;
    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: }

    889: /*@
    890:   ISLocalToGlobalMappingApplyBlock - Takes a list of integers in a local block numbering and converts them to the global block numbering

    892:   Not Collective

    894:   Input Parameters:
    895: + mapping - the local to global mapping context
    896: . N       - number of integers
    897: - in      - input indices in local block numbering

    899:   Output Parameter:
    900: . out - indices in global block numbering

    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.

    906:   Level: advanced

    908:   Note:
    909:   The `in` and `out` array parameters may be identical.

    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;

    920:   PetscFunctionBegin;
    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: }

    935: /*@
    936:   ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers
    937:   specified with a global numbering.

    939:   Not Collective

    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

    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.

    956:   Level: advanced

    958:   Notes:
    959:   Either `nout` or `idxout` may be `NULL`. `idx` and `idxout` may be identical.

    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.

    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`.

    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;
    977:   if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping));
    978:   PetscUseTypeMethod(mapping, globaltolocalmappingapply, type, n, idx, nout, idxout);
    979:   PetscFunctionReturn(PETSC_SUCCESS);
    980: }

    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.

    987:   Not Collective

    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

    995:   Output Parameter:
    996: . newis - index set in local numbering

    998:   Level: advanced

    1000:   Note:
    1001:   The output `IS` will be sequential, as it encodes a purely local operation

    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;

    1011:   PetscFunctionBegin;
    1014:   PetscAssertPointer(newis, 4);

    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: }

    1030: /*@
    1031:   ISGlobalToLocalMappingApplyBlock - Provides the local block numbering for a list of integers
    1032:   specified with a block global numbering.

    1034:   Not Collective

    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

    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.

    1051:   Level: advanced

    1053:   Notes:
    1054:   Either `nout` or `idxout` may be `NULL`. `idx` and `idxout` may be identical.

    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.

    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`.

    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;
    1072:   if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping));
    1073:   PetscUseTypeMethod(mapping, globaltolocalmappingapplyblock, type, n, idx, nout, idxout);
    1074:   PetscFunctionReturn(PETSC_SUCCESS);
    1075: }

    1077: /*@C
    1078:   ISLocalToGlobalMappingGetBlockInfo - Gets the neighbor information

    1080:   Collective the first time it is called

    1082:   Input Parameter:
    1083: . mapping - the mapping from local to global indexing

    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)

    1091:   Level: advanced

    1093: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1094:           `ISLocalToGlobalMappingRestoreBlockInfo()`, `ISLocalToGlobalMappingGetBlockMultiLeavesSF()`
    1095: @*/
    1096: PetscErrorCode ISLocalToGlobalMappingGetBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
    1097: {
    1098:   PetscFunctionBegin;
    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: }

    1108: /*@C
    1109:   ISLocalToGlobalMappingGetBlockNodeInfo - Gets the neighbor information for each local block index

    1111:   Collective the first time it is called

    1113:   Input Parameter:
    1114: . mapping - the mapping from local to global indexing

    1116:   Output Parameters:
    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)

    1121:   Level: advanced

    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.

    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;
    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: }

    1143: /*@C
    1144:   ISLocalToGlobalMappingRestoreBlockNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockNodeInfo()`

    1146:   Not Collective

    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)

    1154:   Level: advanced

    1156: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1157:           `ISLocalToGlobalMappingGetBlockNodeInfo()`
    1158: @*/
    1159: PetscErrorCode ISLocalToGlobalMappingRestoreBlockNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
    1160: {
    1161:   PetscFunctionBegin;
    1163:   if (n) *n = 0;
    1164:   if (n_procs) *n_procs = NULL;
    1165:   if (procs) *procs = NULL;
    1166:   PetscFunctionReturn(PETSC_SUCCESS);
    1167: }

    1169: /*@C
    1170:   ISLocalToGlobalMappingGetBlockMultiLeavesSF - Get the star-forest to communicate multi-leaf block data

    1172:   Collective the first time it is called

    1174:   Input Parameter:
    1175: . mapping - the mapping from local to global indexing

    1177:   Output Parameter:
    1178: . mlsf - the `PetscSF`

    1180:   Level: advanced

    1182:   Notes:
    1183:   The returned star forest is suitable to exchange local information with other processes sharing the same global block index.
    1184:   For example, suppose a mapping with two processes has been created with
    1185: .vb
    1186:     rank 0 global block indices: [0, 1, 2]
    1187:     rank 1 global block indices: [2, 3, 4]
    1188: .ve
    1189:   and we want to share the local information
    1190: .vb
    1191:     rank 0 data: [-1, -2, -3]
    1192:     rank 1 data: [1, 2, 3]
    1193: .ve
    1194:   then, the broadcasting action of `mlsf` will allow to collect
    1195: .vb
    1196:     rank 0 mlleafdata: [-1, -2, -3, 3]
    1197:     rank 1 mlleafdata: [-3, 3, 1, 2]
    1198: .ve
    1199:   Use ``ISLocalToGlobalMappingGetBlockNodeInfo()`` to index into the multi-leaf data.

    1201: .seealso: [](sec_scatter), `ISLocalToGlobalMappingGetBlockNodeInfo()`, `PetscSF`
    1202: @*/
    1203: PetscErrorCode ISLocalToGlobalMappingGetBlockMultiLeavesSF(ISLocalToGlobalMapping mapping, PetscSF *mlsf)
    1204: {
    1205:   PetscFunctionBegin;
    1207:   PetscAssertPointer(mlsf, 2);
    1208:   PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping));
    1209:   *mlsf = mapping->multileaves_sf;
    1210:   PetscFunctionReturn(PETSC_SUCCESS);
    1211: }

    1213: static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping mapping)
    1214: {
    1215:   PetscSF            sf, sf2, imsf, msf;
    1216:   MPI_Comm           comm;
    1217:   const PetscSFNode *sfnode;
    1218:   PetscSFNode       *newsfnode;
    1219:   PetscLayout        layout;
    1220:   PetscHMapI         neighs;
    1221:   PetscHashIter      iter;
    1222:   PetscBool          missing;
    1223:   const PetscInt    *gidxs, *rootdegree;
    1224:   PetscInt          *mask, *mrootdata, *leafdata, *newleafdata, *leafrd, *tmpg;
    1225:   PetscInt           nroots, nleaves, newnleaves, bs, i, j, m, mnroots, p;
    1226:   PetscMPIInt        rank, size;

    1228:   PetscFunctionBegin;
    1229:   if (mapping->multileaves_sf) PetscFunctionReturn(PETSC_SUCCESS);
    1230:   PetscCall(PetscObjectGetComm((PetscObject)mapping, &comm));
    1231:   PetscCallMPI(MPI_Comm_size(comm, &size));
    1232:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

    1234:   /* Get mapping indices */
    1235:   PetscCall(ISLocalToGlobalMappingGetBlockSize(mapping, &bs));
    1236:   PetscCall(ISLocalToGlobalMappingGetBlockIndices(mapping, &gidxs));
    1237:   PetscCall(ISLocalToGlobalMappingGetSize(mapping, &nleaves));
    1238:   nleaves /= bs;

    1240:   /* Create layout for global indices */
    1241:   for (i = 0, m = 0; i < nleaves; i++) m = PetscMax(m, gidxs[i]);
    1242:   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &m, 1, MPIU_INT, MPI_MAX, comm));
    1243:   PetscCall(PetscLayoutCreate(comm, &layout));
    1244:   PetscCall(PetscLayoutSetSize(layout, m + 1));
    1245:   PetscCall(PetscLayoutSetUp(layout));

    1247:   /* Create SF to share global indices */
    1248:   PetscCall(PetscSFCreate(comm, &sf));
    1249:   PetscCall(PetscSFSetGraphLayout(sf, layout, nleaves, NULL, PETSC_OWN_POINTER, gidxs));
    1250:   PetscCall(PetscSFSetUp(sf));
    1251:   PetscCall(PetscLayoutDestroy(&layout));

    1253:   /* communicate root degree to leaves */
    1254:   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, &sfnode));
    1255:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
    1256:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
    1257:   for (i = 0, mnroots = 0; i < nroots; i++) mnroots += rootdegree[i];
    1258:   PetscCall(PetscMalloc3(2 * PetscMax(mnroots, nroots), &mrootdata, 2 * nleaves, &leafdata, nleaves, &leafrd));
    1259:   for (i = 0, m = 0; i < nroots; i++) {
    1260:     mrootdata[2 * i + 0] = rootdegree[i];
    1261:     mrootdata[2 * i + 1] = m;
    1262:     m += rootdegree[i];
    1263:   }
    1264:   PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE));
    1265:   PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE));

    1267:   /* allocate enough space to store ranks */
    1268:   for (i = 0, newnleaves = 0; i < nleaves; i++) {
    1269:     newnleaves += leafdata[2 * i];
    1270:     leafrd[i] = leafdata[2 * i];
    1271:   }

    1273:   /* create new SF nodes to collect multi-root data at leaves */
    1274:   PetscCall(PetscMalloc1(newnleaves, &newsfnode));
    1275:   for (i = 0, m = 0; i < nleaves; i++) {
    1276:     for (j = 0; j < leafrd[i]; j++) {
    1277:       newsfnode[m].rank  = sfnode[i].rank;
    1278:       newsfnode[m].index = leafdata[2 * i + 1] + j;
    1279:       m++;
    1280:     }
    1281:   }

    1283:   /* gather ranks at multi roots */
    1284:   for (i = 0; i < mnroots; i++) mrootdata[i] = -1;
    1285:   for (i = 0; i < nleaves; i++) leafdata[i] = (PetscInt)rank;

    1287:   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, leafdata, mrootdata));
    1288:   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, leafdata, mrootdata));

    1290:   /* from multi-roots to multi-leaves */
    1291:   PetscCall(PetscSFCreate(comm, &sf2));
    1292:   PetscCall(PetscSFSetGraph(sf2, mnroots, newnleaves, NULL, PETSC_OWN_POINTER, newsfnode, PETSC_OWN_POINTER));
    1293:   PetscCall(PetscSFSetUp(sf2));

    1295:   /* broadcast multi-root data to multi-leaves */
    1296:   PetscCall(PetscMalloc1(newnleaves, &newleafdata));
    1297:   PetscCall(PetscSFBcastBegin(sf2, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE));
    1298:   PetscCall(PetscSFBcastEnd(sf2, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE));

    1300:   /* sort sharing ranks */
    1301:   for (i = 0, m = 0; i < nleaves; i++) {
    1302:     PetscCall(PetscSortInt(leafrd[i], newleafdata + m));
    1303:     m += leafrd[i];
    1304:   }

    1306:   /* Number of neighbors and their ranks */
    1307:   PetscCall(PetscHMapICreate(&neighs));
    1308:   for (i = 0; i < newnleaves; i++) PetscCall(PetscHMapIPut(neighs, newleafdata[i], &iter, &missing));
    1309:   PetscCall(PetscHMapIGetSize(neighs, &mapping->info_nproc));
    1310:   PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_procs));
    1311:   PetscCall(PetscHMapIGetKeys(neighs, (i = 0, &i), mapping->info_procs));
    1312:   for (i = 0; i < mapping->info_nproc; i++) { /* put info for self first */
    1313:     if (mapping->info_procs[i] == rank) {
    1314:       PetscInt newr = mapping->info_procs[0];

    1316:       mapping->info_procs[0] = rank;
    1317:       mapping->info_procs[i] = newr;
    1318:       break;
    1319:     }
    1320:   }
    1321:   if (mapping->info_nproc) PetscCall(PetscSortInt(mapping->info_nproc - 1, mapping->info_procs + 1));
    1322:   PetscCall(PetscHMapIDestroy(&neighs));

    1324:   /* collect info data */
    1325:   PetscCall(PetscMalloc1(mapping->info_nproc, &mapping->info_numprocs));
    1326:   PetscCall(PetscMalloc1(mapping->info_nproc, &mapping->info_indices));
    1327:   for (i = 0; i < mapping->info_nproc; i++) mapping->info_indices[i] = NULL;

    1329:   PetscCall(PetscMalloc1(nleaves, &mask));
    1330:   PetscCall(PetscMalloc1(nleaves, &tmpg));
    1331:   for (p = 0; p < mapping->info_nproc; p++) {
    1332:     PetscInt *tmp, trank = mapping->info_procs[p];

    1334:     PetscCall(PetscMemzero(mask, nleaves * sizeof(*mask)));
    1335:     for (i = 0, m = 0; i < nleaves; i++) {
    1336:       for (j = 0; j < leafrd[i]; j++) {
    1337:         if (newleafdata[m] == trank) mask[i]++;
    1338:         if (!p && newleafdata[m] != rank) mask[i]++;
    1339:         m++;
    1340:       }
    1341:     }
    1342:     for (i = 0, m = 0; i < nleaves; i++)
    1343:       if (mask[i] > (!p ? 1 : 0)) m++;

    1345:     PetscCall(PetscMalloc1(m, &tmp));
    1346:     for (i = 0, m = 0; i < nleaves; i++)
    1347:       if (mask[i] > (!p ? 1 : 0)) {
    1348:         tmp[m]  = i;
    1349:         tmpg[m] = gidxs[i];
    1350:         m++;
    1351:       }
    1352:     PetscCall(PetscSortIntWithArray(m, tmpg, tmp));
    1353:     mapping->info_indices[p]  = tmp;
    1354:     mapping->info_numprocs[p] = m;
    1355:   }

    1357:   /* Node info */
    1358:   PetscCall(PetscMalloc2(nleaves, &mapping->info_nodec, nleaves + 1, &mapping->info_nodei));
    1359:   PetscCall(PetscArraycpy(mapping->info_nodec, leafrd, nleaves));
    1360:   PetscCall(PetscMalloc1(newnleaves, &mapping->info_nodei[0]));
    1361:   for (i = 0; i < nleaves - 1; i++) mapping->info_nodei[i + 1] = mapping->info_nodei[i] + mapping->info_nodec[i];
    1362:   PetscCall(PetscArraycpy(mapping->info_nodei[0], newleafdata, newnleaves));

    1364:   /* Create SF from leaves to multi-leaves */
    1365:   PetscCall(PetscSFGetMultiSF(sf, &msf));
    1366:   PetscCall(PetscSFCreateInverseSF(msf, &imsf));
    1367:   PetscCall(PetscSFCompose(imsf, sf2, &mapping->multileaves_sf));
    1368:   PetscCall(PetscSFDestroy(&imsf));
    1369:   PetscCall(PetscSFDestroy(&sf));
    1370:   PetscCall(PetscSFDestroy(&sf2));

    1372:   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(mapping, &gidxs));
    1373:   PetscCall(PetscFree(tmpg));
    1374:   PetscCall(PetscFree(mask));
    1375:   PetscCall(PetscFree3(mrootdata, leafdata, leafrd));
    1376:   PetscCall(PetscFree(newleafdata));
    1377:   PetscFunctionReturn(PETSC_SUCCESS);
    1378: }

    1380: /*@C
    1381:   ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockInfo()`

    1383:   Not Collective

    1385:   Input Parameters:
    1386: + mapping  - the mapping from local to global indexing
    1387: . nproc    - number of processes that are connected to the calling process
    1388: . procs    - neighboring processes
    1389: . numprocs - number of block indices for each process
    1390: - indices  - block indices (in local numbering) shared with neighbors (sorted by global numbering)

    1392:   Level: advanced

    1394: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1395:           `ISLocalToGlobalMappingGetInfo()`
    1396: @*/
    1397: PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
    1398: {
    1399:   PetscFunctionBegin;
    1401:   if (nproc) *nproc = 0;
    1402:   if (procs) *procs = NULL;
    1403:   if (numprocs) *numprocs = NULL;
    1404:   if (indices) *indices = NULL;
    1405:   PetscFunctionReturn(PETSC_SUCCESS);
    1406: }

    1408: /*@C
    1409:   ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each process

    1411:   Collective the first time it is called

    1413:   Input Parameter:
    1414: . mapping - the mapping from local to global indexing

    1416:   Output Parameters:
    1417: + nproc    - number of processes that are connected to the calling process
    1418: . procs    - neighboring processes
    1419: . numprocs - number of indices for each process
    1420: - indices  - indices (in local numbering) shared with neighbors (sorted by global numbering)

    1422:   Level: advanced

    1424:   Note:
    1425:   The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed.

    1427:   Fortran Notes:
    1428:   There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that
    1429:   `procs`[], `numprocs`[] and `indices`[][] are large enough arrays, either by allocating them
    1430:   dynamically or defining static ones large enough.

    1432: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1433:           `ISLocalToGlobalMappingRestoreInfo()`, `ISLocalToGlobalMappingGetNodeInfo()`
    1434: @*/
    1435: PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
    1436: {
    1437:   PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k, n, *bprocs;

    1439:   PetscFunctionBegin;
    1441:   bs = mapping->bs;
    1442:   PetscCall(ISLocalToGlobalMappingGetBlockInfo(mapping, &n, &bprocs, &bnumprocs, &bindices));
    1443:   if (bs > 1) { /* we need to expand the cached info */
    1444:     if (indices) PetscCall(PetscCalloc1(n, indices));
    1445:     if (numprocs) PetscCall(PetscCalloc1(n, numprocs));
    1446:     if (indices || numprocs) {
    1447:       for (i = 0; i < n; i++) {
    1448:         if (indices) {
    1449:           PetscCall(PetscMalloc1(bs * bnumprocs[i], &(*indices)[i]));
    1450:           for (j = 0; j < bnumprocs[i]; j++) {
    1451:             for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k;
    1452:           }
    1453:         }
    1454:         if (numprocs) (*numprocs)[i] = bnumprocs[i] * bs;
    1455:       }
    1456:     }
    1457:   } else {
    1458:     if (numprocs) *numprocs = bnumprocs;
    1459:     if (indices) *indices = bindices;
    1460:   }
    1461:   if (nproc) *nproc = n;
    1462:   if (procs) *procs = bprocs;
    1463:   PetscFunctionReturn(PETSC_SUCCESS);
    1464: }

    1466: /*@C
    1467:   ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetInfo()`

    1469:   Not Collective

    1471:   Input Parameters:
    1472: + mapping  - the mapping from local to global indexing
    1473: . nproc    - number of processes that are connected to the calling process
    1474: . procs    - neighboring processes
    1475: . numprocs - number of indices for each process
    1476: - indices  - indices (in local numbering) shared with neighbors (sorted by global numbering)

    1478:   Level: advanced

    1480: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1481:           `ISLocalToGlobalMappingGetInfo()`
    1482: @*/
    1483: PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
    1484: {
    1485:   PetscFunctionBegin;
    1487:   if (mapping->bs > 1) {
    1488:     if (numprocs) PetscCall(PetscFree(*numprocs));
    1489:     if (indices) {
    1490:       if (*indices)
    1491:         for (PetscInt i = 0; i < *nproc; i++) PetscCall(PetscFree((*indices)[i]));
    1492:       PetscCall(PetscFree(*indices));
    1493:     }
    1494:   }
    1495:   PetscFunctionReturn(PETSC_SUCCESS);
    1496: }

    1498: /*@C
    1499:   ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information of local nodes

    1501:   Collective the first time it is called

    1503:   Input Parameter:
    1504: . mapping - the mapping from local to global indexing

    1506:   Output Parameters:
    1507: + n       - number of local nodes
    1508: . n_procs - an array storing the number of processes for each local node (including self)
    1509: - procs   - the processes' rank for each local node (sorted, self is first)

    1511:   Level: advanced

    1513:   Note:
    1514:   The user needs to call `ISLocalToGlobalMappingRestoreNodeInfo()` when the data is no longer needed.

    1516: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1517:           `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`, `ISLocalToGlobalMappingGetBlockNodeInfo()`
    1518: @*/
    1519: PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
    1520: {
    1521:   PetscInt **bprocs = NULL, *bn_procs = NULL, bs, i, j, k, bn;

    1523:   PetscFunctionBegin;
    1525:   bs = mapping->bs;
    1526:   PetscCall(ISLocalToGlobalMappingGetBlockNodeInfo(mapping, &bn, &bn_procs, &bprocs));
    1527:   if (bs > 1) { /* we need to expand the cached info */
    1528:     PetscInt *tn_procs;
    1529:     PetscInt  c;

    1531:     PetscCall(PetscMalloc1(bn * bs, &tn_procs));
    1532:     for (i = 0, c = 0; i < bn; i++) {
    1533:       for (k = 0; k < bs; k++) tn_procs[i * bs + k] = bn_procs[i];
    1534:       c += bs * bn_procs[i];
    1535:     }
    1536:     if (n) *n = bn * bs;
    1537:     if (procs) {
    1538:       PetscInt **tprocs;
    1539:       PetscInt   tn = bn * bs;

    1541:       PetscCall(PetscMalloc1(tn, &tprocs));
    1542:       if (tn) PetscCall(PetscMalloc1(c, &tprocs[0]));
    1543:       for (i = 0; i < tn - 1; i++) tprocs[i + 1] = tprocs[i] + tn_procs[i];
    1544:       for (i = 0; i < bn; i++) {
    1545:         for (k = 0; k < bs; k++) {
    1546:           for (j = 0; j < bn_procs[i]; j++) tprocs[i * bs + k][j] = bprocs[i][j];
    1547:         }
    1548:       }
    1549:       *procs = tprocs;
    1550:     }
    1551:     if (n_procs) *n_procs = tn_procs;
    1552:     else PetscCall(PetscFree(tn_procs));
    1553:   } else {
    1554:     if (n) *n = bn;
    1555:     if (n_procs) *n_procs = bn_procs;
    1556:     if (procs) *procs = bprocs;
    1557:   }
    1558:   PetscFunctionReturn(PETSC_SUCCESS);
    1559: }

    1561: /*@C
    1562:   ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetNodeInfo()`

    1564:   Not Collective

    1566:   Input Parameters:
    1567: + mapping - the mapping from local to global indexing
    1568: . n       - number of local nodes
    1569: . n_procs - an array storing the number of processes for each local node (including self)
    1570: - procs   - the processes' rank for each local node (sorted, self is first)

    1572:   Level: advanced

    1574: .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
    1575:           `ISLocalToGlobalMappingGetInfo()`
    1576: @*/
    1577: PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[])
    1578: {
    1579:   PetscFunctionBegin;
    1581:   if (mapping->bs > 1) {
    1582:     if (n_procs) PetscCall(PetscFree(*n_procs));
    1583:     if (procs) {
    1584:       if (*procs) PetscCall(PetscFree((*procs)[0]));
    1585:       PetscCall(PetscFree(*procs));
    1586:     }
    1587:   }
    1588:   PetscCall(ISLocalToGlobalMappingRestoreBlockNodeInfo(mapping, n, n_procs, procs));
    1589:   PetscFunctionReturn(PETSC_SUCCESS);
    1590: }

    1592: /*MC
    1593:     ISLocalToGlobalMappingGetIndicesF90 - Get global indices for every local point that is mapped

    1595:     Synopsis:
    1596:     ISLocalToGlobalMappingGetIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)

    1598:     Not Collective

    1600:     Input Parameter:
    1601: .   A - the matrix

    1603:     Output Parameter:
    1604: .   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`

    1606:     Level: advanced

    1608:     Note:
    1609:     Use  `ISLocalToGlobalMappingGetIndicesF90()` when you no longer need access to the data

    1611: .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`,
    1612:           `ISLocalToGlobalMappingRestoreIndicesF90()`
    1613: M*/

    1615: /*MC
    1616:     ISLocalToGlobalMappingRestoreIndicesF90 - restores the global indices for every local point that is mapped obtained with `ISLocalToGlobalMappingGetIndicesF90()`

    1618:     Synopsis:
    1619:     ISLocalToGlobalMappingRestoreIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr)

    1621:     Not Collective

    1623:     Input Parameters:
    1624: +   A - the matrix
    1625: -   array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`

    1627:     Level: advanced

    1629: .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`,
    1630:           `ISLocalToGlobalMappingGetIndicesF90()`
    1631: M*/

    1633: /*@C
    1634:   ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped

    1636:   Not Collective

    1638:   Input Parameter:
    1639: . ltog - local to global mapping

    1641:   Output Parameter:
    1642: . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()`

    1644:   Level: advanced

    1646:   Note:
    1647:   `ISLocalToGlobalMappingGetSize()` returns the length the this array

    1649: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`,
    1650:           `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
    1651: @*/
    1652: PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[])
    1653: {
    1654:   PetscFunctionBegin;
    1656:   PetscAssertPointer(array, 2);
    1657:   if (ltog->bs == 1) {
    1658:     *array = ltog->indices;
    1659:   } else {
    1660:     PetscInt       *jj, k, i, j, n = ltog->n, bs = ltog->bs;
    1661:     const PetscInt *ii;

    1663:     PetscCall(PetscMalloc1(bs * n, &jj));
    1664:     *array = jj;
    1665:     k      = 0;
    1666:     ii     = ltog->indices;
    1667:     for (i = 0; i < n; i++)
    1668:       for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j;
    1669:   }
    1670:   PetscFunctionReturn(PETSC_SUCCESS);
    1671: }

    1673: /*@C
    1674:   ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with `ISLocalToGlobalMappingGetIndices()`

    1676:   Not Collective

    1678:   Input Parameters:
    1679: + ltog  - local to global mapping
    1680: - array - array of indices

    1682:   Level: advanced

    1684: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
    1685: @*/
    1686: PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[])
    1687: {
    1688:   PetscFunctionBegin;
    1690:   PetscAssertPointer(array, 2);
    1691:   PetscCheck(ltog->bs != 1 || *array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
    1692:   if (ltog->bs > 1) PetscCall(PetscFree(*(void **)array));
    1693:   PetscFunctionReturn(PETSC_SUCCESS);
    1694: }

    1696: /*@C
    1697:   ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block

    1699:   Not Collective

    1701:   Input Parameter:
    1702: . ltog - local to global mapping

    1704:   Output Parameter:
    1705: . array - array of indices

    1707:   Level: advanced

    1709: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
    1710: @*/
    1711: PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[])
    1712: {
    1713:   PetscFunctionBegin;
    1715:   PetscAssertPointer(array, 2);
    1716:   *array = ltog->indices;
    1717:   PetscFunctionReturn(PETSC_SUCCESS);
    1718: }

    1720: /*@C
    1721:   ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with `ISLocalToGlobalMappingGetBlockIndices()`

    1723:   Not Collective

    1725:   Input Parameters:
    1726: + ltog  - local to global mapping
    1727: - array - array of indices

    1729:   Level: advanced

    1731: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
    1732: @*/
    1733: PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[])
    1734: {
    1735:   PetscFunctionBegin;
    1737:   PetscAssertPointer(array, 2);
    1738:   PetscCheck(*array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer");
    1739:   *array = NULL;
    1740:   PetscFunctionReturn(PETSC_SUCCESS);
    1741: }

    1743: /*@
    1744:   ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings

    1746:   Not Collective

    1748:   Input Parameters:
    1749: + comm  - communicator for the new mapping, must contain the communicator of every mapping to concatenate
    1750: . n     - number of mappings to concatenate
    1751: - ltogs - local to global mappings

    1753:   Output Parameter:
    1754: . ltogcat - new mapping

    1756:   Level: advanced

    1758:   Note:
    1759:   This currently always returns a mapping with block size of 1

    1761:   Developer Notes:
    1762:   If all the input mapping have the same block size we could easily handle that as a special case

    1764: .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`
    1765: @*/
    1766: PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat)
    1767: {
    1768:   PetscInt i, cnt, m, *idx;

    1770:   PetscFunctionBegin;
    1771:   PetscCheck(n >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Must have a non-negative number of mappings, given %" PetscInt_FMT, n);
    1772:   if (n > 0) PetscAssertPointer(ltogs, 3);
    1774:   PetscAssertPointer(ltogcat, 4);
    1775:   for (cnt = 0, i = 0; i < n; i++) {
    1776:     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
    1777:     cnt += m;
    1778:   }
    1779:   PetscCall(PetscMalloc1(cnt, &idx));
    1780:   for (cnt = 0, i = 0; i < n; i++) {
    1781:     const PetscInt *subidx;
    1782:     PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m));
    1783:     PetscCall(ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx));
    1784:     PetscCall(PetscArraycpy(&idx[cnt], subidx, m));
    1785:     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx));
    1786:     cnt += m;
    1787:   }
    1788:   PetscCall(ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat));
    1789:   PetscFunctionReturn(PETSC_SUCCESS);
    1790: }

    1792: /*MC
    1793:       ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
    1794:                                     used this is good for only small and moderate size problems.

    1796:    Options Database Key:
    1797: .   -islocaltoglobalmapping_type basic - select this method

    1799:    Level: beginner

    1801:    Developer Note:
    1802:    This stores all the mapping information on each MPI rank.

    1804: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH`
    1805: M*/
    1806: PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog)
    1807: {
    1808:   PetscFunctionBegin;
    1809:   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Basic;
    1810:   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Basic;
    1811:   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic;
    1812:   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Basic;
    1813:   PetscFunctionReturn(PETSC_SUCCESS);
    1814: }

    1816: /*MC
    1817:       ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is
    1818:                                     used this is good for large memory problems.

    1820:    Options Database Key:
    1821: .   -islocaltoglobalmapping_type hash - select this method

    1823:    Level: beginner

    1825:    Note:
    1826:     This is selected automatically for large problems if the user does not set the type.

    1828: .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGBASIC`
    1829: M*/
    1830: PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog)
    1831: {
    1832:   PetscFunctionBegin;
    1833:   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Hash;
    1834:   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Hash;
    1835:   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash;
    1836:   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Hash;
    1837:   PetscFunctionReturn(PETSC_SUCCESS);
    1838: }

    1840: /*@C
    1841:   ISLocalToGlobalMappingRegister -  Registers a method for applying a global to local mapping with an `ISLocalToGlobalMapping`

    1843:   Not Collective, No Fortran Support

    1845:   Input Parameters:
    1846: + sname    - name of a new method
    1847: - function - routine to create method context

    1849:   Example Usage:
    1850: .vb
    1851:    ISLocalToGlobalMappingRegister("my_mapper", MyCreate);
    1852: .ve

    1854:   Then, your mapping can be chosen with the procedural interface via
    1855: $     ISLocalToGlobalMappingSetType(ltog, "my_mapper")
    1856:   or at runtime via the option
    1857: $     -islocaltoglobalmapping_type my_mapper

    1859:   Level: advanced

    1861:   Note:
    1862:   `ISLocalToGlobalMappingRegister()` may be called multiple times to add several user-defined mappings.

    1864: .seealso: [](sec_scatter), `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`,
    1865:           `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`
    1866: @*/
    1867: PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping))
    1868: {
    1869:   PetscFunctionBegin;
    1870:   PetscCall(ISInitializePackage());
    1871:   PetscCall(PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function));
    1872:   PetscFunctionReturn(PETSC_SUCCESS);
    1873: }

    1875: /*@
    1876:   ISLocalToGlobalMappingSetType - Sets the implementation type `ISLocalToGlobalMapping` will use

    1878:   Logically Collective

    1880:   Input Parameters:
    1881: + ltog - the `ISLocalToGlobalMapping` object
    1882: - type - a known method

    1884:   Options Database Key:
    1885: . -islocaltoglobalmapping_type  <method> - Sets the method; use -help for a list of available methods (for instance, basic or hash)

    1887:   Level: intermediate

    1889:   Notes:
    1890:   See `ISLocalToGlobalMappingType` for available methods

    1892:   Normally, it is best to use the `ISLocalToGlobalMappingSetFromOptions()` command and
    1893:   then set the `ISLocalToGlobalMappingType` from the options database rather than by using
    1894:   this routine.

    1896:   Developer Notes:
    1897:   `ISLocalToGlobalMappingRegister()` is used to add new types to `ISLocalToGlobalMappingList` from which they
    1898:   are accessed by `ISLocalToGlobalMappingSetType()`.

    1900: .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()`
    1901: @*/
    1902: PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type)
    1903: {
    1904:   PetscBool match;
    1905:   PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL;

    1907:   PetscFunctionBegin;
    1909:   if (type) PetscAssertPointer(type, 2);

    1911:   PetscCall(PetscObjectTypeCompare((PetscObject)ltog, type, &match));
    1912:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

    1914:   /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */
    1915:   if (type) {
    1916:     PetscCall(PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r));
    1917:     PetscCheck(r, PetscObjectComm((PetscObject)ltog), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested ISLocalToGlobalMapping type %s", type);
    1918:   }
    1919:   /* Destroy the previous private LTOG context */
    1920:   PetscTryTypeMethod(ltog, destroy);
    1921:   ltog->ops->destroy = NULL;

    1923:   PetscCall(PetscObjectChangeTypeName((PetscObject)ltog, type));
    1924:   if (r) PetscCall((*r)(ltog));
    1925:   PetscFunctionReturn(PETSC_SUCCESS);
    1926: }

    1928: /*@
    1929:   ISLocalToGlobalMappingGetType - Get the type of the `ISLocalToGlobalMapping`

    1931:   Not Collective

    1933:   Input Parameter:
    1934: . ltog - the `ISLocalToGlobalMapping` object

    1936:   Output Parameter:
    1937: . type - the type

    1939:   Level: intermediate

    1941: .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`
    1942: @*/
    1943: PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type)
    1944: {
    1945:   PetscFunctionBegin;
    1947:   PetscAssertPointer(type, 2);
    1948:   *type = ((PetscObject)ltog)->type_name;
    1949:   PetscFunctionReturn(PETSC_SUCCESS);
    1950: }

    1952: PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE;

    1954: /*@C
    1955:   ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the `IS` package.

    1957:   Not Collective

    1959:   Level: advanced

    1961: .seealso: [](sec_scatter), `ISRegister()`, `ISLocalToGlobalRegister()`
    1962: @*/
    1963: PetscErrorCode ISLocalToGlobalMappingRegisterAll(void)
    1964: {
    1965:   PetscFunctionBegin;
    1966:   if (ISLocalToGlobalMappingRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
    1967:   ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE;
    1968:   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic));
    1969:   PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash));
    1970:   PetscFunctionReturn(PETSC_SUCCESS);
    1971: }