Date: 2022-03-04T17:37:39+00:00

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 Parameters:
    352: + in - input PetscLayout
    353: - ltog - the local to global mapping

    355:   Level: developer

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

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

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

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

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

    381:   Collective on PetscLayout

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

    387:   Level: developer

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

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

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

    406:     Not Collective

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

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

    414:    Level: developer

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

    419:     Fortran Notes:
    420:       Not available from Fortran

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

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

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

    436:   Logically Collective on PetscLayout

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

    442:   Level: developer

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

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

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

    460:   Not Collective

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

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

    468:   Level: developer

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

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

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

    486:   Logically Collective on PetscLayout

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

    492:   Level: developer

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

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

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

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

    521:   Not Collective

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

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

    529:   Level: developer

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

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

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

    547:   Not Collective

    549:   Input Parameter:
    550: . map - pointer to the map

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

    556:   Level: developer

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

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

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

    575:     Not Collective

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

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

    584:    Level: developer

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

    589:     Fortran Notes:
    590:       Not available from Fortran

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

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

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

    606:   Not Collective

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

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

    615:   Level: beginner

    617:   Notes:

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

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