Actual source code: pmap.c

      2: /*
      3:    This file contains routines for basic map object implementation.
      4: */

      6: #include <petsc/private/isimpl.h>

      8: /*@
      9:   PetscLayoutCreate - Allocates PetscLayout space and sets the PetscLayout contents to the default.

     11:   Collective

     13:   Input Parameters:
     14: . comm - the MPI communicator

     16:   Output Parameters:
     17: . map - the new PetscLayout

     19:   Level: advanced

     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: $      PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);

     32:   Optionally use any of the following:

     34: + PetscLayoutGetSize(PetscLayout,PetscInt *);
     35: . PetscLayoutGetLocalSize(PetscLayout,PetscInt *);
     36: . PetscLayoutGetRange(PetscLayout,PetscInt *rstart,PetscInt *rend);
     37: . PetscLayoutGetRanges(PetscLayout,const PetscInt *range[]);
     38: - PetscLayoutDestroy(PetscLayout*);

     40:   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementions; it is often not needed in
     41:   user codes unless you really gain something in their use.

     43: .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
     44:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(),
     45:           PetscLayoutCreateFromSizes()

     47: @*/
     48: PetscErrorCode PetscLayoutCreate(MPI_Comm comm,PetscLayout *map)
     49: {

     53:   PetscNew(map);
     54:   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:   return(0);
     68: }

     70: /*@
     71:   PetscLayoutCreateFromSizes - Allocates PetscLayout space, sets the layout sizes, and sets the layout up.

     73:   Collective

     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)

     81:   Output Parameters:
     82: . map - the new PetscLayout

     84:   Level: advanced

     86:   Notes:
     87: $ PetscLayoutCreateFromSizes(comm,n,N,bs,&layout);
     88:   is a shorthand for
     89: .vb
     90:   PetscLayoutCreate(comm,&layout);
     91:   PetscLayoutSetLocalSize(layout,n);
     92:   PetscLayoutSetSize(layout,N);
     93:   PetscLayoutSetBlockSize(layout,bs);
     94:   PetscLayoutSetUp(layout);
     95: .ve

     97: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
     98:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(), PetscLayoutCreateFromRanges()

    100: @*/
    101: PetscErrorCode PetscLayoutCreateFromSizes(MPI_Comm comm,PetscInt n,PetscInt N,PetscInt bs,PetscLayout *map)
    102: {

    106:   PetscLayoutCreate(comm, map);
    107:   PetscLayoutSetLocalSize(*map, n);
    108:   PetscLayoutSetSize(*map, N);
    109:   PetscLayoutSetBlockSize(*map, bs);
    110:   PetscLayoutSetUp(*map);
    111:   return(0);
    112: }

    114: /*@
    115:   PetscLayoutDestroy - Frees a map object and frees its range if that exists.

    117:   Collective

    119:   Input Parameters:
    120: . map - the PetscLayout

    122:   Level: developer

    124:   Note:
    125:   The PetscLayout object and methods are intended to be used in the PETSc Vec and Mat implementions; it is
    126:   recommended they not be used in user codes unless you really gain something in their use.

    128: .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutCreate(),
    129:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp()

    131: @*/
    132: PetscErrorCode PetscLayoutDestroy(PetscLayout *map)
    133: {

    137:   if (!*map) return(0);
    138:   if (!(*map)->refcnt--) {
    139:     if ((*map)->range_alloc) {PetscFree((*map)->range);}
    140:     ISLocalToGlobalMappingDestroy(&(*map)->mapping);
    141:     PetscFree((*map));
    142:   }
    143:   *map = NULL;
    144:   return(0);
    145: }

    147: /*@
    148:   PetscLayoutCreateFromRanges - Creates a new PetscLayout with the given ownership ranges and sets it up.

    150:   Collective

    152:   Input Parameters:
    153: + comm  - the MPI communicator
    154: . range - the array of ownership ranges for each rank with length commsize+1
    155: . mode  - the copy mode for range
    156: - bs    - the block size (or PETSC_DECIDE)

    158:   Output Parameters:
    159: . newmap - the new PetscLayout

    161:   Level: developer

    163: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
    164:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutSetUp(), PetscLayoutCreateFromSizes()

    166: @*/
    167: PetscErrorCode PetscLayoutCreateFromRanges(MPI_Comm comm,const PetscInt range[],PetscCopyMode mode,PetscInt bs,PetscLayout *newmap)
    168: {
    169:   PetscLayout    map;
    170:   PetscMPIInt    rank;

    174:   MPI_Comm_rank(comm, &rank);
    175:   PetscLayoutCreate(comm, &map);
    176:   PetscLayoutSetBlockSize(map, bs);
    177:   switch (mode) {
    178:     case PETSC_COPY_VALUES:
    179:       PetscMalloc1(map->size+1, &map->range);
    180:       PetscArraycpy(map->range, range, map->size+1);
    181:       break;
    182:     case PETSC_USE_POINTER:
    183:       map->range_alloc = PETSC_FALSE;
    184:     default:
    185:       map->range = (PetscInt*) range;
    186:       break;
    187:   }
    188:   map->rstart = map->range[rank];
    189:   map->rend   = map->range[rank+1];
    190:   map->n      = map->rend - map->rstart;
    191:   map->N      = map->range[map->size];
    192:   if (PetscDefined(USE_DEBUG)) {  /* just check that n, N and bs are consistent */
    193:     PetscInt tmp;
    194:     MPIU_Allreduce(&map->n,&tmp,1,MPIU_INT,MPI_SUM,map->comm);
    195:     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);
    196:     if (map->bs > 1) {
    197:       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);
    198:     }
    199:     if (map->bs > 1) {
    200:       if (map->N % map->bs) SETERRQ2(map->comm,PETSC_ERR_PLIB,"Global size %D must be divisible by blocksize %D",map->N,map->bs);
    201:     }
    202:   }
    203:   /* lock the layout */
    204:   map->setupcalled = PETSC_TRUE;
    205:   map->oldn = map->n;
    206:   map->oldN = map->N;
    207:   map->oldbs = map->bs;
    208:   *newmap = map;
    209:   return(0);
    210: }

    212: /*@
    213:   PetscLayoutSetUp - given a map where you have set either the global or local
    214:                      size sets up the map so that it may be used.

    216:   Collective

    218:   Input Parameters:
    219: . map - pointer to the map

    221:   Level: developer

    223:   Notes:
    224:     Typical calling sequence
    225: $ PetscLayoutCreate(MPI_Comm,PetscLayout *);
    226: $ PetscLayoutSetBlockSize(PetscLayout,1);
    227: $ PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N); or both
    228: $ PetscLayoutSetUp(PetscLayout);
    229: $ PetscLayoutGetSize(PetscLayout,PetscInt *);

    231:   If range exists, and local size is not set, everything gets computed from the range.

    233:   If the local size, global size are already set and range exists then this does nothing.

    235: .seealso: PetscLayoutSetLocalSize(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayout, PetscLayoutDestroy(),
    236:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize(), PetscLayoutCreate()
    237: @*/
    238: PetscErrorCode PetscLayoutSetUp(PetscLayout map)
    239: {
    240:   PetscMPIInt    rank;
    241:   PetscInt       p;

    245:   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);
    246:   if (map->setupcalled) return(0);

    248:   if (map->n > 0 && map->bs > 1) {
    249:     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);
    250:   }
    251:   if (map->N > 0 && map->bs > 1) {
    252:     if (map->N % map->bs) SETERRQ2(map->comm,PETSC_ERR_PLIB,"Global size %D must be divisible by blocksize %D",map->N,map->bs);
    253:   }

    255:   MPI_Comm_rank(map->comm, &rank);
    256:   if (map->n > 0) map->n = map->n/PetscAbs(map->bs);
    257:   if (map->N > 0) map->N = map->N/PetscAbs(map->bs);
    258:   PetscSplitOwnership(map->comm,&map->n,&map->N);
    259:   map->n = map->n*PetscAbs(map->bs);
    260:   map->N = map->N*PetscAbs(map->bs);
    261:   if (!map->range) {
    262:     PetscMalloc1(map->size+1, &map->range);
    263:   }
    264:   MPI_Allgather(&map->n, 1, MPIU_INT, map->range+1, 1, MPIU_INT, map->comm);

    266:   map->range[0] = 0;
    267:   for (p = 2; p <= map->size; p++) map->range[p] += map->range[p-1];

    269:   map->rstart = map->range[rank];
    270:   map->rend   = map->range[rank+1];

    272:   /* lock the layout */
    273:   map->setupcalled = PETSC_TRUE;
    274:   map->oldn = map->n;
    275:   map->oldN = map->N;
    276:   map->oldbs = map->bs;
    277:   return(0);
    278: }

    280: /*@
    281:   PetscLayoutDuplicate - creates a new PetscLayout with the same information as a given one. If the PetscLayout already exists it is destroyed first.

    283:   Collective on PetscLayout

    285:   Input Parameter:
    286: . in - input PetscLayout to be duplicated

    288:   Output Parameter:
    289: . out - the copy

    291:   Level: developer

    293:   Notes:
    294:     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout

    296: .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutReference()
    297: @*/
    298: PetscErrorCode PetscLayoutDuplicate(PetscLayout in,PetscLayout *out)
    299: {
    301:   MPI_Comm       comm = in->comm;

    304:   PetscLayoutDestroy(out);
    305:   PetscLayoutCreate(comm,out);
    306:   PetscMemcpy(*out,in,sizeof(struct _n_PetscLayout));
    307:   if (in->range) {
    308:     PetscMalloc1((*out)->size+1,&(*out)->range);
    309:     PetscArraycpy((*out)->range,in->range,(*out)->size+1);
    310:   }
    311:   (*out)->refcnt = 0;
    312:   return(0);
    313: }

    315: /*@
    316:   PetscLayoutReference - Causes a PETSc Vec or Mat to share a PetscLayout with one that already exists. Used by Vec/MatDuplicate_XXX()

    318:   Collective on PetscLayout

    320:   Input Parameter:
    321: . in - input PetscLayout to be copied

    323:   Output Parameter:
    324: . out - the reference location

    326:   Level: developer

    328:   Notes:
    329:     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout

    331:   If the out location already contains a PetscLayout it is destroyed

    333: .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutDuplicate()
    334: @*/
    335: PetscErrorCode PetscLayoutReference(PetscLayout in,PetscLayout *out)
    336: {

    340:   in->refcnt++;
    341:   PetscLayoutDestroy(out);
    342:   *out = in;
    343:   return(0);
    344: }

    346: /*@
    347:   PetscLayoutSetISLocalToGlobalMapping - sets a ISLocalGlobalMapping into a PetscLayout

    349:   Collective on PetscLayout

    351:   Input Parameter:
    352: + in - input PetscLayout
    353: - ltog - the local to global mapping

    356:   Level: developer

    358:   Notes:
    359:     PetscLayoutSetUp() does not need to be called on the resulting PetscLayout

    361:   If the ltog location already contains a PetscLayout it is destroyed

    363: .seealso: PetscLayoutCreate(), PetscLayoutDestroy(), PetscLayoutSetUp(), PetscLayoutDuplicate()
    364: @*/
    365: PetscErrorCode PetscLayoutSetISLocalToGlobalMapping(PetscLayout in,ISLocalToGlobalMapping ltog)
    366: {
    368:   PetscInt       bs;

    371:   ISLocalToGlobalMappingGetBlockSize(ltog,&bs);
    372:   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);
    373:   PetscObjectReference((PetscObject)ltog);
    374:   ISLocalToGlobalMappingDestroy(&in->mapping);
    375:   in->mapping = ltog;
    376:   return(0);
    377: }

    379: /*@
    380:   PetscLayoutSetLocalSize - Sets the local size for a PetscLayout object.

    382:   Collective on PetscLayout

    384:   Input Parameters:
    385: + map - pointer to the map
    386: - n - the local size

    388:   Level: developer

    390:   Notes:
    391:   Call this after the call to PetscLayoutCreate()

    393: .seealso: PetscLayoutCreate(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayoutSetUp()
    394:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
    395: @*/
    396: PetscErrorCode PetscLayoutSetLocalSize(PetscLayout map,PetscInt n)
    397: {
    399:   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);
    400:   map->n = n;
    401:   return(0);
    402: }

    404: /*@C
    405:      PetscLayoutGetLocalSize - Gets the local size for a PetscLayout object.

    407:     Not Collective

    409:    Input Parameters:
    410: .    map - pointer to the map

    412:    Output Parameters:
    413: .    n - the local size

    415:    Level: developer

    417:     Notes:
    418:        Call this after the call to PetscLayoutSetUp()

    420:     Fortran Notes:
    421:       Not available from Fortran

    423: .seealso: PetscLayoutCreate(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutGetLocalSize(), PetscLayoutSetUp()
    424:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()

    426: @*/
    427: PetscErrorCode  PetscLayoutGetLocalSize(PetscLayout map,PetscInt *n)
    428: {
    430:   *n = map->n;
    431:   return(0);
    432: }

    434: /*@
    435:   PetscLayoutSetSize - Sets the global size for a PetscLayout object.

    437:   Logically Collective on PetscLayout

    439:   Input Parameters:
    440: + map - pointer to the map
    441: - n - the global size

    443:   Level: developer

    445:   Notes:
    446:   Call this after the call to PetscLayoutCreate()

    448: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
    449:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
    450: @*/
    451: PetscErrorCode PetscLayoutSetSize(PetscLayout map,PetscInt n)
    452: {
    454:   map->N = n;
    455:   return(0);
    456: }

    458: /*@
    459:   PetscLayoutGetSize - Gets the global size for a PetscLayout object.

    461:   Not Collective

    463:   Input Parameters:
    464: . map - pointer to the map

    466:   Output Parameters:
    467: . n - the global size

    469:   Level: developer

    471:   Notes:
    472:   Call this after the call to PetscLayoutSetUp()

    474: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(), PetscLayoutSetUp()
    475:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetBlockSize()
    476: @*/
    477: PetscErrorCode PetscLayoutGetSize(PetscLayout map,PetscInt *n)
    478: {
    480:   *n = map->N;
    481:   return(0);
    482: }

    484: /*@
    485:   PetscLayoutSetBlockSize - Sets the block size for a PetscLayout object.

    487:   Logically Collective on PetscLayout

    489:   Input Parameters:
    490: + map - pointer to the map
    491: - bs - the size

    493:   Level: developer

    495:   Notes:
    496:   Call this after the call to PetscLayoutCreate()

    498: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetBlockSize(),
    499:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
    500: @*/
    501: PetscErrorCode PetscLayoutSetBlockSize(PetscLayout map,PetscInt bs)
    502: {
    504:   if (bs < 0) return(0);
    505:   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);
    506:   if (map->mapping) {
    507:     PetscInt       obs;

    510:     ISLocalToGlobalMappingGetBlockSize(map->mapping,&obs);
    511:     if (obs > 1) {
    512:       ISLocalToGlobalMappingSetBlockSize(map->mapping,bs);
    513:     }
    514:   }
    515:   map->bs = bs;
    516:   return(0);
    517: }

    519: /*@
    520:   PetscLayoutGetBlockSize - Gets the block size for a PetscLayout object.

    522:   Not Collective

    524:   Input Parameters:
    525: . map - pointer to the map

    527:   Output Parameters:
    528: . bs - the size

    530:   Level: developer

    532:   Notes:
    533:   Call this after the call to PetscLayoutSetUp()

    535: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(), PetscLayoutSetUp()
    536:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetSize()
    537: @*/
    538: PetscErrorCode PetscLayoutGetBlockSize(PetscLayout map,PetscInt *bs)
    539: {
    541:   *bs = PetscAbs(map->bs);
    542:   return(0);
    543: }

    545: /*@
    546:   PetscLayoutGetRange - gets the range of values owned by this process

    548:   Not Collective

    550:   Input Parameters:
    551: . map - pointer to the map

    553:   Output Parameters:
    554: + rstart - first index owned by this process
    555: - rend   - one more than the last index owned by this process

    557:   Level: developer

    559:   Notes:
    560:   Call this after the call to PetscLayoutSetUp()

    562: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(),
    563:           PetscLayoutGetSize(), PetscLayoutGetRanges(), PetscLayoutSetBlockSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
    564: @*/
    565: PetscErrorCode PetscLayoutGetRange(PetscLayout map,PetscInt *rstart,PetscInt *rend)
    566: {
    568:   if (rstart) *rstart = map->rstart;
    569:   if (rend)   *rend   = map->rend;
    570:   return(0);
    571: }

    573: /*@C
    574:      PetscLayoutGetRanges - gets the range of values owned by all processes

    576:     Not Collective

    578:    Input Parameters:
    579: .    map - pointer to the map

    581:    Output Parameters:
    582: .    range - start of each processors range of indices (the final entry is one more then the
    583:              last index on the last process)

    585:    Level: developer

    587:     Notes:
    588:        Call this after the call to PetscLayoutSetUp()

    590:     Fortran Notes:
    591:       Not available from Fortran

    593: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutSetSize(),
    594:           PetscLayoutGetSize(), PetscLayoutGetRange(), PetscLayoutSetBlockSize(), PetscLayoutGetSize(), PetscLayoutSetUp()

    596: @*/
    597: PetscErrorCode  PetscLayoutGetRanges(PetscLayout map,const PetscInt *range[])
    598: {
    600:   *range = map->range;
    601:   return(0);
    602: }

    604: /*@
    605:   PetscLayoutCompare - Compares two layouts

    607:   Not Collective

    609:   Input Parameters:
    610: + mapa - pointer to the first map
    611: - mapb - pointer to the second map

    613:   Output Parameters:
    614: . congruent - PETSC_TRUE if the two layouts are congruent, PETSC_FALSE otherwise

    616:   Level: beginner

    618:   Notes:

    620: .seealso: PetscLayoutCreate(), PetscLayoutSetLocalSize(), PetscLayoutGetLocalSize(), PetscLayoutGetBlockSize(),
    621:           PetscLayoutGetRange(), PetscLayoutGetRanges(), PetscLayoutSetSize(), PetscLayoutGetSize(), PetscLayoutSetUp()
    622: @*/
    623: PetscErrorCode PetscLayoutCompare(PetscLayout mapa,PetscLayout mapb,PetscBool *congruent)
    624: {

    628:   *congruent = PETSC_FALSE;
    629:   if (mapa->N == mapb->N && mapa->range && mapb->range && mapa->size == mapb->size) {
    630:     PetscArraycmp(mapa->range,mapb->range,mapa->size+1,congruent);
    631:   }
    632:   return(0);
    633: }