xref: /petsc/src/vec/is/utils/pmap.c (revision ccfb0f9f40a0131988d7995ed9679700dae2a75a)
1 /*
2    This file contains routines for basic map object implementation.
3 */
4 
5 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/
6 
7 /*@
8   PetscLayoutCreate - Allocates `PetscLayout` object
9 
10   Collective
11 
12   Input Parameter:
13 . comm - the MPI communicator
14 
15   Output Parameter:
16 . map - the new `PetscLayout`
17 
18   Level: advanced
19 
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
32 
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
41 
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.
44 
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 }
69 
70 /*@
71   PetscLayoutCreateFromSizes - Allocates `PetscLayout` object and sets the layout sizes, and sets the layout up.
72 
73   Collective
74 
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`)
80 
81   Output Parameter:
82 . map - the new `PetscLayout`
83 
84   Level: advanced
85 
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
98 
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 }
112 
113 /*@
114   PetscLayoutDestroy - Frees a `PetscLayout` object and frees its range if that exists.
115 
116   Collective
117 
118   Input Parameter:
119 . map - the `PetscLayout`
120 
121   Level: developer
122 
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 }
139 
140 /*@
141   PetscLayoutCreateFromRanges - Creates a new `PetscLayout` with the given ownership ranges and sets it up.
142 
143   Collective
144 
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`)
150 
151   Output Parameter:
152 . newmap - the new `PetscLayout`
153 
154   Level: developer
155 
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;
164 
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;
176     break;
177   default:
178     map->range = (PetscInt *)range;
179     break;
180   }
181   map->rstart = map->range[rank];
182   map->rend   = map->range[rank + 1];
183   map->n      = map->rend - map->rstart;
184   map->N      = map->range[map->size];
185   if (PetscDefined(USE_DEBUG)) { /* just check that n, N and bs are consistent */
186     PetscInt tmp;
187     PetscCallMPI(MPIU_Allreduce(&map->n, &tmp, 1, MPIU_INT, MPI_SUM, map->comm));
188     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);
189     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);
190     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);
191   }
192   /* lock the layout */
193   map->setupcalled = PETSC_TRUE;
194   map->oldn        = map->n;
195   map->oldN        = map->N;
196   map->oldbs       = map->bs;
197   *newmap          = map;
198   PetscFunctionReturn(PETSC_SUCCESS);
199 }
200 
201 /*@
202   PetscLayoutSetUp - given a map where you have set either the global or local
203   size sets up the map so that it may be used.
204 
205   Collective
206 
207   Input Parameter:
208 . map - pointer to the map
209 
210   Level: developer
211 
212   Notes:
213   Typical calling sequence
214 .vb
215   PetscLayoutCreate(MPI_Comm,PetscLayout *);
216   PetscLayoutSetBlockSize(PetscLayout,1);
217   PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both
218   PetscLayoutSetUp(PetscLayout);
219   PetscLayoutGetSize(PetscLayout,PetscInt *);
220 .ve
221 
222   If range exists, and local size is not set, everything gets computed from the range.
223 
224   If the local size, global size are already set and range exists then this does nothing.
225 
226 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`,
227           `PetscLayout`, `PetscLayoutDestroy()`,
228           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutCreate()`, `PetscSplitOwnership()`
229 @*/
230 PetscErrorCode PetscLayoutSetUp(PetscLayout map)
231 {
232   PetscMPIInt rank;
233   PetscInt    p;
234 
235   PetscFunctionBegin;
236   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 ")",
237              map->oldn, map->oldN, map->n, map->N);
238   if (map->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
239 
240   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);
241   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);
242 
243   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
244   if (map->n > 0) map->n = map->n / map->bs;
245   if (map->N > 0) map->N = map->N / map->bs;
246   PetscCall(PetscSplitOwnership(map->comm, &map->n, &map->N));
247   map->n = map->n * map->bs;
248   map->N = map->N * map->bs;
249   if (!map->range) PetscCall(PetscMalloc1(map->size + 1, &map->range));
250   PetscCallMPI(MPI_Allgather(&map->n, 1, MPIU_INT, map->range + 1, 1, MPIU_INT, map->comm));
251 
252   map->range[0] = 0;
253   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p - 1];
254 
255   map->rstart = map->range[rank];
256   map->rend   = map->range[rank + 1];
257 
258   /* lock the layout */
259   map->setupcalled = PETSC_TRUE;
260   map->oldn        = map->n;
261   map->oldN        = map->N;
262   map->oldbs       = map->bs;
263   PetscFunctionReturn(PETSC_SUCCESS);
264 }
265 
266 /*@
267   PetscLayoutDuplicate - creates a new `PetscLayout` with the same information as a given one. If the `PetscLayout` already exists it is destroyed first.
268 
269   Collective
270 
271   Input Parameter:
272 . in - input `PetscLayout` to be duplicated
273 
274   Output Parameter:
275 . out - the copy
276 
277   Level: developer
278 
279   Note:
280   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
281 
282 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutReference()`
283 @*/
284 PetscErrorCode PetscLayoutDuplicate(PetscLayout in, PetscLayout *out)
285 {
286   MPI_Comm comm = in->comm;
287 
288   PetscFunctionBegin;
289   PetscCall(PetscLayoutDestroy(out));
290   PetscCall(PetscLayoutCreate(comm, out));
291   PetscCall(PetscMemcpy(*out, in, sizeof(struct _n_PetscLayout)));
292   if (in->range) {
293     PetscCall(PetscMalloc1((*out)->size + 1, &(*out)->range));
294     PetscCall(PetscArraycpy((*out)->range, in->range, (*out)->size + 1));
295   }
296   (*out)->refcnt = 0;
297   PetscFunctionReturn(PETSC_SUCCESS);
298 }
299 
300 /*@
301   PetscLayoutReference - Causes a PETSc `Vec` or `Mat` to share a `PetscLayout` with one that already exists.
302 
303   Collective
304 
305   Input Parameter:
306 . in - input `PetscLayout` to be copied
307 
308   Output Parameter:
309 . out - the reference location
310 
311   Level: developer
312 
313   Notes:
314   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
315 
316   If the out location already contains a `PetscLayout` it is destroyed
317 
318 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
319 @*/
320 PetscErrorCode PetscLayoutReference(PetscLayout in, PetscLayout *out)
321 {
322   PetscFunctionBegin;
323   in->refcnt++;
324   PetscCall(PetscLayoutDestroy(out));
325   *out = in;
326   PetscFunctionReturn(PETSC_SUCCESS);
327 }
328 
329 /*@
330   PetscLayoutSetISLocalToGlobalMapping - sets a `ISLocalGlobalMapping` into a `PetscLayout`
331 
332   Collective
333 
334   Input Parameters:
335 + in   - input `PetscLayout`
336 - ltog - the local to global mapping
337 
338   Level: developer
339 
340   Notes:
341   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
342 
343   If the `PetscLayout` already contains a `ISLocalGlobalMapping` it is destroyed
344 
345 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
346 @*/
347 PetscErrorCode PetscLayoutSetISLocalToGlobalMapping(PetscLayout in, ISLocalToGlobalMapping ltog)
348 {
349   PetscFunctionBegin;
350   if (ltog) {
351     PetscInt bs;
352 
353     PetscCall(ISLocalToGlobalMappingGetBlockSize(ltog, &bs));
354     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);
355   }
356   PetscCall(PetscObjectReference((PetscObject)ltog));
357   PetscCall(ISLocalToGlobalMappingDestroy(&in->mapping));
358   in->mapping = ltog;
359   PetscFunctionReturn(PETSC_SUCCESS);
360 }
361 
362 /*@
363   PetscLayoutSetLocalSize - Sets the local size for a `PetscLayout` object.
364 
365   Collective
366 
367   Input Parameters:
368 + map - pointer to the map
369 - n   - the local size, pass `PETSC_DECIDE` (the default) to have this value determined by the global size set with `PetscLayoutSetSize()`
370 
371   Level: developer
372 
373 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetUp()`
374           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
375 @*/
376 PetscErrorCode PetscLayoutSetLocalSize(PetscLayout map, PetscInt n)
377 {
378   PetscFunctionBegin;
379   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);
380   map->n = n;
381   PetscFunctionReturn(PETSC_SUCCESS);
382 }
383 
384 /*@
385   PetscLayoutGetLocalSize - Gets the local size for a `PetscLayout` object.
386 
387   Not Collective
388 
389   Input Parameter:
390 . map - pointer to the map
391 
392   Output Parameter:
393 . n - the local size
394 
395   Level: developer
396 
397   Note:
398   Call this after the call to `PetscLayoutSetUp()`
399 
400 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
401           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
402 @*/
403 PetscErrorCode PetscLayoutGetLocalSize(PetscLayout map, PetscInt *n)
404 {
405   PetscFunctionBegin;
406   *n = map->n;
407   PetscFunctionReturn(PETSC_SUCCESS);
408 }
409 
410 /*@
411   PetscLayoutSetSize - Sets the global size for a `PetscLayout` object.
412 
413   Logically Collective
414 
415   Input Parameters:
416 + map - pointer to the map
417 - n   - the global size, use `PETSC_DETERMINE` (the default) to have this value computed as the sum of the local sizes set with `PetscLayoutSetLocalSize()`
418 
419   Level: developer
420 
421 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
422           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
423 @*/
424 PetscErrorCode PetscLayoutSetSize(PetscLayout map, PetscInt n)
425 {
426   PetscFunctionBegin;
427   map->N = n;
428   PetscFunctionReturn(PETSC_SUCCESS);
429 }
430 
431 /*@
432   PetscLayoutGetSize - Gets the global size for a `PetscLayout` object.
433 
434   Not Collective
435 
436   Input Parameter:
437 . map - pointer to the map
438 
439   Output Parameter:
440 . n - the global size
441 
442   Level: developer
443 
444   Note:
445   Call this after the call to `PetscLayoutSetUp()`
446 
447 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`
448           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
449 @*/
450 PetscErrorCode PetscLayoutGetSize(PetscLayout map, PetscInt *n)
451 {
452   PetscFunctionBegin;
453   *n = map->N;
454   PetscFunctionReturn(PETSC_SUCCESS);
455 }
456 
457 /*@
458   PetscLayoutSetBlockSize - Sets the block size for a `PetscLayout` object.
459 
460   Logically Collective
461 
462   Input Parameters:
463 + map - pointer to the map
464 - bs  - the size
465 
466   Level: developer
467 
468 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
469           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
470 @*/
471 PetscErrorCode PetscLayoutSetBlockSize(PetscLayout map, PetscInt bs)
472 {
473   PetscFunctionBegin;
474   PetscCheck(bs > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Block size %" PetscInt_FMT " must be positive", bs);
475   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);
476   if (map->mapping) {
477     PetscInt obs;
478 
479     PetscCall(ISLocalToGlobalMappingGetBlockSize(map->mapping, &obs));
480     if (obs > 1) PetscCall(ISLocalToGlobalMappingSetBlockSize(map->mapping, bs));
481   }
482   map->bs = bs;
483   PetscFunctionReturn(PETSC_SUCCESS);
484 }
485 
486 /*@
487   PetscLayoutGetBlockSize - Gets the block size for a `PetscLayout` object.
488 
489   Not Collective
490 
491   Input Parameter:
492 . map - pointer to the map
493 
494   Output Parameter:
495 . bs - the size
496 
497   Level: developer
498 
499   Notes:
500   Call this after the call to `PetscLayoutSetUp()`
501 
502 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`
503           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetSize()`
504 @*/
505 PetscErrorCode PetscLayoutGetBlockSize(PetscLayout map, PetscInt *bs)
506 {
507   PetscFunctionBegin;
508   *bs = map->bs;
509   PetscFunctionReturn(PETSC_SUCCESS);
510 }
511 
512 /*@
513   PetscLayoutGetRange - gets the range of values owned by this process
514 
515   Not Collective
516 
517   Input Parameter:
518 . map - pointer to the map
519 
520   Output Parameters:
521 + rstart - first index owned by this process
522 - rend   - one more than the last index owned by this process
523 
524   Level: developer
525 
526   Note:
527   Call this after the call to `PetscLayoutSetUp()`
528 
529 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
530           `PetscLayoutGetSize()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutSetUp()`
531 @*/
532 PetscErrorCode PetscLayoutGetRange(PetscLayout map, PetscInt *rstart, PetscInt *rend)
533 {
534   PetscFunctionBegin;
535   if (rstart) *rstart = map->rstart;
536   if (rend) *rend = map->rend;
537   PetscFunctionReturn(PETSC_SUCCESS);
538 }
539 
540 /*@C
541   PetscLayoutGetRanges - gets the ranges of values owned by all processes
542 
543   Not Collective
544 
545   Input Parameter:
546 . map - pointer to the map
547 
548   Output Parameter:
549 . range - start of each processors range of indices (the final entry is one more than the
550           last index on the last process). The length of the array is one more than the number of processes in the MPI
551           communicator owned by `map`
552 
553   Level: developer
554 
555   Note:
556   Call this after the call to `PetscLayoutSetUp()`
557 
558   Fortran Notes:
559 .vb
560   PetscInt, pointer :: range(:)
561 .ve
562 
563   Call `PetscLayoutRestoreRanges()` when no longer needed.
564 
565 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
566           `PetscLayoutGetSize()`, `PetscLayoutGetRange()`, `PetscLayoutSetBlockSize()`, `PetscLayoutSetUp()`
567 @*/
568 PetscErrorCode PetscLayoutGetRanges(PetscLayout map, const PetscInt *range[])
569 {
570   PetscFunctionBegin;
571   *range = map->range;
572   PetscFunctionReturn(PETSC_SUCCESS);
573 }
574 
575 /*@
576   PetscLayoutCompare - Compares two layouts
577 
578   Not Collective
579 
580   Input Parameters:
581 + mapa - pointer to the first map
582 - mapb - pointer to the second map
583 
584   Output Parameter:
585 . congruent - `PETSC_TRUE` if the two layouts are congruent, `PETSC_FALSE` otherwise
586 
587   Level: beginner
588 
589 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
590           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
591 @*/
592 PetscErrorCode PetscLayoutCompare(PetscLayout mapa, PetscLayout mapb, PetscBool *congruent)
593 {
594   PetscFunctionBegin;
595   *congruent = PETSC_FALSE;
596   if (mapa->N == mapb->N && mapa->range && mapb->range && mapa->size == mapb->size) PetscCall(PetscArraycmp(mapa->range, mapb->range, mapa->size + 1, congruent));
597   PetscFunctionReturn(PETSC_SUCCESS);
598 }
599 
600 /*@
601   PetscLayoutFindOwner - Find the owning MPI process for a global index
602 
603   Not Collective; No Fortran Support
604 
605   Input Parameters:
606 + map - the layout
607 - idx - global index to find the owner of
608 
609   Output Parameter:
610 . owner - the owning rank
611 
612   Level: developer
613 
614 .seealso: `PetscLayout`, `PetscLayoutFindOwnerIndex()`
615 @*/
616 PetscErrorCode PetscLayoutFindOwner(PetscLayout map, PetscInt idx, PetscMPIInt *owner)
617 {
618   PetscMPIInt lo = 0, hi, t;
619 
620   PetscFunctionBegin;
621   *owner = -1; /* GCC erroneously issues warning about possibly uninitialized use when error condition */
622   PetscAssert((map->n >= 0) && (map->N >= 0) && (map->range), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscLayoutSetUp() must be called first");
623   PetscAssert(idx >= 0 && idx <= map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " is out of range", idx);
624   hi = map->size;
625   while (hi - lo > 1) {
626     t = lo + (hi - lo) / 2;
627     if (idx < map->range[t]) hi = t;
628     else lo = t;
629   }
630   *owner = lo;
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@
635   PetscLayoutFindOwnerIndex - Find the owning MPI process and the local index on that process for a global index
636 
637   Not Collective; No Fortran Support
638 
639   Input Parameters:
640 + map - the layout
641 - idx - global index to find the owner of
642 
643   Output Parameters:
644 + owner - the owning rank
645 - lidx  - local index used by the owner for `idx`
646 
647   Level: developer
648 
649 .seealso: `PetscLayout`, `PetscLayoutFindOwner()`
650 @*/
651 PetscErrorCode PetscLayoutFindOwnerIndex(PetscLayout map, PetscInt idx, PetscMPIInt *owner, PetscInt *lidx)
652 {
653   PetscMPIInt lo = 0, hi, t;
654 
655   PetscFunctionBegin;
656   PetscAssert((map->n >= 0) && (map->N >= 0) && (map->range), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscLayoutSetUp() must be called first");
657   PetscAssert(idx >= 0 && idx <= map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index %" PetscInt_FMT " is out of range", idx);
658   hi = map->size;
659   while (hi - lo > 1) {
660     t = lo + (hi - lo) / 2;
661     if (idx < map->range[t]) hi = t;
662     else lo = t;
663   }
664   if (owner) *owner = lo;
665   if (lidx) *lidx = idx - map->range[lo];
666   PetscFunctionReturn(PETSC_SUCCESS);
667 }
668