xref: /petsc/src/vec/is/utils/pmap.c (revision c2eed0ed062e48e2d9826290b0e8567e0dcff684)
1 
2 /*
3    This file contains routines for basic map object implementation.
4 */
5 
6 #include <petscis.h> /*I "petscis.h" I*/
7 #include <petscsf.h>
8 #include <petsc/private/isimpl.h>
9 
10 /*@
11   PetscLayoutCreate - Allocates PetscLayout space and sets the PetscLayout contents to the default.
12 
13   Collective
14 
15   Input Parameters:
16 . comm - the MPI communicator
17 
18   Output Parameters:
19 . map - the new PetscLayout
20 
21   Level: advanced
22 
23   Notes:
24   Typical calling sequence
25 .vb
26        PetscLayoutCreate(MPI_Comm,PetscLayout *);
27        PetscLayoutSetBlockSize(PetscLayout,bs);
28        PetscLayoutSetSize(PetscLayout,N); // or PetscLayoutSetLocalSize(PetscLayout,n);
29        PetscLayoutSetUp(PetscLayout);
30 .ve
31   Alternatively,
32 $      PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
33 
34   Optionally use any of the following:
35 
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 
42   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementions; it is often not needed in
43   user codes unless you really gain something in their use.
44 
45 .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
46           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(),
47           PetscLayoutCreateFromSizes()
48 
49 @*/
50 PetscErrorCode PetscLayoutCreate(MPI_Comm comm,PetscLayout *map)
51 {
52   PetscErrorCode ierr;
53 
54   PetscFunctionBegin;
55   ierr = PetscNew(map);CHKERRQ(ierr);
56   ierr = MPI_Comm_size(comm, &(*map)->size);CHKERRQ(ierr);
57   (*map)->comm        = comm;
58   (*map)->bs          = -1;
59   (*map)->n           = -1;
60   (*map)->N           = -1;
61   (*map)->range       = NULL;
62   (*map)->range_alloc = PETSC_TRUE;
63   (*map)->rstart      = 0;
64   (*map)->rend        = 0;
65   (*map)->setupcalled = PETSC_FALSE;
66   (*map)->oldn        = -1;
67   (*map)->oldN        = -1;
68   (*map)->oldbs       = -1;
69   PetscFunctionReturn(0);
70 }
71 
72 /*@
73   PetscLayoutCreateFromSizes - Allocates PetscLayout space, sets the layout sizes, and sets the layout up.
74 
75   Collective
76 
77   Input Parameters:
78 + comm  - the MPI communicator
79 . n     - the local size (or PETSC_DECIDE)
80 . N     - the global size (or PETSC_DECIDE)
81 - bs    - the block size (or PETSC_DECIDE)
82 
83   Output Parameters:
84 . map - the new PetscLayout
85 
86   Level: advanced
87 
88   Notes:
89 $ PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
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: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
100           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(), PetscLayoutCreateFromRanges()
101 
102 @*/
103 PetscErrorCode PetscLayoutCreateFromSizes(MPI_Comm comm,PetscInt n,PetscInt N,PetscInt bs,PetscLayout *map)
104 {
105   PetscErrorCode ierr;
106 
107   PetscFunctionBegin;
108   ierr = PetscLayoutCreate(comm, map);CHKERRQ(ierr);
109   ierr = PetscLayoutSetLocalSize(*map, n);CHKERRQ(ierr);
110   ierr = PetscLayoutSetSize(*map, N);CHKERRQ(ierr);
111   ierr = PetscLayoutSetBlockSize(*map, bs);CHKERRQ(ierr);
112   ierr = PetscLayoutSetUp(*map);CHKERRQ(ierr);
113   PetscFunctionReturn(0);
114 }
115 
116 /*@
117   PetscLayoutDestroy - Frees a map object and frees its range if that exists.
118 
119   Collective
120 
121   Input Parameters:
122 . map - the PetscLayout
123 
124   Level: developer
125 
126   Note:
127   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementions; it is
128   recommended they not be used in user codes unless you really gain something in their use.
129 
130 .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutCreate(),
131           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp()
132 
133 @*/
134 PetscErrorCode PetscLayoutDestroy(PetscLayout *map)
135 {
136   PetscErrorCode ierr;
137 
138   PetscFunctionBegin;
139   if (!*map) PetscFunctionReturn(0);
140   if (!(*map)->refcnt--) {
141     if ((*map)->range_alloc) {ierr = PetscFree((*map)->range);CHKERRQ(ierr);}
142     ierr = ISLocalToGlobalMappingDestroy(&(*map)->mapping);CHKERRQ(ierr);
143     ierr = PetscFree((*map));CHKERRQ(ierr);
144   }
145   *map = NULL;
146   PetscFunctionReturn(0);
147 }
148 
149 /*@
150   PetscLayoutCreateFromRanges - Creates a new PetscLayout with the given ownership ranges and sets it up.
151 
152   Collective
153 
154   Input Parameters:
155 + comm  - the MPI communicator
156 . range - the array of ownership ranges for each rank with length commsize+1
157 . mode  - the copy mode for range
158 - bs    - the block size (or PETSC_DECIDE)
159 
160   Output Parameters:
161 . newmap - the new PetscLayout
162 
163   Level: developer
164 
165 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
166           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(), PetscLayoutCreateFromSizes()
167 
168 @*/
169 PetscErrorCode PetscLayoutCreateFromRanges(MPI_Comm comm,const PetscInt range[],PetscCopyMode mode,PetscInt bs,PetscLayout *newmap)
170 {
171   PetscLayout    map;
172   PetscMPIInt    rank;
173   PetscErrorCode ierr;
174 
175   PetscFunctionBegin;
176   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
177   ierr = PetscLayoutCreate(comm, &map);CHKERRQ(ierr);
178   ierr = PetscLayoutSetBlockSize(map, bs);CHKERRQ(ierr);
179   switch (mode) {
180     case PETSC_COPY_VALUES:
181       ierr = PetscMalloc1(map->size+1, &map->range);CHKERRQ(ierr);
182       ierr = PetscArraycpy(map->range, range, map->size+1);CHKERRQ(ierr);
183       break;
184     case PETSC_USE_POINTER:
185       map->range_alloc = PETSC_FALSE;
186     default:
187       map->range = (PetscInt*) range;
188       break;
189   }
190   map->rstart = map->range[rank];
191   map->rend   = map->range[rank+1];
192   map->n      = map->rend - map->rstart;
193   map->N      = map->range[map->size];
194   if (PetscDefined(USE_DEBUG)) {  /* just check that n, N and bs are consistent */
195     PetscInt tmp;
196     ierr = MPIU_Allreduce(&map->n,&tmp,1,MPIU_INT,MPI_SUM,map->comm);CHKERRQ(ierr);
197     if (tmp != map->N) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Sum of local lengths %D does not equal global length %D, my local length %D.\nThe provided PetscLayout is wrong.",tmp,map->N,map->n);
198     if (map->bs > 1) {
199       if (map->n % map->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Local size %D must be divisible by blocksize %D",map->n,map->bs);
200     }
201     if (map->bs > 1) {
202       if (map->N % map->bs) SETERRQ2(map->comm,PETSC_ERR_PLIB,"Global size %D must be divisible by blocksize %D",map->N,map->bs);
203     }
204   }
205   /* lock the layout */
206   map->setupcalled = PETSC_TRUE;
207   map->oldn = map->n;
208   map->oldN = map->N;
209   map->oldbs = map->bs;
210   *newmap = map;
211   PetscFunctionReturn(0);
212 }
213 
214 /*@
215   PetscLayoutSetUp - given a map where you have set either the global or local
216                      size sets up the map so that it may be used.
217 
218   Collective
219 
220   Input Parameters:
221 . map - pointer to the map
222 
223   Level: developer
224 
225   Notes:
226     Typical calling sequence
227 $ PetscLayoutCreate(MPI_Comm,PetscLayout *);
228 $ PetscLayoutSetBlockSize(PetscLayout,1);
229 $ PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both
230 $ PetscLayoutSetUp(PetscLayout);
231 $ PetscLayoutGetSize(PetscLayout,PetscInt *);
232 
233   If range exists, and local size is not set, everything gets computed from the range.
234 
235   If the local size, global size are already set and range exists then this does nothing.
236 
237 .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
238           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutCreate()
239 @*/
240 PetscErrorCode PetscLayoutSetUp(PetscLayout map)
241 {
242   PetscMPIInt    rank;
243   PetscInt       p;
244   PetscErrorCode ierr;
245 
246   PetscFunctionBegin;
247   if (map->setupcalled && (map->n != map->oldn || map->N != map->oldN)) SETERRQ4(map->comm,PETSC_ERR_ARG_WRONGSTATE,"Layout is already setup with (local=%D,global=%D), cannot call setup again with (local=%D,global=%D)", map->oldn, map->oldN, map->n, map->N);
248   if (map->setupcalled) PetscFunctionReturn(0);
249 
250   if (map->n > 0 && map->bs > 1) {
251     if (map->n % map->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Local size %D must be divisible by blocksize %D",map->n,map->bs);
252   }
253   if (map->N > 0 && map->bs > 1) {
254     if (map->N % map->bs) SETERRQ2(map->comm,PETSC_ERR_PLIB,"Global size %D must be divisible by blocksize %D",map->N,map->bs);
255   }
256 
257   ierr = MPI_Comm_rank(map->comm, &rank);CHKERRMPI(ierr);
258   if (map->n > 0) map->n = map->n/PetscAbs(map->bs);
259   if (map->N > 0) map->N = map->N/PetscAbs(map->bs);
260   ierr = PetscSplitOwnership(map->comm,&map->n,&map->N);CHKERRQ(ierr);
261   map->n = map->n*PetscAbs(map->bs);
262   map->N = map->N*PetscAbs(map->bs);
263   if (!map->range) {
264     ierr = PetscMalloc1(map->size+1, &map->range);CHKERRQ(ierr);
265   }
266   ierr = MPI_Allgather(&map->n, 1, MPIU_INT, map->range+1, 1, MPIU_INT, map->comm);CHKERRMPI(ierr);
267 
268   map->range[0] = 0;
269   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p-1];
270 
271   map->rstart = map->range[rank];
272   map->rend   = map->range[rank+1];
273 
274   /* lock the layout */
275   map->setupcalled = PETSC_TRUE;
276   map->oldn = map->n;
277   map->oldN = map->N;
278   map->oldbs = map->bs;
279   PetscFunctionReturn(0);
280 }
281 
282 /*@
283   PetscLayoutDuplicate - creates a new PetscLayout with the same information as a given one. If the PetscLayout already exists it is destroyed first.
284 
285   Collective on PetscLayout
286 
287   Input Parameter:
288 . in - input PetscLayout to be duplicated
289 
290   Output Parameter:
291 . out - the copy
292 
293   Level: developer
294 
295   Notes:
296     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
297 
298 .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutReference()
299 @*/
300 PetscErrorCode PetscLayoutDuplicate(PetscLayout in,PetscLayout *out)
301 {
302   PetscErrorCode ierr;
303   MPI_Comm       comm = in->comm;
304 
305   PetscFunctionBegin;
306   ierr = PetscLayoutDestroy(out);CHKERRQ(ierr);
307   ierr = PetscLayoutCreate(comm,out);CHKERRQ(ierr);
308   ierr = PetscMemcpy(*out,in,sizeof(struct _n_PetscLayout));CHKERRQ(ierr);
309   if (in->range) {
310     ierr = PetscMalloc1((*out)->size+1,&(*out)->range);CHKERRQ(ierr);
311     ierr = PetscArraycpy((*out)->range,in->range,(*out)->size+1);CHKERRQ(ierr);
312   }
313   (*out)->refcnt = 0;
314   PetscFunctionReturn(0);
315 }
316 
317 /*@
318   PetscLayoutReference - Causes a PETSc Vec or Mat to share a PetscLayout with one that already exists. Used by Vec/MatDuplicate_XXX()
319 
320   Collective on PetscLayout
321 
322   Input Parameter:
323 . in - input PetscLayout to be copied
324 
325   Output Parameter:
326 . out - the reference location
327 
328   Level: developer
329 
330   Notes:
331     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
332 
333   If the out location already contains a PetscLayout it is destroyed
334 
335 .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutDuplicate()
336 @*/
337 PetscErrorCode PetscLayoutReference(PetscLayout in,PetscLayout *out)
338 {
339   PetscErrorCode ierr;
340 
341   PetscFunctionBegin;
342   in->refcnt++;
343   ierr = PetscLayoutDestroy(out);CHKERRQ(ierr);
344   *out = in;
345   PetscFunctionReturn(0);
346 }
347 
348 /*@
349   PetscLayoutSetISLocalToGlobalMapping - sets a ISLocalGlobalMapping into a PetscLayout
350 
351   Collective on PetscLayout
352 
353   Input Parameter:
354 + in - input PetscLayout
355 - ltog - the local to global mapping
356 
357 
358   Level: developer
359 
360   Notes:
361     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout
362 
363   If the ltog location already contains a PetscLayout it is destroyed
364 
365 .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutDuplicate()
366 @*/
367 PetscErrorCode PetscLayoutSetISLocalToGlobalMapping(PetscLayout in,ISLocalToGlobalMapping ltog)
368 {
369   PetscErrorCode ierr;
370   PetscInt       bs;
371 
372   PetscFunctionBegin;
373   ierr = ISLocalToGlobalMappingGetBlockSize(ltog,&bs);CHKERRQ(ierr);
374   if (in->bs > 0 && (bs != 1) && in->bs != bs) SETERRQ2(in->comm,PETSC_ERR_PLIB,"Blocksize of layout %D must match that of mapping %D (or the latter must be 1)",in->bs,bs);
375   ierr = PetscObjectReference((PetscObject)ltog);CHKERRQ(ierr);
376   ierr = ISLocalToGlobalMappingDestroy(&in->mapping);CHKERRQ(ierr);
377   in->mapping = ltog;
378   PetscFunctionReturn(0);
379 }
380 
381 /*@
382   PetscLayoutSetLocalSize - Sets the local size for a PetscLayout object.
383 
384   Collective on PetscLayout
385 
386   Input Parameters:
387 + map - pointer to the map
388 - n - the local size
389 
390   Level: developer
391 
392   Notes:
393   Call this after the call to PetscLayoutCreate()
394 
395 .seealso: PetscLayoutCreate(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayoutSetUp()
396           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
397 @*/
398 PetscErrorCode PetscLayoutSetLocalSize(PetscLayout map,PetscInt n)
399 {
400   PetscFunctionBegin;
401   if (map->bs > 1 && n % map->bs) SETERRQ2(map->comm,PETSC_ERR_ARG_INCOMP,"Local size %D not compatible with block size %D",n,map->bs);
402   map->n = n;
403   PetscFunctionReturn(0);
404 }
405 
406 /*@C
407      PetscLayoutGetLocalSize - Gets the local size for a PetscLayout object.
408 
409     Not Collective
410 
411    Input Parameters:
412 .    map - pointer to the map
413 
414    Output Parameters:
415 .    n - the local size
416 
417    Level: developer
418 
419     Notes:
420        Call this after the call to PetscLayoutSetUp()
421 
422     Fortran Notes:
423       Not available from Fortran
424 
425 .seealso: PetscLayoutCreate(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayoutSetUp()
426           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
427 
428 @*/
429 PetscErrorCode  PetscLayoutGetLocalSize(PetscLayout map,PetscInt *n)
430 {
431   PetscFunctionBegin;
432   *n = map->n;
433   PetscFunctionReturn(0);
434 }
435 
436 /*@
437   PetscLayoutSetSize - Sets the global size for a PetscLayout object.
438 
439   Logically Collective on PetscLayout
440 
441   Input Parameters:
442 + map - pointer to the map
443 - n - the global size
444 
445   Level: developer
446 
447   Notes:
448   Call this after the call to PetscLayoutCreate()
449 
450 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
451           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
452 @*/
453 PetscErrorCode PetscLayoutSetSize(PetscLayout map,PetscInt n)
454 {
455   PetscFunctionBegin;
456   map->N = n;
457   PetscFunctionReturn(0);
458 }
459 
460 /*@
461   PetscLayoutGetSize - Gets the global size for a PetscLayout object.
462 
463   Not Collective
464 
465   Input Parameters:
466 . map - pointer to the map
467 
468   Output Parameters:
469 . n - the global size
470 
471   Level: developer
472 
473   Notes:
474   Call this after the call to PetscLayoutSetUp()
475 
476 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(), PetscLayoutSetUp()
477           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
478 @*/
479 PetscErrorCode PetscLayoutGetSize(PetscLayout map,PetscInt *n)
480 {
481   PetscFunctionBegin;
482   *n = map->N;
483   PetscFunctionReturn(0);
484 }
485 
486 /*@
487   PetscLayoutSetBlockSize - Sets the block size for a PetscLayout object.
488 
489   Logically Collective on PetscLayout
490 
491   Input Parameters:
492 + map - pointer to the map
493 - bs - the size
494 
495   Level: developer
496 
497   Notes:
498   Call this after the call to PetscLayoutCreate()
499 
500 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetBlockSize(),
501           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
502 @*/
503 PetscErrorCode PetscLayoutSetBlockSize(PetscLayout map,PetscInt bs)
504 {
505   PetscFunctionBegin;
506   if (bs < 0) PetscFunctionReturn(0);
507   if (map->n > 0 && map->n % bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local size %D not compatible with block size %D",map->n,bs);
508   if (map->mapping) {
509     PetscInt       obs;
510     PetscErrorCode ierr;
511 
512     ierr = ISLocalToGlobalMappingGetBlockSize(map->mapping,&obs);CHKERRQ(ierr);
513     if (obs > 1) {
514       ierr = ISLocalToGlobalMappingSetBlockSize(map->mapping,bs);CHKERRQ(ierr);
515     }
516   }
517   map->bs = bs;
518   PetscFunctionReturn(0);
519 }
520 
521 /*@
522   PetscLayoutGetBlockSize - Gets the block size for a PetscLayout object.
523 
524   Not Collective
525 
526   Input Parameters:
527 . map - pointer to the map
528 
529   Output Parameters:
530 . bs - the size
531 
532   Level: developer
533 
534   Notes:
535   Call this after the call to PetscLayoutSetUp()
536 
537 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(), PetscLayoutSetUp()
538           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetSize()
539 @*/
540 PetscErrorCode PetscLayoutGetBlockSize(PetscLayout map,PetscInt *bs)
541 {
542   PetscFunctionBegin;
543   *bs = PetscAbs(map->bs);
544   PetscFunctionReturn(0);
545 }
546 
547 /*@
548   PetscLayoutGetRange - gets the range of values owned by this process
549 
550   Not Collective
551 
552   Input Parameters:
553 . map - pointer to the map
554 
555   Output Parameters:
556 + rstart - first index owned by this process
557 - rend   - one more than the last index owned by this process
558 
559   Level: developer
560 
561   Notes:
562   Call this after the call to PetscLayoutSetUp()
563 
564 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(),
565           PetscLayoutGetSize(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
566 @*/
567 PetscErrorCode PetscLayoutGetRange(PetscLayout map,PetscInt *rstart,PetscInt *rend)
568 {
569   PetscFunctionBegin;
570   if (rstart) *rstart = map->rstart;
571   if (rend)   *rend   = map->rend;
572   PetscFunctionReturn(0);
573 }
574 
575 /*@C
576      PetscLayoutGetRanges - gets the range of values owned by all processes
577 
578     Not Collective
579 
580    Input Parameters:
581 .    map - pointer to the map
582 
583    Output Parameters:
584 .    range - start of each processors range of indices (the final entry is one more then the
585              last index on the last process)
586 
587    Level: developer
588 
589     Notes:
590        Call this after the call to PetscLayoutSetUp()
591 
592     Fortran Notes:
593       Not available from Fortran
594 
595 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(),
596           PetscLayoutGetSize(), PetscLayoutGetRange(), PetscLayoutSetBlockSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
597 
598 @*/
599 PetscErrorCode  PetscLayoutGetRanges(PetscLayout map,const PetscInt *range[])
600 {
601   PetscFunctionBegin;
602   *range = map->range;
603   PetscFunctionReturn(0);
604 }
605 
606 /*@C
607    PetscLayoutsCreateSF - Creates a parallel star forest mapping two PetscLayout objects
608 
609    Collective
610 
611    Input Arguments:
612 +  rmap - PetscLayout defining the global root space
613 -  lmap - PetscLayout defining the global leaf space
614 
615    Output Arguments:
616 .  sf - The parallel star forest
617 
618    Level: intermediate
619 
620 .seealso: PetscSFCreate(), PetscLayoutCreate(), PetscSFSetGraphLayout()
621 @*/
622 PetscErrorCode PetscLayoutsCreateSF(PetscLayout rmap, PetscLayout lmap, PetscSF* sf)
623 {
624   PetscErrorCode ierr;
625   PetscInt       i,nroots,nleaves = 0;
626   PetscInt       rN, lst, len;
627   PetscMPIInt    owner = -1;
628   PetscSFNode    *remote;
629   MPI_Comm       rcomm = rmap->comm;
630   MPI_Comm       lcomm = lmap->comm;
631   PetscMPIInt    flg;
632 
633   PetscFunctionBegin;
634   PetscValidPointer(sf,3);
635   if (!rmap->setupcalled) SETERRQ(rcomm,PETSC_ERR_ARG_WRONGSTATE,"Root layout not setup");
636   if (!lmap->setupcalled) SETERRQ(lcomm,PETSC_ERR_ARG_WRONGSTATE,"Leaf layout not setup");
637   ierr = MPI_Comm_compare(rcomm,lcomm,&flg);CHKERRMPI(ierr);
638   if (flg != MPI_CONGRUENT && flg != MPI_IDENT) SETERRQ(rcomm,PETSC_ERR_SUP,"cannot map two layouts with non-matching communicators");
639   ierr = PetscSFCreate(rcomm,sf);CHKERRQ(ierr);
640   ierr = PetscLayoutGetLocalSize(rmap,&nroots);CHKERRQ(ierr);
641   ierr = PetscLayoutGetSize(rmap,&rN);CHKERRQ(ierr);
642   ierr = PetscLayoutGetRange(lmap,&lst,&len);CHKERRQ(ierr);
643   ierr = PetscMalloc1(len-lst,&remote);CHKERRQ(ierr);
644   for (i = lst; i < len && i < rN; i++) {
645     if (owner < -1 || i >= rmap->range[owner+1]) {
646       ierr = PetscLayoutFindOwner(rmap,i,&owner);CHKERRQ(ierr);
647     }
648     remote[nleaves].rank  = owner;
649     remote[nleaves].index = i - rmap->range[owner];
650     nleaves++;
651   }
652   ierr = PetscSFSetGraph(*sf,nroots,nleaves,NULL,PETSC_OWN_POINTER,remote,PETSC_COPY_VALUES);CHKERRQ(ierr);
653   ierr = PetscFree(remote);CHKERRQ(ierr);
654   PetscFunctionReturn(0);
655 }
656 
657 /*@
658   PetscLayoutCompare - Compares two layouts
659 
660   Not Collective
661 
662   Input Parameters:
663 + mapa - pointer to the first map
664 - mapb - pointer to the second map
665 
666   Output Parameters:
667 . congruent - PETSC_TRUE if the two layouts are congruent, PETSC_FALSE otherwise
668 
669   Level: beginner
670 
671   Notes:
672 
673 .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetBlockSize(),
674           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
675 @*/
676 PetscErrorCode PetscLayoutCompare(PetscLayout mapa,PetscLayout mapb,PetscBool *congruent)
677 {
678   PetscErrorCode ierr;
679 
680   PetscFunctionBegin;
681   *congruent = PETSC_FALSE;
682   if (mapa->N == mapb->N && mapa->range && mapb->range && mapa->size == mapb->size) {
683     ierr = PetscArraycmp(mapa->range,mapb->range,mapa->size+1,congruent);CHKERRQ(ierr);
684   }
685   PetscFunctionReturn(0);
686 }
687 
688 /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
689 PetscErrorCode PetscLayoutMapLocal(PetscLayout map,PetscInt N,const PetscInt idxs[], PetscInt *on,PetscInt **oidxs,PetscInt **ogidxs)
690 {
691   PetscInt      *owners = map->range;
692   PetscInt       n      = map->n;
693   PetscSF        sf;
694   PetscInt      *lidxs,*work = NULL;
695   PetscSFNode   *ridxs;
696   PetscMPIInt    rank, p = 0;
697   PetscInt       r, len = 0;
698   PetscErrorCode ierr;
699 
700   PetscFunctionBegin;
701   if (on) *on = 0;              /* squelch -Wmaybe-uninitialized */
702   /* Create SF where leaves are input idxs and roots are owned idxs */
703   ierr = MPI_Comm_rank(map->comm,&rank);CHKERRMPI(ierr);
704   ierr = PetscMalloc1(n,&lidxs);CHKERRQ(ierr);
705   for (r = 0; r < n; ++r) lidxs[r] = -1;
706   ierr = PetscMalloc1(N,&ridxs);CHKERRQ(ierr);
707   for (r = 0; r < N; ++r) {
708     const PetscInt idx = idxs[r];
709     if (idx < 0 || map->N <= idx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D out of range [0,%D)",idx,map->N);
710     if (idx < owners[p] || owners[p+1] <= idx) { /* short-circuit the search if the last p owns this idx too */
711       ierr = PetscLayoutFindOwner(map,idx,&p);CHKERRQ(ierr);
712     }
713     ridxs[r].rank = p;
714     ridxs[r].index = idxs[r] - owners[p];
715   }
716   ierr = PetscSFCreate(map->comm,&sf);CHKERRQ(ierr);
717   ierr = PetscSFSetGraph(sf,n,N,NULL,PETSC_OWN_POINTER,ridxs,PETSC_OWN_POINTER);CHKERRQ(ierr);
718   ierr = PetscSFReduceBegin(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
719   ierr = PetscSFReduceEnd(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR);CHKERRQ(ierr);
720   if (ogidxs) { /* communicate global idxs */
721     PetscInt cum = 0,start,*work2;
722 
723     ierr = PetscMalloc1(n,&work);CHKERRQ(ierr);
724     ierr = PetscCalloc1(N,&work2);CHKERRQ(ierr);
725     for (r = 0; r < N; ++r) if (idxs[r] >=0) cum++;
726     ierr = MPI_Scan(&cum,&start,1,MPIU_INT,MPI_SUM,map->comm);CHKERRMPI(ierr);
727     start -= cum;
728     cum = 0;
729     for (r = 0; r < N; ++r) if (idxs[r] >=0) work2[r] = start+cum++;
730     ierr = PetscSFReduceBegin(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
731     ierr = PetscSFReduceEnd(sf,MPIU_INT,work2,work,MPIU_REPLACE);CHKERRQ(ierr);
732     ierr = PetscFree(work2);CHKERRQ(ierr);
733   }
734   ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
735   /* Compress and put in indices */
736   for (r = 0; r < n; ++r)
737     if (lidxs[r] >= 0) {
738       if (work) work[len] = work[r];
739       lidxs[len++] = r;
740     }
741   if (on) *on = len;
742   if (oidxs) *oidxs = lidxs;
743   if (ogidxs) *ogidxs = work;
744   PetscFunctionReturn(0);
745 }
746