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