xref: /petsc/src/vec/is/utils/pmap.c (revision d52a580b706c59ca78066c1e38754e45b6b56e2b)
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; /* fall through */
176   case PETSC_OWN_POINTER:
177     map->range = (PetscInt *)range;
178     break;
179   default:
180     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Received invalid PetscCopyMode somehow");
181   }
182   map->rstart = map->range[rank];
183   map->rend   = map->range[rank + 1];
184   map->n      = map->rend - map->rstart;
185   map->N      = map->range[map->size] - map->range[0];
186   if (PetscDefined(USE_DEBUG)) { /* just check that n, N and bs are consistent */
187     PetscInt tmp;
188     PetscCallMPI(MPIU_Allreduce(&map->n, &tmp, 1, MPIU_INT, MPI_SUM, map->comm));
189     PetscCheck(tmp == map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local lengths %" PetscInt_FMT " does not equal global length %" PetscInt_FMT ", my local length %" PetscInt_FMT ". The provided PetscLayout is wrong.", tmp, map->N, map->n);
190     PetscCheck(map->n % map->bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->n, map->bs);
191     PetscCheck(map->N % map->bs == 0, map->comm, PETSC_ERR_PLIB, "Global size %" PetscInt_FMT " must be divisible by blocksize %" PetscInt_FMT, map->N, map->bs);
192   }
193   /* lock the layout */
194   map->setupcalled = PETSC_TRUE;
195   map->oldn        = map->n;
196   map->oldN        = map->N;
197   map->oldbs       = map->bs;
198   *newmap          = map;
199   PetscFunctionReturn(PETSC_SUCCESS);
200 }
201 
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.
205 
206   Collective
207 
208   Input Parameter:
209 . map - pointer to the map
210 
211   Level: developer
212 
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
222 
223   If range exists, and local size is not set, everything gets computed from the range.
224 
225   If the local size, global size are already set and range exists then this does nothing.
226 
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;
235 
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);
240 
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);
243 
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));
252 
253   map->range[0] = 0;
254   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p - 1];
255 
256   map->rstart = map->range[rank];
257   map->rend   = map->range[rank + 1];
258 
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 }
266 
267 /*@
268   PetscLayoutDuplicate - creates a new `PetscLayout` with the same information as a given one. If the `PetscLayout` already exists it is destroyed first.
269 
270   Collective
271 
272   Input Parameter:
273 . in - input `PetscLayout` to be duplicated
274 
275   Output Parameter:
276 . out - the copy
277 
278   Level: developer
279 
280   Note:
281   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
282 
283 .seealso: [PetscLayout](sec_matlayout), `PetscLayoutCreate()`, `PetscLayoutDestroy()`, `PetscLayoutSetUp()`, `PetscLayoutReference()`
284 @*/
285 PetscErrorCode PetscLayoutDuplicate(PetscLayout in, PetscLayout *out)
286 {
287   MPI_Comm comm = in->comm;
288 
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 }
300 
301 /*@
302   PetscLayoutReference - Causes a PETSc `Vec` or `Mat` to share a `PetscLayout` with one that already exists.
303 
304   Collective
305 
306   Input Parameter:
307 . in - input `PetscLayout` to be copied
308 
309   Output Parameter:
310 . out - the reference location
311 
312   Level: developer
313 
314   Notes:
315   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
316 
317   If the out location already contains a `PetscLayout` it is destroyed
318 
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 }
329 
330 /*@
331   PetscLayoutSetISLocalToGlobalMapping - sets a `ISLocalGlobalMapping` into a `PetscLayout`
332 
333   Collective
334 
335   Input Parameters:
336 + in   - input `PetscLayout`
337 - ltog - the local to global mapping
338 
339   Level: developer
340 
341   Notes:
342   `PetscLayoutSetUp()` does not need to be called on the resulting `PetscLayout`
343 
344   If the `PetscLayout` already contains a `ISLocalGlobalMapping` it is destroyed
345 
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;
353 
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 }
362 
363 /*@
364   PetscLayoutSetLocalSize - Sets the local size for a `PetscLayout` object.
365 
366   Collective
367 
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()`
371 
372   Level: developer
373 
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 }
384 
385 /*@
386   PetscLayoutGetLocalSize - Gets the local size for a `PetscLayout` object.
387 
388   Not Collective
389 
390   Input Parameter:
391 . map - pointer to the map
392 
393   Output Parameter:
394 . n - the local size
395 
396   Level: developer
397 
398   Note:
399   Call this after the call to `PetscLayoutSetUp()`
400 
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 }
410 
411 /*@
412   PetscLayoutSetSize - Sets the global size for a `PetscLayout` object.
413 
414   Logically Collective
415 
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()`
419 
420   Level: developer
421 
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 }
431 
432 /*@
433   PetscLayoutGetSize - Gets the global size for a `PetscLayout` object.
434 
435   Not Collective
436 
437   Input Parameter:
438 . map - pointer to the map
439 
440   Output Parameter:
441 . n - the global size
442 
443   Level: developer
444 
445   Note:
446   Call this after the call to `PetscLayoutSetUp()`
447 
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 }
457 
458 /*@
459   PetscLayoutSetBlockSize - Sets the block size for a `PetscLayout` object.
460 
461   Logically Collective
462 
463   Input Parameters:
464 + map - pointer to the map
465 - bs  - the size
466 
467   Level: developer
468 
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;
479 
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 }
486 
487 /*@
488   PetscLayoutGetBlockSize - Gets the block size for a `PetscLayout` object.
489 
490   Not Collective
491 
492   Input Parameter:
493 . map - pointer to the map
494 
495   Output Parameter:
496 . bs - the size
497 
498   Level: developer
499 
500   Notes:
501   Call this after the call to `PetscLayoutSetUp()`
502 
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 }
512 
513 /*@
514   PetscLayoutGetRange - gets the range of values owned by this process
515 
516   Not Collective
517 
518   Input Parameter:
519 . map - pointer to the map
520 
521   Output Parameters:
522 + rstart - first index owned by this process
523 - rend   - one more than the last index owned by this process
524 
525   Level: developer
526 
527   Note:
528   Call this after the call to `PetscLayoutSetUp()`
529 
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 }
540 
541 /*@C
542   PetscLayoutGetRanges - gets the ranges of values owned by all processes
543 
544   Not Collective
545 
546   Input Parameter:
547 . map - pointer to the map
548 
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`
553 
554   Level: developer
555 
556   Note:
557   Call this after the call to `PetscLayoutSetUp()`
558 
559   Fortran Notes:
560 .vb
561   PetscInt, pointer :: range(:)
562 .ve
563 
564   Call `PetscLayoutRestoreRanges()` when no longer needed.
565 
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 }
575 
576 /*@
577   PetscLayoutCompare - Compares two layouts
578 
579   Not Collective
580 
581   Input Parameters:
582 + mapa - pointer to the first map
583 - mapb - pointer to the second map
584 
585   Output Parameter:
586 . congruent - `PETSC_TRUE` if the two layouts are congruent, `PETSC_FALSE` otherwise
587 
588   Level: beginner
589 
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 }
600 
601 /*@
602   PetscLayoutFindOwner - Find the owning MPI process for a global index
603 
604   Not Collective; No Fortran Support
605 
606   Input Parameters:
607 + map - the layout
608 - idx - global index to find the owner of
609 
610   Output Parameter:
611 . owner - the owning rank
612 
613   Level: developer
614 
615 .seealso: `PetscLayout`, `PetscLayoutFindOwnerIndex()`
616 @*/
617 PetscErrorCode PetscLayoutFindOwner(PetscLayout map, PetscInt idx, PetscMPIInt *owner)
618 {
619   PetscMPIInt lo = 0, hi, t;
620 
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 }
634 
635 /*@
636   PetscLayoutFindOwnerIndex - Find the owning MPI process and the local index on that process for a global index
637 
638   Not Collective; No Fortran Support
639 
640   Input Parameters:
641 + map - the layout
642 - idx - global index to find the owner of
643 
644   Output Parameters:
645 + owner - the owning rank
646 - lidx  - local index used by the owner for `idx`
647 
648   Level: developer
649 
650 .seealso: `PetscLayout`, `PetscLayoutFindOwner()`
651 @*/
652 PetscErrorCode PetscLayoutFindOwnerIndex(PetscLayout map, PetscInt idx, PetscMPIInt *owner, PetscInt *lidx)
653 {
654   PetscMPIInt lo = 0, hi, t;
655 
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 }
669