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