Actual source code: pmap.c

      1: /*
      2:    This file contains routines for basic map object implementation.
      3: */

      5: #include <petsc/private/isimpl.h>

      7: /*@
      8:   PetscLayoutCreate - Allocates `PetscLayout` object

     10:   Collective

     12:   Input Parameter:
     13: . comm - the MPI communicator

     15:   Output Parameter:
     16: . map - the new `PetscLayout`

     18:   Level: advanced

     20:   Notes:
     21:   Typical calling sequence
     22: .vb
     23:        PetscLayoutCreate(MPI_Comm,PetscLayout *);
     24:        PetscLayoutSetBlockSize(PetscLayout,bs);
     25:        PetscLayoutSetSize(PetscLayout,N); // or PetscLayoutSetLocalSize(PetscLayout,n);
     26:        PetscLayoutSetUp(PetscLayout);
     27: .ve
     28:   Alternatively,
     29: .vb
     30:       PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
     31: .ve

     33:   Optionally use any of the following
     34: .vb
     35:   PetscLayoutGetSize(PetscLayout,PetscInt *);
     36:   PetscLayoutGetLocalSize(PetscLayout,PetscInt *);
     37:   PetscLayoutGetRange(PetscLayout,PetscInt *rstart,PetscInt *rend);
     38:   PetscLayoutGetRanges(PetscLayout,const PetscInt *range[]);
     39:   PetscLayoutDestroy(PetscLayout*);
     40: .ve

     42:   The `PetscLayout` object and methods are intended to be used in the PETSc `Vec` and `Mat` implementations; it is often not needed in
     43:   user codes unless you really gain something in their use.

     45: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`,
     46:           `PetscLayout`, `PetscLayoutDestroy()`,
     47:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`,
     48:           `PetscLayoutCreateFromSizes()`
     49: @*/
     50: PetscErrorCode PetscLayoutCreate(MPI_Comm comm, PetscLayout *map)
     51: {
     52:   PetscFunctionBegin;
     53:   PetscCall(PetscNew(map));
     54:   PetscCallMPI(MPI_Comm_size(comm, &(*map)->size));
     55:   (*map)->comm        = comm;
     56:   (*map)->bs          = 1;
     57:   (*map)->n           = -1;
     58:   (*map)->N           = -1;
     59:   (*map)->range       = NULL;
     60:   (*map)->range_alloc = PETSC_TRUE;
     61:   (*map)->rstart      = 0;
     62:   (*map)->rend        = 0;
     63:   (*map)->setupcalled = PETSC_FALSE;
     64:   (*map)->oldn        = -1;
     65:   (*map)->oldN        = -1;
     66:   (*map)->oldbs       = -1;
     67:   PetscFunctionReturn(PETSC_SUCCESS);
     68: }

     70: /*@
     71:   PetscLayoutCreateFromSizes - Allocates `PetscLayout` object and sets the layout sizes, and sets the layout up.

     73:   Collective

     75:   Input Parameters:
     76: + comm - the MPI communicator
     77: . n    - the local size (or `PETSC_DECIDE`)
     78: . N    - the global size (or `PETSC_DECIDE`)
     79: - bs   - the block size (or `PETSC_DECIDE`)

     81:   Output Parameter:
     82: . map - the new `PetscLayout`

     84:   Level: advanced

     86:   Note:
     87: .vb
     88:   PetscLayoutCreateFromSizes(comm, n, N, bs, &layout);
     89: .ve
     90:   is a shorthand for
     91: .vb
     92:   PetscLayoutCreate(comm, &layout);
     93:   PetscLayoutSetLocalSize(layout, n);
     94:   PetscLayoutSetSize(layout, N);
     95:   PetscLayoutSetBlockSize(layout, bs);
     96:   PetscLayoutSetUp(layout);
     97: .ve

     99: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
    100:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`, `PetscLayoutCreateFromRanges()`
    101: @*/
    102: PetscErrorCode PetscLayoutCreateFromSizes(MPI_Comm comm, PetscInt n, PetscInt N, PetscInt bs, PetscLayout *map)
    103: {
    104:   PetscFunctionBegin;
    105:   PetscCall(PetscLayoutCreate(comm, map));
    106:   PetscCall(PetscLayoutSetLocalSize(*map, n));
    107:   PetscCall(PetscLayoutSetSize(*map, N));
    108:   PetscCall(PetscLayoutSetBlockSize(*map, bs));
    109:   PetscCall(PetscLayoutSetUp(*map));
    110:   PetscFunctionReturn(PETSC_SUCCESS);
    111: }

    113: /*@
    114:   PetscLayoutDestroy - Frees a `PetscLayout` object and frees its range if that exists.

    116:   Collective

    118:   Input Parameter:
    119: . map - the `PetscLayout`

    121:   Level: developer

    123: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`,
    124:           `PetscLayout`, `PetscLayoutCreate()`,
    125:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`
    126: @*/
    127: PetscErrorCode PetscLayoutDestroy(PetscLayout *map)
    128: {
    129:   PetscFunctionBegin;
    130:   if (!*map) PetscFunctionReturn(PETSC_SUCCESS);
    131:   if (!(*map)->refcnt--) {
    132:     if ((*map)->range_alloc) PetscCall(PetscFree((*map)->range));
    133:     PetscCall(ISLocalToGlobalMappingDestroy(&(*map)->mapping));
    134:     PetscCall(PetscFree(*map));
    135:   }
    136:   *map = NULL;
    137:   PetscFunctionReturn(PETSC_SUCCESS);
    138: }

    140: /*@
    141:   PetscLayoutCreateFromRanges - Creates a new `PetscLayout` with the given ownership ranges and sets it up.

    143:   Collective

    145:   Input Parameters:
    146: + comm  - the MPI communicator
    147: . range - the array of ownership ranges for each rank with length commsize+1
    148: . mode  - the copy mode for range
    149: - bs    - the block size (or `PETSC_DECIDE`)

    151:   Output Parameter:
    152: . newmap - the new `PetscLayout`

    154:   Level: developer

    156: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`,
    157:           `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
    158:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`, `PetscLayoutCreateFromSizes()`
    159: @*/
    160: PetscErrorCode PetscLayoutCreateFromRanges(MPI_Comm comm, const PetscInt range[], PetscCopyMode mode, PetscInt bs, PetscLayout *newmap)
    161: {
    162:   PetscLayout map;
    163:   PetscMPIInt rank;

    165:   PetscFunctionBegin;
    166:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    167:   PetscCall(PetscLayoutCreate(comm, &map));
    168:   PetscCall(PetscLayoutSetBlockSize(map, bs));
    169:   switch (mode) {
    170:   case PETSC_COPY_VALUES:
    171:     PetscCall(PetscMalloc1(map->size + 1, &map->range));
    172:     PetscCall(PetscArraycpy(map->range, range, map->size + 1));
    173:     break;
    174:   case PETSC_USE_POINTER:
    175:     map->range_alloc = PETSC_FALSE; /* fall through */
    176:   case PETSC_OWN_POINTER:
    177:     map->range = (PetscInt *)range;
    178:     break;
    179:   default:
    180:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Received invalid PetscCopyMode somehow");
    181:   }
    182:   map->rstart = map->range[rank];
    183:   map->rend   = map->range[rank + 1];
    184:   map->n      = map->rend - map->rstart;
    185:   map->N      = map->range[map->size] - map->range[0];
    186:   if (PetscDefined(USE_DEBUG)) { /* just check that n, N and bs are consistent */
    187:     PetscInt tmp;
    188:     PetscCallMPI(MPIU_Allreduce(&map->n, &tmp, 1, MPIU_INT, MPI_SUM, map->comm));
    189:     PetscCheck(tmp == map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local lengths %" PetscInt_FMT " does not equal global length %" PetscInt_FMT ", my local length %" PetscInt_FMT ". The provided PetscLayout is wrong.", tmp, map->N, map->n);
    190:     PetscCheck(map->n % map->bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->n, map->bs);
    191:     PetscCheck(map->N % map->bs == 0, map->comm, PETSC_ERR_PLIB, "Global size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->N, map->bs);
    192:   }
    193:   /* lock the layout */
    194:   map->setupcalled = PETSC_TRUE;
    195:   map->oldn        = map->n;
    196:   map->oldN        = map->N;
    197:   map->oldbs       = map->bs;
    198:   *newmap          = map;
    199:   PetscFunctionReturn(PETSC_SUCCESS);
    200: }

    202: /*@
    203:   PetscLayoutSetUp - given a map where you have set either the global or local
    204:   size sets up the map so that it may be used.

    206:   Collective

    208:   Input Parameter:
    209: . map - pointer to the map

    211:   Level: developer

    213:   Notes:
    214:   Typical calling sequence
    215: .vb
    216:   PetscLayoutCreate(MPI_Comm,PetscLayout *);
    217:   PetscLayoutSetBlockSize(PetscLayout,1);
    218:   PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both
    219:   PetscLayoutSetUp(PetscLayout);
    220:   PetscLayoutGetSize(PetscLayout,PetscInt *);
    221: .ve

    223:   If range exists, and local size is not set, everything gets computed from the range.

    225:   If the local size, global size are already set and range exists then this does nothing.

    227: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`,
    228:           `PetscLayout`, `PetscLayoutDestroy()`,
    229:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutCreate()`, `PetscSplitOwnership()`
    230: @*/
    231: PetscErrorCode PetscLayoutSetUp(PetscLayout map)
    232: {
    233:   PetscMPIInt rank;
    234:   PetscInt    p;

    236:   PetscFunctionBegin;
    237:   PetscCheck(!map->setupcalled || !(map->n != map->oldn || map->N != map->oldN), map->comm, PETSC_ERR_ARG_WRONGSTATE, "Layout is already setup with (local=%" PetscInt_FMT ",global=%" PetscInt_FMT "), cannot call setup again with (local=%" PetscInt_FMT ",global=%" PetscInt_FMT ")",
    238:              map->oldn, map->oldN, map->n, map->N);
    239:   if (map->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);

    241:   PetscCheck(map->n < 0 || map->n % map->bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->n, map->bs);
    242:   PetscCheck(map->N < 0 || map->N % map->bs == 0, map->comm, PETSC_ERR_PLIB, "Global size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->N, map->bs);

    244:   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
    245:   if (map->n > 0) map->n = map->n / map->bs;
    246:   if (map->N > 0) map->N = map->N / map->bs;
    247:   PetscCall(PetscSplitOwnership(map->comm, &map->n, &map->N));
    248:   map->n = map->n * map->bs;
    249:   map->N = map->N * map->bs;
    250:   if (!map->range) PetscCall(PetscMalloc1(map->size + 1, &map->range));
    251:   PetscCallMPI(MPI_Allgather(&map->n, 1, MPIU_INT, map->range + 1, 1, MPIU_INT, map->comm));

    253:   map->range[0] = 0;
    254:   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p - 1];

    256:   map->rstart = map->range[rank];
    257:   map->rend   = map->range[rank + 1];

    259:   /* lock the layout */
    260:   map->setupcalled = PETSC_TRUE;
    261:   map->oldn        = map->n;
    262:   map->oldN        = map->N;
    263:   map->oldbs       = map->bs;
    264:   PetscFunctionReturn(PETSC_SUCCESS);
    265: }

    267: /*@
    268:   PetscLayoutDuplicate - creates a new `PetscLayout` with the same information as a given one. If the `PetscLayout` already exists it is destroyed first.

    270:   Collective

    272:   Input Parameter:
    273: . in - input `PetscLayout` to be duplicated

    275:   Output Parameter:
    276: . out - the copy

    278:   Level: developer

    280:   Note:
    281:   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`

    283: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutReference()`
    284: @*/
    285: PetscErrorCode PetscLayoutDuplicate(PetscLayout in, PetscLayout *out)
    286: {
    287:   MPI_Comm comm = in->comm;

    289:   PetscFunctionBegin;
    290:   PetscCall(PetscLayoutDestroy(out));
    291:   PetscCall(PetscLayoutCreate(comm, out));
    292:   PetscCall(PetscMemcpy(*out, in, sizeof(struct _n_PetscLayout)));
    293:   if (in->range) {
    294:     PetscCall(PetscMalloc1((*out)->size + 1, &(*out)->range));
    295:     PetscCall(PetscArraycpy((*out)->range, in->range, (*out)->size + 1));
    296:   }
    297:   (*out)->refcnt = 0;
    298:   PetscFunctionReturn(PETSC_SUCCESS);
    299: }

    301: /*@
    302:   PetscLayoutReference - Causes a PETSc `Vec` or `Mat` to share a `PetscLayout` with one that already exists.

    304:   Collective

    306:   Input Parameter:
    307: . in - input `PetscLayout` to be copied

    309:   Output Parameter:
    310: . out - the reference location

    312:   Level: developer

    314:   Notes:
    315:   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`

    317:   If the out location already contains a `PetscLayout` it is destroyed

    319: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
    320: @*/
    321: PetscErrorCode PetscLayoutReference(PetscLayout in, PetscLayout *out)
    322: {
    323:   PetscFunctionBegin;
    324:   in->refcnt++;
    325:   PetscCall(PetscLayoutDestroy(out));
    326:   *out = in;
    327:   PetscFunctionReturn(PETSC_SUCCESS);
    328: }

    330: /*@
    331:   PetscLayoutSetISLocalToGlobalMapping - sets a `ISLocalGlobalMapping` into a `PetscLayout`

    333:   Collective

    335:   Input Parameters:
    336: + in   - input `PetscLayout`
    337: - ltog - the local to global mapping

    339:   Level: developer

    341:   Notes:
    342:   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`

    344:   If the `PetscLayout` already contains a `ISLocalGlobalMapping` it is destroyed

    346: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
    347: @*/
    348: PetscErrorCode PetscLayoutSetISLocalToGlobalMapping(PetscLayout in, ISLocalToGlobalMapping ltog)
    349: {
    350:   PetscFunctionBegin;
    351:   if (ltog) {
    352:     PetscInt bs;

    354:     PetscCall(ISLocalToGlobalMappingGetBlockSize(ltog, &bs));
    355:     PetscCheck(in->bs == 1 || bs == 1 || in->bs == bs, in->comm, PETSC_ERR_PLIB, "Blocksize of layout %" PetscInt_FMT " must match that of mapping %" PetscInt_FMT " (or the latter must be 1)", in->bs, bs);
    356:   }
    357:   PetscCall(PetscObjectReference((PetscObject)ltog));
    358:   PetscCall(ISLocalToGlobalMappingDestroy(&in->mapping));
    359:   in->mapping = ltog;
    360:   PetscFunctionReturn(PETSC_SUCCESS);
    361: }

    363: /*@
    364:   PetscLayoutSetLocalSize - Sets the local size for a `PetscLayout` object.

    366:   Collective

    368:   Input Parameters:
    369: + map - pointer to the map
    370: - n   - the local size, pass `PETSC_DECIDE` (the default) to have this value determined by the global size set with `PetscLayoutSetSize()`

    372:   Level: developer

    374: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetUp()`,
    375:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
    376: @*/
    377: PetscErrorCode PetscLayoutSetLocalSize(PetscLayout map, PetscInt n)
    378: {
    379:   PetscFunctionBegin;
    380:   PetscCheck(n % map->bs == 0, map->comm, PETSC_ERR_ARG_INCOMP, "Local size %" PetscInt_FMT " not compatible with block size %" PetscInt_FMT, n, map->bs);
    381:   map->n = n;
    382:   PetscFunctionReturn(PETSC_SUCCESS);
    383: }

    385: /*@
    386:   PetscLayoutGetLocalSize - Gets the local size for a `PetscLayout` object.

    388:   Not Collective

    390:   Input Parameter:
    391: . map - pointer to the map

    393:   Output Parameter:
    394: . n - the local size

    396:   Level: developer

    398:   Note:
    399:   Call this after the call to `PetscLayoutSetUp()`

    401: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`,
    402:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
    403: @*/
    404: PetscErrorCode PetscLayoutGetLocalSize(PetscLayout map, PetscInt *n)
    405: {
    406:   PetscFunctionBegin;
    407:   *n = map->n;
    408:   PetscFunctionReturn(PETSC_SUCCESS);
    409: }

    411: /*@
    412:   PetscLayoutSetSize - Sets the global size for a `PetscLayout` object.

    414:   Logically Collective

    416:   Input Parameters:
    417: + map - pointer to the map
    418: - n   - the global size, use `PETSC_DETERMINE` (the default) to have this value computed as the sum of the local sizes set with `PetscLayoutSetLocalSize()`

    420:   Level: developer

    422: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`,
    423:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
    424: @*/
    425: PetscErrorCode PetscLayoutSetSize(PetscLayout map, PetscInt n)
    426: {
    427:   PetscFunctionBegin;
    428:   map->N = n;
    429:   PetscFunctionReturn(PETSC_SUCCESS);
    430: }

    432: /*@
    433:   PetscLayoutGetSize - Gets the global size for a `PetscLayout` object.

    435:   Not Collective

    437:   Input Parameter:
    438: . map - pointer to the map

    440:   Output Parameter:
    441: . n - the global size

    443:   Level: developer

    445:   Note:
    446:   Call this after the call to `PetscLayoutSetUp()`

    448: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`,
    449:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
    450: @*/
    451: PetscErrorCode PetscLayoutGetSize(PetscLayout map, PetscInt *n)
    452: {
    453:   PetscFunctionBegin;
    454:   *n = map->N;
    455:   PetscFunctionReturn(PETSC_SUCCESS);
    456: }

    458: /*@
    459:   PetscLayoutSetBlockSize - Sets the block size for a `PetscLayout` object.

    461:   Logically Collective

    463:   Input Parameters:
    464: + map - pointer to the map
    465: - bs  - the size

    467:   Level: developer

    469: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
    470:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
    471: @*/
    472: PetscErrorCode PetscLayoutSetBlockSize(PetscLayout map, PetscInt bs)
    473: {
    474:   PetscFunctionBegin;
    475:   PetscCheck(bs > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Block size %" PetscInt_FMT " must be positive", bs);
    476:   PetscCheck(map->n <= 0 || (map->n % bs) == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local size %" PetscInt_FMT " not compatible with block size %" PetscInt_FMT, map->n, bs);
    477:   if (map->mapping) {
    478:     PetscInt obs;

    480:     PetscCall(ISLocalToGlobalMappingGetBlockSize(map->mapping, &obs));
    481:     if (obs > 1) PetscCall(ISLocalToGlobalMappingSetBlockSize(map->mapping, bs));
    482:   }
    483:   map->bs = bs;
    484:   PetscFunctionReturn(PETSC_SUCCESS);
    485: }

    487: /*@
    488:   PetscLayoutGetBlockSize - Gets the block size for a `PetscLayout` object.

    490:   Not Collective

    492:   Input Parameter:
    493: . map - pointer to the map

    495:   Output Parameter:
    496: . bs - the size

    498:   Level: developer

    500:   Notes:
    501:   Call this after the call to `PetscLayoutSetUp()`

    503: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`,
    504:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetSize()`
    505: @*/
    506: PetscErrorCode PetscLayoutGetBlockSize(PetscLayout map, PetscInt *bs)
    507: {
    508:   PetscFunctionBegin;
    509:   *bs = map->bs;
    510:   PetscFunctionReturn(PETSC_SUCCESS);
    511: }

    513: /*@
    514:   PetscLayoutGetRange - gets the range of values owned by this process

    516:   Not Collective

    518:   Input Parameter:
    519: . map - pointer to the map

    521:   Output Parameters:
    522: + rstart - first index owned by this process
    523: - rend   - one more than the last index owned by this process

    525:   Level: developer

    527:   Note:
    528:   Call this after the call to `PetscLayoutSetUp()`

    530: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
    531:           `PetscLayoutGetSize()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutSetUp()`
    532: @*/
    533: PetscErrorCode PetscLayoutGetRange(PetscLayout map, PetscInt *rstart, PetscInt *rend)
    534: {
    535:   PetscFunctionBegin;
    536:   if (rstart) *rstart = map->rstart;
    537:   if (rend) *rend = map->rend;
    538:   PetscFunctionReturn(PETSC_SUCCESS);
    539: }

    541: /*@C
    542:   PetscLayoutGetRanges - gets the ranges of values owned by all processes

    544:   Not Collective

    546:   Input Parameter:
    547: . map - pointer to the map

    549:   Output Parameter:
    550: . range - start of each processors range of indices (the final entry is one more than the
    551:           last index on the last process). The length of the array is one more than the number of processes in the MPI
    552:           communicator owned by `map`

    554:   Level: developer

    556:   Note:
    557:   Call this after the call to `PetscLayoutSetUp()`

    559:   Fortran Notes:
    560: .vb
    561:   PetscInt, pointer :: range(:)
    562: .ve

    564:   Call `PetscLayoutRestoreRanges()` when no longer needed.

    566: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
    567:           `PetscLayoutGetSize()`, `PetscLayoutGetRange()`, `PetscLayoutSetBlockSize()`, `PetscLayoutSetUp()`
    568: @*/
    569: PetscErrorCode PetscLayoutGetRanges(PetscLayout map, const PetscInt *range[])
    570: {
    571:   PetscFunctionBegin;
    572:   *range = map->range;
    573:   PetscFunctionReturn(PETSC_SUCCESS);
    574: }

    576: /*@
    577:   PetscLayoutCompare - Compares two layouts

    579:   Not Collective

    581:   Input Parameters:
    582: + mapa - pointer to the first map
    583: - mapb - pointer to the second map

    585:   Output Parameter:
    586: . congruent - `PETSC_TRUE` if the two layouts are congruent, `PETSC_FALSE` otherwise

    588:   Level: beginner

    590: .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
    591:           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
    592: @*/
    593: PetscErrorCode PetscLayoutCompare(PetscLayout mapa, PetscLayout mapb, PetscBool *congruent)
    594: {
    595:   PetscFunctionBegin;
    596:   *congruent = PETSC_FALSE;
    597:   if (mapa->N == mapb->N && mapa->range && mapb->range && mapa->size == mapb->size) PetscCall(PetscArraycmp(mapa->range, mapb->range, mapa->size + 1, congruent));
    598:   PetscFunctionReturn(PETSC_SUCCESS);
    599: }

    601: /*@
    602:   PetscLayoutFindOwner - Find the owning MPI process for a global index

    604:   Not Collective; No Fortran Support

    606:   Input Parameters:
    607: + map - the layout
    608: - idx - global index to find the owner of

    610:   Output Parameter:
    611: . owner - the owning rank

    613:   Level: developer

    615: .seealso: `PetscLayout`, `PetscLayoutFindOwnerIndex()`
    616: @*/
    617: PetscErrorCode PetscLayoutFindOwner(PetscLayout map, PetscInt idx, PetscMPIInt *owner)
    618: {
    619:   PetscMPIInt lo = 0, hi, t;

    621:   PetscFunctionBegin;
    622:   *owner = -1; /* GCC erroneously issues warning about possibly uninitialized use when error condition */
    623:   PetscAssert((map->n >= 0) && (map->N >= 0) && (map->range), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscLayoutSetUp() must be called first");
    624:   PetscAssert(idx >= 0 && idx <= map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " is out of range", idx);
    625:   hi = map->size;
    626:   while (hi - lo > 1) {
    627:     t = lo + (hi - lo) / 2;
    628:     if (idx < map->range[t]) hi = t;
    629:     else lo = t;
    630:   }
    631:   *owner = lo;
    632:   PetscFunctionReturn(PETSC_SUCCESS);
    633: }

    635: /*@
    636:   PetscLayoutFindOwnerIndex - Find the owning MPI process and the local index on that process for a global index

    638:   Not Collective; No Fortran Support

    640:   Input Parameters:
    641: + map - the layout
    642: - idx - global index to find the owner of

    644:   Output Parameters:
    645: + owner - the owning rank
    646: - lidx  - local index used by the owner for `idx`

    648:   Level: developer

    650: .seealso: `PetscLayout`, `PetscLayoutFindOwner()`
    651: @*/
    652: PetscErrorCode PetscLayoutFindOwnerIndex(PetscLayout map, PetscInt idx, PetscMPIInt *owner, PetscInt *lidx)
    653: {
    654:   PetscMPIInt lo = 0, hi, t;

    656:   PetscFunctionBegin;
    657:   PetscAssert((map->n >= 0) && (map->N >= 0) && (map->range), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscLayoutSetUp() must be called first");
    658:   PetscAssert(idx >= 0 && idx <= map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " is out of range", idx);
    659:   hi = map->size;
    660:   while (hi - lo > 1) {
    661:     t = lo + (hi - lo) / 2;
    662:     if (idx < map->range[t]) hi = t;
    663:     else lo = t;
    664:   }
    665:   if (owner) *owner = lo;
    666:   if (lidx) *lidx = idx - map->range[lo];
    667:   PetscFunctionReturn(PETSC_SUCCESS);
    668: }