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