xref: /petsc/src/vec/is/utils/pmap.c (revision 750b007cd8d816cecd9de99077bb0a703b4cf61a)
1 
2 /*
3    This file contains routines for basic map object implementation.
4 */
5 
6 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/
7 
8 /*@
9   PetscLayoutCreate - Allocates PetscLayout space and sets the PetscLayout contents to the default.
10 
11   Collective
12 
13   Input Parameters:
14 . comm - the MPI communicator
15 
16   Output Parameters:
17 . map - the new PetscLayout
18 
19   Level: advanced
20 
21   Notes:
22   Typical calling sequence
23 .vb
24        PetscLayoutCreate(MPI_Comm,PetscLayout *);
25        PetscLayoutSetBlockSize(PetscLayout,bs);
26        PetscLayoutSetSize(PetscLayout,N); // or PetscLayoutSetLocalSize(PetscLayout,n);
27        PetscLayoutSetUp(PetscLayout);
28 .ve
29   Alternatively,
30 .vb
31       PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
32 .ve
33 
34   Optionally use any of the following
35 .vb
36   PetscLayoutGetSize(PetscLayout,PetscInt *);
37   PetscLayoutGetLocalSize(PetscLayout,PetscInt *);
38   PetscLayoutGetRange(PetscLayout,PetscInt *rstart,PetscInt *rend);
39   PetscLayoutGetRanges(PetscLayout,const PetscInt *range[]);
40   PetscLayoutDestroy(PetscLayout*);
41 .ve
42 
43   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementations; it is often not needed in
44   user codes unless you really gain something in their use.
45 
46 .seealso: `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
47           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`,
48           `PetscLayoutCreateFromSizes()`
49 
50 @*/
51 PetscErrorCode PetscLayoutCreate(MPI_Comm comm, PetscLayout *map) {
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(0);
68 }
69 
70 /*@
71   PetscLayoutCreateFromSizes - Allocates PetscLayout space, 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 Parameters:
82 . map - the new PetscLayout
83 
84   Level: advanced
85 
86   Notes:
87 $ PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
88   is a shorthand for
89 .vb
90   PetscLayoutCreate(comm,&layout);
91   PetscLayoutSetLocalSize(layout,n);
92   PetscLayoutSetSize(layout,N);
93   PetscLayoutSetBlockSize(layout,bs);
94   PetscLayoutSetUp(layout);
95 .ve
96 
97 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
98           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`, `PetscLayoutCreateFromRanges()`
99 
100 @*/
101 PetscErrorCode PetscLayoutCreateFromSizes(MPI_Comm comm, PetscInt n, PetscInt N, PetscInt bs, PetscLayout *map) {
102   PetscFunctionBegin;
103   PetscCall(PetscLayoutCreate(comm, map));
104   PetscCall(PetscLayoutSetLocalSize(*map, n));
105   PetscCall(PetscLayoutSetSize(*map, N));
106   PetscCall(PetscLayoutSetBlockSize(*map, bs));
107   PetscCall(PetscLayoutSetUp(*map));
108   PetscFunctionReturn(0);
109 }
110 
111 /*@
112   PetscLayoutDestroy - Frees a map object and frees its range if that exists.
113 
114   Collective
115 
116   Input Parameters:
117 . map - the PetscLayout
118 
119   Level: developer
120 
121   Note:
122   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementations; it is
123   recommended they not be used in user codes unless you really gain something in their use.
124 
125 .seealso: `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutCreate()`,
126           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`
127 
128 @*/
129 PetscErrorCode PetscLayoutDestroy(PetscLayout *map) {
130   PetscFunctionBegin;
131   if (!*map) PetscFunctionReturn(0);
132   if (!(*map)->refcnt--) {
133     if ((*map)->range_alloc) PetscCall(PetscFree((*map)->range));
134     PetscCall(ISLocalToGlobalMappingDestroy(&(*map)->mapping));
135     PetscCall(PetscFree((*map)));
136   }
137   *map = NULL;
138   PetscFunctionReturn(0);
139 }
140 
141 /*@
142   PetscLayoutCreateFromRanges - Creates a new PetscLayout with the given ownership ranges and sets it up.
143 
144   Collective
145 
146   Input Parameters:
147 + comm  - the MPI communicator
148 . range - the array of ownership ranges for each rank with length commsize+1
149 . mode  - the copy mode for range
150 - bs    - the block size (or PETSC_DECIDE)
151 
152   Output Parameters:
153 . newmap - the new PetscLayout
154 
155   Level: developer
156 
157 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
158           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutSetUp()`, `PetscLayoutCreateFromSizes()`
159 
160 @*/
161 PetscErrorCode PetscLayoutCreateFromRanges(MPI_Comm comm, const PetscInt range[], PetscCopyMode mode, PetscInt bs, PetscLayout *newmap) {
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: map->range_alloc = PETSC_FALSE; break;
175   default: map->range = (PetscInt *)range; break;
176   }
177   map->rstart = map->range[rank];
178   map->rend   = map->range[rank + 1];
179   map->n      = map->rend - map->rstart;
180   map->N      = map->range[map->size];
181   if (PetscDefined(USE_DEBUG)) { /* just check that n, N and bs are consistent */
182     PetscInt tmp;
183     PetscCall(MPIU_Allreduce(&map->n, &tmp, 1, MPIU_INT, MPI_SUM, map->comm));
184     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 ".\nThe provided PetscLayout is wrong.", tmp, map->N, map->n);
185     if (map->bs > 1) 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);
186     if (map->bs > 1) 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);
187   }
188   /* lock the layout */
189   map->setupcalled = PETSC_TRUE;
190   map->oldn        = map->n;
191   map->oldN        = map->N;
192   map->oldbs       = map->bs;
193   *newmap          = map;
194   PetscFunctionReturn(0);
195 }
196 
197 /*@
198   PetscLayoutSetUp - given a map where you have set either the global or local
199                      size sets up the map so that it may be used.
200 
201   Collective
202 
203   Input Parameters:
204 . map - pointer to the map
205 
206   Level: developer
207 
208   Notes:
209     Typical calling sequence
210 $ PetscLayoutCreate(MPI_Comm,PetscLayout *);
211 $ PetscLayoutSetBlockSize(PetscLayout,1);
212 $ PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both
213 $ PetscLayoutSetUp(PetscLayout);
214 $ PetscLayoutGetSize(PetscLayout,PetscInt *);
215 
216   If range exists, and local size is not set, everything gets computed from the range.
217 
218   If the local size, global size are already set and range exists then this does nothing.
219 
220 .seealso: `PetscLayoutSetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayout`, `PetscLayoutDestroy()`,
221           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`, `PetscLayoutCreate()`, `PetscSplitOwnership()`
222 @*/
223 PetscErrorCode PetscLayoutSetUp(PetscLayout map) {
224   PetscMPIInt rank;
225   PetscInt    p;
226 
227   PetscFunctionBegin;
228   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 ")",
229              map->oldn, map->oldN, map->n, map->N);
230   if (map->setupcalled) PetscFunctionReturn(0);
231 
232   if (map->n > 0 && map->bs > 1) 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);
233   if (map->N > 0 && map->bs > 1) 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);
234 
235   PetscCallMPI(MPI_Comm_rank(map->comm, &rank));
236   if (map->n > 0) map->n = map->n / PetscAbs(map->bs);
237   if (map->N > 0) map->N = map->N / PetscAbs(map->bs);
238   PetscCall(PetscSplitOwnership(map->comm, &map->n, &map->N));
239   map->n = map->n * PetscAbs(map->bs);
240   map->N = map->N * PetscAbs(map->bs);
241   if (!map->range) PetscCall(PetscMalloc1(map->size + 1, &map->range));
242   PetscCallMPI(MPI_Allgather(&map->n, 1, MPIU_INT, map->range + 1, 1, MPIU_INT, map->comm));
243 
244   map->range[0] = 0;
245   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p - 1];
246 
247   map->rstart = map->range[rank];
248   map->rend   = map->range[rank + 1];
249 
250   /* lock the layout */
251   map->setupcalled = PETSC_TRUE;
252   map->oldn        = map->n;
253   map->oldN        = map->N;
254   map->oldbs       = map->bs;
255   PetscFunctionReturn(0);
256 }
257 
258 /*@
259   PetscLayoutDuplicate - creates a new PetscLayout with the same information as a given one. If the PetscLayout already exists it is destroyed first.
260 
261   Collective on PetscLayout
262 
263   Input Parameter:
264 . in - input PetscLayout to be duplicated
265 
266   Output Parameter:
267 . out - the copy
268 
269   Level: developer
270 
271   Notes:
272     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
273 
274 .seealso: `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutReference()`
275 @*/
276 PetscErrorCode PetscLayoutDuplicate(PetscLayout in, PetscLayout *out) {
277   MPI_Comm comm = in->comm;
278 
279   PetscFunctionBegin;
280   PetscCall(PetscLayoutDestroy(out));
281   PetscCall(PetscLayoutCreate(comm, out));
282   PetscCall(PetscMemcpy(*out, in, sizeof(struct _n_PetscLayout)));
283   if (in->range) {
284     PetscCall(PetscMalloc1((*out)->size + 1, &(*out)->range));
285     PetscCall(PetscArraycpy((*out)->range, in->range, (*out)->size + 1));
286   }
287   (*out)->refcnt = 0;
288   PetscFunctionReturn(0);
289 }
290 
291 /*@
292   PetscLayoutReference - Causes a PETSc Vec or Mat to share a PetscLayout with one that already exists. Used by Vec/MatDuplicate_XXX()
293 
294   Collective on PetscLayout
295 
296   Input Parameter:
297 . in - input PetscLayout to be copied
298 
299   Output Parameter:
300 . out - the reference location
301 
302   Level: developer
303 
304   Notes:
305     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
306 
307   If the out location already contains a PetscLayout it is destroyed
308 
309 .seealso: `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
310 @*/
311 PetscErrorCode PetscLayoutReference(PetscLayout in, PetscLayout *out) {
312   PetscFunctionBegin;
313   in->refcnt++;
314   PetscCall(PetscLayoutDestroy(out));
315   *out = in;
316   PetscFunctionReturn(0);
317 }
318 
319 /*@
320   PetscLayoutSetISLocalToGlobalMapping - sets a ISLocalGlobalMapping into a PetscLayout
321 
322   Collective on PetscLayout
323 
324   Input Parameters:
325 + in - input PetscLayout
326 - ltog - the local to global mapping
327 
328   Level: developer
329 
330   Notes:
331     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
332 
333   If the ltog location already contains a PetscLayout it is destroyed
334 
335 .seealso: `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutDuplicate()`
336 @*/
337 PetscErrorCode PetscLayoutSetISLocalToGlobalMapping(PetscLayout in, ISLocalToGlobalMapping ltog) {
338   PetscFunctionBegin;
339   if (ltog) {
340     PetscInt bs;
341 
342     PetscCall(ISLocalToGlobalMappingGetBlockSize(ltog, &bs));
343     PetscCheck(in->bs <= 0 || 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);
344     PetscCall(PetscObjectReference((PetscObject)ltog));
345   }
346   PetscCall(ISLocalToGlobalMappingDestroy(&in->mapping));
347   in->mapping = ltog;
348   PetscFunctionReturn(0);
349 }
350 
351 /*@
352   PetscLayoutSetLocalSize - Sets the local size for a PetscLayout object.
353 
354   Collective on PetscLayout
355 
356   Input Parameters:
357 + map - pointer to the map
358 - n - the local size
359 
360   Level: developer
361 
362   Notes:
363   Call this after the call to PetscLayoutCreate()
364 
365 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetUp()`
366           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
367 @*/
368 PetscErrorCode PetscLayoutSetLocalSize(PetscLayout map, PetscInt n) {
369   PetscFunctionBegin;
370   PetscCheck(map->bs <= 1 || (n % map->bs) == 0, map->comm, PETSC_ERR_ARG_INCOMP, "Local size %" PetscInt_FMT " not compatible with block size %" PetscInt_FMT, n, map->bs);
371   map->n = n;
372   PetscFunctionReturn(0);
373 }
374 
375 /*@
376      PetscLayoutGetLocalSize - Gets the local size for a PetscLayout object.
377 
378     Not Collective
379 
380    Input Parameters:
381 .    map - pointer to the map
382 
383    Output Parameters:
384 .    n - the local size
385 
386    Level: developer
387 
388     Notes:
389        Call this after the call to PetscLayoutSetUp()
390 
391     Fortran Notes:
392       Not available from Fortran
393 
394 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetUp()`
395           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
396 
397 @*/
398 PetscErrorCode PetscLayoutGetLocalSize(PetscLayout map, PetscInt *n) {
399   PetscFunctionBegin;
400   *n = map->n;
401   PetscFunctionReturn(0);
402 }
403 
404 /*@
405   PetscLayoutSetSize - Sets the global size for a PetscLayout object.
406 
407   Logically Collective on PetscLayout
408 
409   Input Parameters:
410 + map - pointer to the map
411 - n - the global size
412 
413   Level: developer
414 
415   Notes:
416   Call this after the call to PetscLayoutCreate()
417 
418 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
419           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
420 @*/
421 PetscErrorCode PetscLayoutSetSize(PetscLayout map, PetscInt n) {
422   PetscFunctionBegin;
423   map->N = n;
424   PetscFunctionReturn(0);
425 }
426 
427 /*@
428   PetscLayoutGetSize - Gets the global size for a PetscLayout object.
429 
430   Not Collective
431 
432   Input Parameters:
433 . map - pointer to the map
434 
435   Output Parameters:
436 . n - the global size
437 
438   Level: developer
439 
440   Notes:
441   Call this after the call to PetscLayoutSetUp()
442 
443 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`
444           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetBlockSize()`
445 @*/
446 PetscErrorCode PetscLayoutGetSize(PetscLayout map, PetscInt *n) {
447   PetscFunctionBegin;
448   *n = map->N;
449   PetscFunctionReturn(0);
450 }
451 
452 /*@
453   PetscLayoutSetBlockSize - Sets the block size for a PetscLayout object.
454 
455   Logically Collective on PetscLayout
456 
457   Input Parameters:
458 + map - pointer to the map
459 - bs - the size
460 
461   Level: developer
462 
463   Notes:
464   Call this after the call to PetscLayoutCreate()
465 
466 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
467           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
468 @*/
469 PetscErrorCode PetscLayoutSetBlockSize(PetscLayout map, PetscInt bs) {
470   PetscFunctionBegin;
471   if (bs < 0) PetscFunctionReturn(0);
472   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);
473   if (map->mapping) {
474     PetscInt obs;
475 
476     PetscCall(ISLocalToGlobalMappingGetBlockSize(map->mapping, &obs));
477     if (obs > 1) PetscCall(ISLocalToGlobalMappingSetBlockSize(map->mapping, bs));
478   }
479   map->bs = bs;
480   PetscFunctionReturn(0);
481 }
482 
483 /*@
484   PetscLayoutGetBlockSize - Gets the block size for a PetscLayout object.
485 
486   Not Collective
487 
488   Input Parameters:
489 . map - pointer to the map
490 
491   Output Parameters:
492 . bs - the size
493 
494   Level: developer
495 
496   Notes:
497   Call this after the call to PetscLayoutSetUp()
498 
499 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`, `PetscLayoutSetUp()`
500           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetSize()`
501 @*/
502 PetscErrorCode PetscLayoutGetBlockSize(PetscLayout map, PetscInt *bs) {
503   PetscFunctionBegin;
504   *bs = PetscAbs(map->bs);
505   PetscFunctionReturn(0);
506 }
507 
508 /*@
509   PetscLayoutGetRange - gets the range of values owned by this process
510 
511   Not Collective
512 
513   Input Parameter:
514 . map - pointer to the map
515 
516   Output Parameters:
517 + rstart - first index owned by this process
518 - rend   - one more than the last index owned by this process
519 
520   Level: developer
521 
522   Notes:
523   Call this after the call to PetscLayoutSetUp()
524 
525 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
526           `PetscLayoutGetSize()`, `PetscLayoutGetRanges()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
527 @*/
528 PetscErrorCode PetscLayoutGetRange(PetscLayout map, PetscInt *rstart, PetscInt *rend) {
529   PetscFunctionBegin;
530   if (rstart) *rstart = map->rstart;
531   if (rend) *rend = map->rend;
532   PetscFunctionReturn(0);
533 }
534 
535 /*@C
536      PetscLayoutGetRanges - gets the range of values owned by all processes
537 
538     Not Collective
539 
540    Input Parameters:
541 .    map - pointer to the map
542 
543    Output Parameters:
544 .    range - start of each processors range of indices (the final entry is one more than the
545              last index on the last process)
546 
547    Level: developer
548 
549     Notes:
550        Call this after the call to PetscLayoutSetUp()
551 
552     Fortran Notes:
553       Not available from Fortran
554 
555 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutSetSize()`,
556           `PetscLayoutGetSize()`, `PetscLayoutGetRange()`, `PetscLayoutSetBlockSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
557 
558 @*/
559 PetscErrorCode PetscLayoutGetRanges(PetscLayout map, const PetscInt *range[]) {
560   PetscFunctionBegin;
561   *range = map->range;
562   PetscFunctionReturn(0);
563 }
564 
565 /*@
566   PetscLayoutCompare - Compares two layouts
567 
568   Not Collective
569 
570   Input Parameters:
571 + mapa - pointer to the first map
572 - mapb - pointer to the second map
573 
574   Output Parameters:
575 . congruent - PETSC_TRUE if the two layouts are congruent, PETSC_FALSE otherwise
576 
577   Level: beginner
578 
579   Notes:
580 
581 .seealso: `PetscLayoutCreate()`, `PetscLayoutSetLocalSize()`, `PetscLayoutGetLocalSize()`, `PetscLayoutGetBlockSize()`,
582           `PetscLayoutGetRange()`, `PetscLayoutGetRanges()`, `PetscLayoutSetSize()`, `PetscLayoutGetSize()`, `PetscLayoutSetUp()`
583 @*/
584 PetscErrorCode PetscLayoutCompare(PetscLayout mapa, PetscLayout mapb, PetscBool *congruent) {
585   PetscFunctionBegin;
586   *congruent = PETSC_FALSE;
587   if (mapa->N == mapb->N && mapa->range && mapb->range && mapa->size == mapb->size) PetscCall(PetscArraycmp(mapa->range, mapb->range, mapa->size + 1, congruent));
588   PetscFunctionReturn(0);
589 }
590