Actual source code: isltog.c


  2: #include <petsc/private/isimpl.h>
  3: #include <petsc/private/hashmapi.h>
  4: #include <petscsf.h>
  5: #include <petscviewer.h>

  7: PetscClassId          IS_LTOGM_CLASSID;
  8: static PetscErrorCode ISLocalToGlobalMappingGetBlockInfo_Private(ISLocalToGlobalMapping, PetscInt *, PetscInt **, PetscInt **, PetscInt ***);

 10: typedef struct {
 11:   PetscInt *globals;
 12: } ISLocalToGlobalMapping_Basic;

 14: typedef struct {
 15:   PetscHMapI globalht;
 16: } ISLocalToGlobalMapping_Hash;

 18: /*@C
 19:   ISGetPointRange - Returns a description of the points in an IS suitable for traversal

 21:   Not collective

 23:   Input Parameter:
 24: . pointIS - The IS object

 26:   Output Parameters:
 27: + pStart - The first index, see notes
 28: . pEnd   - One past the last index, see notes
 29: - points - The indices, see notes

 31:   Notes:
 32:   If the IS contains contiguous indices in an ISSTRIDE, then the indices are contained in [pStart, pEnd) and points = NULL. Otherwise, pStart = 0, pEnd = numIndices, and points is an array of the indices. This supports the following pattern
 33: $ ISGetPointRange(is, &pStart, &pEnd, &points);
 34: $ for (p = pStart; p < pEnd; ++p) {
 35: $   const PetscInt point = points ? points[p] : p;
 36: $ }
 37: $ ISRestorePointRange(is, &pstart, &pEnd, &points);

 39:   Level: intermediate

 41: .seealso: `ISRestorePointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()`
 42: @*/
 43: PetscErrorCode ISGetPointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt **points)
 44: {
 45:   PetscInt  numCells, step = 1;
 46:   PetscBool isStride;

 49:   *pStart = 0;
 50:   *points = NULL;
 51:   ISGetLocalSize(pointIS, &numCells);
 52:   PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride);
 53:   if (isStride) ISStrideGetInfo(pointIS, pStart, &step);
 54:   *pEnd = *pStart + numCells;
 55:   if (!isStride || step != 1) ISGetIndices(pointIS, points);
 56:   return 0;
 57: }

 59: /*@C
 60:   ISRestorePointRange - Destroys the traversal description

 62:   Not collective

 64:   Input Parameters:
 65: + pointIS - The IS object
 66: . pStart  - The first index, from ISGetPointRange()
 67: . pEnd    - One past the last index, from ISGetPointRange()
 68: - points  - The indices, from ISGetPointRange()

 70:   Notes:
 71:   If the IS contains contiguous indices in an ISSTRIDE, then the indices are contained in [pStart, pEnd) and points = NULL. Otherwise, pStart = 0, pEnd = numIndices, and points is an array of the indices. This supports the following pattern
 72: $ ISGetPointRange(is, &pStart, &pEnd, &points);
 73: $ for (p = pStart; p < pEnd; ++p) {
 74: $   const PetscInt point = points ? points[p] : p;
 75: $ }
 76: $ ISRestorePointRange(is, &pstart, &pEnd, &points);

 78:   Level: intermediate

 80: .seealso: `ISGetPointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()`
 81: @*/
 82: PetscErrorCode ISRestorePointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt **points)
 83: {
 84:   PetscInt  step = 1;
 85:   PetscBool isStride;

 88:   PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride);
 89:   if (isStride) ISStrideGetInfo(pointIS, pStart, &step);
 90:   if (!isStride || step != 1) ISGetIndices(pointIS, points);
 91:   return 0;
 92: }

 94: /*@C
 95:   ISGetPointSubrange - Configures the input IS to be a subrange for the traversal information given

 97:   Not collective

 99:   Input Parameters:
100: + subpointIS - The IS object to be configured
101: . pStar   t  - The first index of the subrange
102: . pEnd       - One past the last index for the subrange
103: - points     - The indices for the entire range, from ISGetPointRange()

105:   Output Parameters:
106: . subpointIS - The IS object now configured to be a subrange

108:   Notes:
109:   The input IS will now respond properly to calls to ISGetPointRange() and return the subrange.

111:   Level: intermediate

113: .seealso: `ISGetPointRange()`, `ISRestorePointRange()`, `ISGetIndices()`, `ISCreateStride()`
114: @*/
115: PetscErrorCode ISGetPointSubrange(IS subpointIS, PetscInt pStart, PetscInt pEnd, const PetscInt *points)
116: {
118:   if (points) {
119:     ISSetType(subpointIS, ISGENERAL);
120:     ISGeneralSetIndices(subpointIS, pEnd - pStart, &points[pStart], PETSC_USE_POINTER);
121:   } else {
122:     ISSetType(subpointIS, ISSTRIDE);
123:     ISStrideSetStride(subpointIS, pEnd - pStart, pStart, 1);
124:   }
125:   return 0;
126: }

128: /* -----------------------------------------------------------------------------------------*/

130: /*
131:     Creates the global mapping information in the ISLocalToGlobalMapping structure

133:     If the user has not selected how to handle the global to local mapping then use HASH for "large" problems
134: */
135: static PetscErrorCode ISGlobalToLocalMappingSetUp(ISLocalToGlobalMapping mapping)
136: {
137:   PetscInt i, *idx = mapping->indices, n = mapping->n, end, start;

139:   if (mapping->data) return 0;
140:   end   = 0;
141:   start = PETSC_MAX_INT;

143:   for (i = 0; i < n; i++) {
144:     if (idx[i] < 0) continue;
145:     if (idx[i] < start) start = idx[i];
146:     if (idx[i] > end) end = idx[i];
147:   }
148:   if (start > end) {
149:     start = 0;
150:     end   = -1;
151:   }
152:   mapping->globalstart = start;
153:   mapping->globalend   = end;
154:   if (!((PetscObject)mapping)->type_name) {
155:     if ((end - start) > PetscMax(4 * n, 1000000)) {
156:       ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGHASH);
157:     } else {
158:       ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGBASIC);
159:     }
160:   }
161:   PetscTryTypeMethod(mapping, globaltolocalmappingsetup);
162:   return 0;
163: }

165: static PetscErrorCode ISGlobalToLocalMappingSetUp_Basic(ISLocalToGlobalMapping mapping)
166: {
167:   PetscInt                      i, *idx = mapping->indices, n = mapping->n, end, start, *globals;
168:   ISLocalToGlobalMapping_Basic *map;

170:   start = mapping->globalstart;
171:   end   = mapping->globalend;
172:   PetscNew(&map);
173:   PetscMalloc1(end - start + 2, &globals);
174:   map->globals = globals;
175:   for (i = 0; i < end - start + 1; i++) globals[i] = -1;
176:   for (i = 0; i < n; i++) {
177:     if (idx[i] < 0) continue;
178:     globals[idx[i] - start] = i;
179:   }
180:   mapping->data = (void *)map;
181:   return 0;
182: }

184: static PetscErrorCode ISGlobalToLocalMappingSetUp_Hash(ISLocalToGlobalMapping mapping)
185: {
186:   PetscInt                     i, *idx = mapping->indices, n = mapping->n;
187:   ISLocalToGlobalMapping_Hash *map;

189:   PetscNew(&map);
190:   PetscHMapICreate(&map->globalht);
191:   for (i = 0; i < n; i++) {
192:     if (idx[i] < 0) continue;
193:     PetscHMapISet(map->globalht, idx[i], i);
194:   }
195:   mapping->data = (void *)map;
196:   return 0;
197: }

199: static PetscErrorCode ISLocalToGlobalMappingDestroy_Basic(ISLocalToGlobalMapping mapping)
200: {
201:   ISLocalToGlobalMapping_Basic *map = (ISLocalToGlobalMapping_Basic *)mapping->data;

203:   if (!map) return 0;
204:   PetscFree(map->globals);
205:   PetscFree(mapping->data);
206:   return 0;
207: }

209: static PetscErrorCode ISLocalToGlobalMappingDestroy_Hash(ISLocalToGlobalMapping mapping)
210: {
211:   ISLocalToGlobalMapping_Hash *map = (ISLocalToGlobalMapping_Hash *)mapping->data;

213:   if (!map) return 0;
214:   PetscHMapIDestroy(&map->globalht);
215:   PetscFree(mapping->data);
216:   return 0;
217: }

219: #define GTOLTYPE _Basic
220: #define GTOLNAME _Basic
221: #define GTOLBS   mapping->bs
222: #define GTOL(g, local) \
223:   do { \
224:     local = map->globals[g / bs - start]; \
225:     if (local >= 0) local = bs * local + (g % bs); \
226:   } while (0)

228: #include <../src/vec/is/utils/isltog.h>

230: #define GTOLTYPE _Basic
231: #define GTOLNAME Block_Basic
232: #define GTOLBS   1
233: #define GTOL(g, local) \
234:   do { \
235:     local = map->globals[g - start]; \
236:   } while (0)
237: #include <../src/vec/is/utils/isltog.h>

239: #define GTOLTYPE _Hash
240: #define GTOLNAME _Hash
241: #define GTOLBS   mapping->bs
242: #define GTOL(g, local) \
243:   do { \
244:     (void)PetscHMapIGet(map->globalht, g / bs, &local); \
245:     if (local >= 0) local = bs * local + (g % bs); \
246:   } while (0)
247: #include <../src/vec/is/utils/isltog.h>

249: #define GTOLTYPE _Hash
250: #define GTOLNAME Block_Hash
251: #define GTOLBS   1
252: #define GTOL(g, local) \
253:   do { \
254:     (void)PetscHMapIGet(map->globalht, g, &local); \
255:   } while (0)
256: #include <../src/vec/is/utils/isltog.h>

258: /*@
259:     ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object

261:     Not Collective

263:     Input Parameter:
264: .   ltog - local to global mapping

266:     Output Parameter:
267: .   nltog - the duplicated local to global mapping

269:     Level: advanced

271: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
272: @*/
273: PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog)
274: {
275:   ISLocalToGlobalMappingType l2gtype;

278:   ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog);
279:   ISLocalToGlobalMappingGetType(ltog, &l2gtype);
280:   ISLocalToGlobalMappingSetType(*nltog, l2gtype);
281:   return 0;
282: }

284: /*@
285:     ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping

287:     Not Collective

289:     Input Parameter:
290: .   ltog - local to global mapping

292:     Output Parameter:
293: .   n - the number of entries in the local mapping, ISLocalToGlobalMappingGetIndices() returns an array of this length

295:     Level: advanced

297: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
298: @*/
299: PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n)
300: {
303:   *n = mapping->bs * mapping->n;
304:   return 0;
305: }

307: /*@C
308:    ISLocalToGlobalMappingViewFromOptions - View from Options

310:    Collective on ISLocalToGlobalMapping

312:    Input Parameters:
313: +  A - the local to global mapping object
314: .  obj - Optional object
315: -  name - command line option

317:    Level: intermediate
318: .seealso: `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()`
319: @*/
320: PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[])
321: {
323:   PetscObjectViewFromOptions((PetscObject)A, obj, name);
324:   return 0;
325: }

327: /*@C
328:     ISLocalToGlobalMappingView - View a local to global mapping

330:     Not Collective

332:     Input Parameters:
333: +   ltog - local to global mapping
334: -   viewer - viewer

336:     Level: advanced

338: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`
339: @*/
340: PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer)
341: {
342:   PetscInt    i;
343:   PetscMPIInt rank;
344:   PetscBool   iascii;

347:   if (!viewer) PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer);

350:   MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank);
351:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
352:   if (iascii) {
353:     PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer);
354:     PetscViewerASCIIPushSynchronized(viewer);
355:     for (i = 0; i < mapping->n; i++) PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, mapping->indices[i]);
356:     PetscViewerFlush(viewer);
357:     PetscViewerASCIIPopSynchronized(viewer);
358:   }
359:   return 0;
360: }

362: /*@
363:     ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
364:     ordering and a global parallel ordering.

366:     Not collective

368:     Input Parameter:
369: .   is - index set containing the global numbers for each local number

371:     Output Parameter:
372: .   mapping - new mapping data structure

374:     Notes:
375:     the block size of the IS determines the block size of the mapping
376:     Level: advanced

378: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()`
379: @*/
380: PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping)
381: {
382:   PetscInt        n, bs;
383:   const PetscInt *indices;
384:   MPI_Comm        comm;
385:   PetscBool       isblock;


390:   PetscObjectGetComm((PetscObject)is, &comm);
391:   ISGetLocalSize(is, &n);
392:   PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock);
393:   if (!isblock) {
394:     ISGetIndices(is, &indices);
395:     ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping);
396:     ISRestoreIndices(is, &indices);
397:   } else {
398:     ISGetBlockSize(is, &bs);
399:     ISBlockGetIndices(is, &indices);
400:     ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping);
401:     ISBlockRestoreIndices(is, &indices);
402:   }
403:   return 0;
404: }

406: /*@C
407:     ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n)
408:     ordering and a global parallel ordering.

410:     Collective

412:     Input Parameters:
413: +   sf - star forest mapping contiguous local indices to (rank, offset)
414: -   start - first global index on this process, or PETSC_DECIDE to compute contiguous global numbering automatically

416:     Output Parameter:
417: .   mapping - new mapping data structure

419:     Level: advanced

421:     Notes:
422:     If any processor calls this with start = PETSC_DECIDE then all processors must, otherwise the program will hang.

424: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`
425: @*/
426: PetscErrorCode ISLocalToGlobalMappingCreateSF(PetscSF sf, PetscInt start, ISLocalToGlobalMapping *mapping)
427: {
428:   PetscInt i, maxlocal, nroots, nleaves, *globals, *ltog;
429:   MPI_Comm comm;

433:   PetscObjectGetComm((PetscObject)sf, &comm);
434:   PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL);
435:   if (start == PETSC_DECIDE) {
436:     start = 0;
437:     MPI_Exscan(&nroots, &start, 1, MPIU_INT, MPI_SUM, comm);
439:   PetscSFGetLeafRange(sf, NULL, &maxlocal);
440:   ++maxlocal;
441:   PetscMalloc1(nroots, &globals);
442:   PetscMalloc1(maxlocal, &ltog);
443:   for (i = 0; i < nroots; i++) globals[i] = start + i;
444:   for (i = 0; i < maxlocal; i++) ltog[i] = -1;
445:   PetscSFBcastBegin(sf, MPIU_INT, globals, ltog, MPI_REPLACE);
446:   PetscSFBcastEnd(sf, MPIU_INT, globals, ltog, MPI_REPLACE);
447:   ISLocalToGlobalMappingCreate(comm, 1, maxlocal, ltog, PETSC_OWN_POINTER, mapping);
448:   PetscFree(globals);
449:   return 0;
450: }

452: /*@
453:     ISLocalToGlobalMappingSetBlockSize - Sets the blocksize of the mapping

455:     Not collective

457:     Input Parameters:
458: +   mapping - mapping data structure
459: -   bs - the blocksize

461:     Level: advanced

463: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`
464: @*/
465: PetscErrorCode ISLocalToGlobalMappingSetBlockSize(ISLocalToGlobalMapping mapping, PetscInt bs)
466: {
467:   PetscInt       *nid;
468:   const PetscInt *oid;
469:   PetscInt        i, cn, on, obs, nn;

473:   if (bs == mapping->bs) return 0;
474:   on  = mapping->n;
475:   obs = mapping->bs;
476:   oid = mapping->indices;
477:   nn  = (on * obs) / bs;

480:   PetscMalloc1(nn, &nid);
481:   ISLocalToGlobalMappingGetIndices(mapping, &oid);
482:   for (i = 0; i < nn; i++) {
483:     PetscInt j;
484:     for (j = 0, cn = 0; j < bs - 1; j++) {
485:       if (oid[i * bs + j] < 0) {
486:         cn++;
487:         continue;
488:       }
490:     }
491:     if (oid[i * bs + j] < 0) cn++;
492:     if (cn) {
494:       nid[i] = -1;
495:     } else {
496:       nid[i] = oid[i * bs] / bs;
497:     }
498:   }
499:   ISLocalToGlobalMappingRestoreIndices(mapping, &oid);

501:   mapping->n  = nn;
502:   mapping->bs = bs;
503:   PetscFree(mapping->indices);
504:   mapping->indices     = nid;
505:   mapping->globalstart = 0;
506:   mapping->globalend   = 0;

508:   /* reset the cached information */
509:   PetscFree(mapping->info_procs);
510:   PetscFree(mapping->info_numprocs);
511:   if (mapping->info_indices) {
512:     PetscInt i;

514:     PetscFree((mapping->info_indices)[0]);
515:     for (i = 1; i < mapping->info_nproc; i++) PetscFree(mapping->info_indices[i]);
516:     PetscFree(mapping->info_indices);
517:   }
518:   mapping->info_cached = PETSC_FALSE;

520:   PetscTryTypeMethod(mapping, destroy);
521:   return 0;
522: }

524: /*@
525:     ISLocalToGlobalMappingGetBlockSize - Gets the blocksize of the mapping
526:     ordering and a global parallel ordering.

528:     Not Collective

530:     Input Parameters:
531: .   mapping - mapping data structure

533:     Output Parameter:
534: .   bs - the blocksize

536:     Level: advanced

538: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`
539: @*/
540: PetscErrorCode ISLocalToGlobalMappingGetBlockSize(ISLocalToGlobalMapping mapping, PetscInt *bs)
541: {
543:   *bs = mapping->bs;
544:   return 0;
545: }

547: /*@
548:     ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n)
549:     ordering and a global parallel ordering.

551:     Not Collective, but communicator may have more than one process

553:     Input Parameters:
554: +   comm - MPI communicator
555: .   bs - the block size
556: .   n - the number of local elements divided by the block size, or equivalently the number of block indices
557: .   indices - the global index for each local element, these do not need to be in increasing order (sorted), these values should not be scaled (i.e. multiplied) by the blocksize bs
558: -   mode - see PetscCopyMode

560:     Output Parameter:
561: .   mapping - new mapping data structure

563:     Notes:
564:     There is one integer value in indices per block and it represents the actual indices bs*idx + j, where j=0,..,bs-1

566:     For "small" problems when using ISGlobalToLocalMappingApply() and ISGlobalToLocalMappingApplyBlock(), the ISLocalToGlobalMappingType of ISLOCALTOGLOBALMAPPINGBASIC will be used;
567:     this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems ISLOCALTOGLOBALMAPPINGHASH is used, this is scalable.
568:     Use ISLocalToGlobalMappingSetType() or call ISLocalToGlobalMappingSetFromOptions() with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.

570:     Level: advanced

572: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`, `ISLOCALTOGLOBALMAPPINGBASIC`, `ISLOCALTOGLOBALMAPPINGHASH`
573:           `ISLocalToGlobalMappingSetType()`, `ISLocalToGlobalMappingType`
574: @*/
575: PetscErrorCode ISLocalToGlobalMappingCreate(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscInt indices[], PetscCopyMode mode, ISLocalToGlobalMapping *mapping)
576: {
577:   PetscInt *in;


582:   *mapping = NULL;
583:   ISInitializePackage();

585:   PetscHeaderCreate(*mapping, IS_LTOGM_CLASSID, "ISLocalToGlobalMapping", "Local to global mapping", "IS", comm, ISLocalToGlobalMappingDestroy, ISLocalToGlobalMappingView);
586:   (*mapping)->n  = n;
587:   (*mapping)->bs = bs;
588:   if (mode == PETSC_COPY_VALUES) {
589:     PetscMalloc1(n, &in);
590:     PetscArraycpy(in, indices, n);
591:     (*mapping)->indices         = in;
592:     (*mapping)->dealloc_indices = PETSC_TRUE;
593:   } else if (mode == PETSC_OWN_POINTER) {
594:     (*mapping)->indices         = (PetscInt *)indices;
595:     (*mapping)->dealloc_indices = PETSC_TRUE;
596:   } else if (mode == PETSC_USE_POINTER) {
597:     (*mapping)->indices = (PetscInt *)indices;
598:   } else SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid mode %d", mode);
599:   return 0;
600: }

602: PetscFunctionList ISLocalToGlobalMappingList = NULL;

604: /*@
605:    ISLocalToGlobalMappingSetFromOptions - Set mapping options from the options database.

607:    Not collective

609:    Input Parameters:
610: .  mapping - mapping data structure

612:    Level: advanced

614: @*/
615: PetscErrorCode ISLocalToGlobalMappingSetFromOptions(ISLocalToGlobalMapping mapping)
616: {
617:   char                       type[256];
618:   ISLocalToGlobalMappingType defaulttype = "Not set";
619:   PetscBool                  flg;

622:   ISLocalToGlobalMappingRegisterAll();
623:   PetscObjectOptionsBegin((PetscObject)mapping);
624:   PetscOptionsFList("-islocaltoglobalmapping_type", "ISLocalToGlobalMapping method", "ISLocalToGlobalMappingSetType", ISLocalToGlobalMappingList, (char *)(((PetscObject)mapping)->type_name) ? ((PetscObject)mapping)->type_name : defaulttype, type, 256, &flg);
625:   if (flg) ISLocalToGlobalMappingSetType(mapping, type);
626:   PetscOptionsEnd();
627:   return 0;
628: }

630: /*@
631:    ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n)
632:    ordering and a global parallel ordering.

634:    Note Collective

636:    Input Parameters:
637: .  mapping - mapping data structure

639:    Level: advanced

641: .seealso: `ISLocalToGlobalMappingCreate()`
642: @*/
643: PetscErrorCode ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping *mapping)
644: {
645:   if (!*mapping) return 0;
647:   if (--((PetscObject)(*mapping))->refct > 0) {
648:     *mapping = NULL;
649:     return 0;
650:   }
651:   if ((*mapping)->dealloc_indices) PetscFree((*mapping)->indices);
652:   PetscFree((*mapping)->info_procs);
653:   PetscFree((*mapping)->info_numprocs);
654:   if ((*mapping)->info_indices) {
655:     PetscInt i;

657:     PetscFree(((*mapping)->info_indices)[0]);
658:     for (i = 1; i < (*mapping)->info_nproc; i++) PetscFree(((*mapping)->info_indices)[i]);
659:     PetscFree((*mapping)->info_indices);
660:   }
661:   if ((*mapping)->info_nodei) PetscFree(((*mapping)->info_nodei)[0]);
662:   PetscFree2((*mapping)->info_nodec, (*mapping)->info_nodei);
663:   if ((*mapping)->ops->destroy) (*(*mapping)->ops->destroy)(*mapping);
664:   PetscHeaderDestroy(mapping);
665:   *mapping = NULL;
666:   return 0;
667: }

669: /*@
670:     ISLocalToGlobalMappingApplyIS - Creates from an IS in the local numbering
671:     a new index set using the global numbering defined in an ISLocalToGlobalMapping
672:     context.

674:     Collective on is

676:     Input Parameters:
677: +   mapping - mapping between local and global numbering
678: -   is - index set in local numbering

680:     Output Parameters:
681: .   newis - index set in global numbering

683:     Notes:
684:     The output IS will have the same communicator of the input IS.

686:     Level: advanced

688: .seealso: `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
689:           `ISLocalToGlobalMappingDestroy()`, `ISGlobalToLocalMappingApply()`
690: @*/
691: PetscErrorCode ISLocalToGlobalMappingApplyIS(ISLocalToGlobalMapping mapping, IS is, IS *newis)
692: {
693:   PetscInt        n, *idxout;
694:   const PetscInt *idxin;


700:   ISGetLocalSize(is, &n);
701:   ISGetIndices(is, &idxin);
702:   PetscMalloc1(n, &idxout);
703:   ISLocalToGlobalMappingApply(mapping, n, idxin, idxout);
704:   ISRestoreIndices(is, &idxin);
705:   ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idxout, PETSC_OWN_POINTER, newis);
706:   return 0;
707: }

709: /*@
710:    ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering
711:    and converts them to the global numbering.

713:    Not collective

715:    Input Parameters:
716: +  mapping - the local to global mapping context
717: .  N - number of integers
718: -  in - input indices in local numbering

720:    Output Parameter:
721: .  out - indices in global numbering

723:    Notes:
724:    The in and out array parameters may be identical.

726:    Level: advanced

728: .seealso: `ISLocalToGlobalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`,
729:           `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`,
730:           `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()`

732: @*/
733: PetscErrorCode ISLocalToGlobalMappingApply(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[])
734: {
735:   PetscInt i, bs, Nmax;

738:   bs   = mapping->bs;
739:   Nmax = bs * mapping->n;
740:   if (bs == 1) {
741:     const PetscInt *idx = mapping->indices;
742:     for (i = 0; i < N; i++) {
743:       if (in[i] < 0) {
744:         out[i] = in[i];
745:         continue;
746:       }
748:       out[i] = idx[in[i]];
749:     }
750:   } else {
751:     const PetscInt *idx = mapping->indices;
752:     for (i = 0; i < N; i++) {
753:       if (in[i] < 0) {
754:         out[i] = in[i];
755:         continue;
756:       }
758:       out[i] = idx[in[i] / bs] * bs + (in[i] % bs);
759:     }
760:   }
761:   return 0;
762: }

764: /*@
765:    ISLocalToGlobalMappingApplyBlock - Takes a list of integers in a local block numbering and converts them to the global block numbering

767:    Not collective

769:    Input Parameters:
770: +  mapping - the local to global mapping context
771: .  N - number of integers
772: -  in - input indices in local block numbering

774:    Output Parameter:
775: .  out - indices in global block numbering

777:    Notes:
778:    The in and out array parameters may be identical.

780:    Example:
781:      If the index values are {0,1,6,7} set with a call to ISLocalToGlobalMappingCreate(PETSC_COMM_SELF,2,2,{0,3}) then the mapping applied to 0
782:      (the first block) would produce 0 and the mapping applied to 1 (the second block) would produce 3.

784:    Level: advanced

786: .seealso: `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`,
787:           `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`,
788:           `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()`

790: @*/
791: PetscErrorCode ISLocalToGlobalMappingApplyBlock(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[])
792: {
793:   PetscInt        i, Nmax;
794:   const PetscInt *idx;

797:   Nmax = mapping->n;
798:   idx  = mapping->indices;
799:   for (i = 0; i < N; i++) {
800:     if (in[i] < 0) {
801:       out[i] = in[i];
802:       continue;
803:     }
805:     out[i] = idx[in[i]];
806:   }
807:   return 0;
808: }

810: /*@
811:     ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers
812:     specified with a global numbering.

814:     Not collective

816:     Input Parameters:
817: +   mapping - mapping between local and global numbering
818: .   type - IS_GTOLM_MASK - maps global indices with no local value to -1 in the output list (i.e., mask them)
819:            IS_GTOLM_DROP - drops the indices with no local value from the output list
820: .   n - number of global indices to map
821: -   idx - global indices to map

823:     Output Parameters:
824: +   nout - number of indices in output array (if type == IS_GTOLM_MASK then nout = n)
825: -   idxout - local index of each global index, one must pass in an array long enough
826:              to hold all the indices. You can call ISGlobalToLocalMappingApply() with
827:              idxout == NULL to determine the required length (returned in nout)
828:              and then allocate the required space and call ISGlobalToLocalMappingApply()
829:              a second time to set the values.

831:     Notes:
832:     Either nout or idxout may be NULL. idx and idxout may be identical.

834:     For "small" problems when using ISGlobalToLocalMappingApply() and ISGlobalToLocalMappingApplyBlock(), the ISLocalToGlobalMappingType of ISLOCALTOGLOBALMAPPINGBASIC will be used;
835:     this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems ISLOCALTOGLOBALMAPPINGHASH is used, this is scalable.
836:     Use ISLocalToGlobalMappingSetType() or call ISLocalToGlobalMappingSetFromOptions() with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.

838:     Level: advanced

840:     Developer Note: The manual page states that idx and idxout may be identical but the calling
841:        sequence declares idx as const so it cannot be the same as idxout.

843: .seealso: `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`,
844:           `ISLocalToGlobalMappingDestroy()`
845: @*/
846: PetscErrorCode ISGlobalToLocalMappingApply(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[])
847: {
849:   if (!mapping->data) ISGlobalToLocalMappingSetUp(mapping);
850:   PetscUseTypeMethod(mapping, globaltolocalmappingapply, type, n, idx, nout, idxout);
851:   return 0;
852: }

854: /*@
855:     ISGlobalToLocalMappingApplyIS - Creates from an IS in the global numbering
856:     a new index set using the local numbering defined in an ISLocalToGlobalMapping
857:     context.

859:     Not collective

861:     Input Parameters:
862: +   mapping - mapping between local and global numbering
863: .   type - IS_GTOLM_MASK - maps global indices with no local value to -1 in the output list (i.e., mask them)
864:            IS_GTOLM_DROP - drops the indices with no local value from the output list
865: -   is - index set in global numbering

867:     Output Parameters:
868: .   newis - index set in local numbering

870:     Notes:
871:     The output IS will be sequential, as it encodes a purely local operation

873:     Level: advanced

875: .seealso: `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
876:           `ISLocalToGlobalMappingDestroy()`
877: @*/
878: PetscErrorCode ISGlobalToLocalMappingApplyIS(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, IS is, IS *newis)
879: {
880:   PetscInt        n, nout, *idxout;
881:   const PetscInt *idxin;


887:   ISGetLocalSize(is, &n);
888:   ISGetIndices(is, &idxin);
889:   if (type == IS_GTOLM_MASK) {
890:     PetscMalloc1(n, &idxout);
891:   } else {
892:     ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, NULL);
893:     PetscMalloc1(nout, &idxout);
894:   }
895:   ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, idxout);
896:   ISRestoreIndices(is, &idxin);
897:   ISCreateGeneral(PETSC_COMM_SELF, nout, idxout, PETSC_OWN_POINTER, newis);
898:   return 0;
899: }

901: /*@
902:     ISGlobalToLocalMappingApplyBlock - Provides the local block numbering for a list of integers
903:     specified with a block global numbering.

905:     Not collective

907:     Input Parameters:
908: +   mapping - mapping between local and global numbering
909: .   type - IS_GTOLM_MASK - maps global indices with no local value to -1 in the output list (i.e., mask them)
910:            IS_GTOLM_DROP - drops the indices with no local value from the output list
911: .   n - number of global indices to map
912: -   idx - global indices to map

914:     Output Parameters:
915: +   nout - number of indices in output array (if type == IS_GTOLM_MASK then nout = n)
916: -   idxout - local index of each global index, one must pass in an array long enough
917:              to hold all the indices. You can call ISGlobalToLocalMappingApplyBlock() with
918:              idxout == NULL to determine the required length (returned in nout)
919:              and then allocate the required space and call ISGlobalToLocalMappingApplyBlock()
920:              a second time to set the values.

922:     Notes:
923:     Either nout or idxout may be NULL. idx and idxout may be identical.

925:     For "small" problems when using ISGlobalToLocalMappingApply() and ISGlobalToLocalMappingApplyBlock(), the ISLocalToGlobalMappingType of ISLOCALTOGLOBALMAPPINGBASIC will be used;
926:     this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems ISLOCALTOGLOBALMAPPINGHASH is used, this is scalable.
927:     Use ISLocalToGlobalMappingSetType() or call ISLocalToGlobalMappingSetFromOptions() with the option -islocaltoglobalmapping_type <basic,hash> to control which is used.

929:     Level: advanced

931:     Developer Note: The manual page states that idx and idxout may be identical but the calling
932:        sequence declares idx as const so it cannot be the same as idxout.

934: .seealso: `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`,
935:           `ISLocalToGlobalMappingDestroy()`
936: @*/
937: PetscErrorCode ISGlobalToLocalMappingApplyBlock(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[])
938: {
940:   if (!mapping->data) ISGlobalToLocalMappingSetUp(mapping);
941:   PetscUseTypeMethod(mapping, globaltolocalmappingapplyblock, type, n, idx, nout, idxout);
942:   return 0;
943: }

945: /*@C
946:     ISLocalToGlobalMappingGetBlockInfo - Gets the neighbor information for each processor and
947:      each index shared by more than one processor

949:     Collective on ISLocalToGlobalMapping

951:     Input Parameter:
952: .   mapping - the mapping from local to global indexing

954:     Output Parameters:
955: +   nproc - number of processors that are connected to this one
956: .   proc - neighboring processors
957: .   numproc - number of indices for each subdomain (processor)
958: -   indices - indices of nodes (in local numbering) shared with neighbors (sorted by global numbering)

960:     Level: advanced

962:     Fortran Usage:
963: $        ISLocalToGlobalMpngGetInfoSize(ISLocalToGlobalMapping,PetscInt nproc,PetscInt numprocmax,ierr) followed by
964: $        ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping,PetscInt nproc, PetscInt procs[nproc],PetscInt numprocs[nproc],
965:           PetscInt indices[nproc][numprocmax],ierr)
966:         There is no ISLocalToGlobalMappingRestoreInfo() in Fortran. You must make sure that procs[], numprocs[] and
967:         indices[][] are large enough arrays, either by allocating them dynamically or defining static ones large enough.

969: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
970:           `ISLocalToGlobalMappingRestoreInfo()`
971: @*/
972: PetscErrorCode ISLocalToGlobalMappingGetBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
973: {
975:   if (mapping->info_cached) {
976:     *nproc    = mapping->info_nproc;
977:     *procs    = mapping->info_procs;
978:     *numprocs = mapping->info_numprocs;
979:     *indices  = mapping->info_indices;
980:   } else {
981:     ISLocalToGlobalMappingGetBlockInfo_Private(mapping, nproc, procs, numprocs, indices);
982:   }
983:   return 0;
984: }

986: static PetscErrorCode ISLocalToGlobalMappingGetBlockInfo_Private(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
987: {
988:   PetscMPIInt  size, rank, tag1, tag2, tag3, *len, *source, imdex;
989:   PetscInt     i, n = mapping->n, Ng, ng, max = 0, *lindices = mapping->indices;
990:   PetscInt    *nprocs, *owner, nsends, *sends, j, *starts, nmax, nrecvs, *recvs, proc;
991:   PetscInt     cnt, scale, *ownedsenders, *nownedsenders, rstart;
992:   PetscInt     node, nownedm, nt, *sends2, nsends2, *starts2, *lens2, *dest, nrecvs2, *starts3, *recvs2, k, *bprocs, *tmp;
993:   PetscInt     first_procs, first_numprocs, *first_indices;
994:   MPI_Request *recv_waits, *send_waits;
995:   MPI_Status   recv_status, *send_status, *recv_statuses;
996:   MPI_Comm     comm;
997:   PetscBool    debug = PETSC_FALSE;

999:   PetscObjectGetComm((PetscObject)mapping, &comm);
1000:   MPI_Comm_size(comm, &size);
1001:   MPI_Comm_rank(comm, &rank);
1002:   if (size == 1) {
1003:     *nproc = 0;
1004:     *procs = NULL;
1005:     PetscNew(numprocs);
1006:     (*numprocs)[0] = 0;
1007:     PetscNew(indices);
1008:     (*indices)[0] = NULL;
1009:     /* save info for reuse */
1010:     mapping->info_nproc    = *nproc;
1011:     mapping->info_procs    = *procs;
1012:     mapping->info_numprocs = *numprocs;
1013:     mapping->info_indices  = *indices;
1014:     mapping->info_cached   = PETSC_TRUE;
1015:     return 0;
1016:   }

1018:   PetscOptionsGetBool(((PetscObject)mapping)->options, NULL, "-islocaltoglobalmappinggetinfo_debug", &debug, NULL);

1020:   /*
1021:     Notes on ISLocalToGlobalMappingGetBlockInfo

1023:     globally owned node - the nodes that have been assigned to this processor in global
1024:            numbering, just for this routine.

1026:     nontrivial globally owned node - node assigned to this processor that is on a subdomain
1027:            boundary (i.e. is has more than one local owner)

1029:     locally owned node - node that exists on this processors subdomain

1031:     nontrivial locally owned node - node that is not in the interior (i.e. has more than one
1032:            local subdomain
1033:   */
1034:   PetscObjectGetNewTag((PetscObject)mapping, &tag1);
1035:   PetscObjectGetNewTag((PetscObject)mapping, &tag2);
1036:   PetscObjectGetNewTag((PetscObject)mapping, &tag3);

1038:   for (i = 0; i < n; i++) {
1039:     if (lindices[i] > max) max = lindices[i];
1040:   }
1041:   MPIU_Allreduce(&max, &Ng, 1, MPIU_INT, MPI_MAX, comm);
1042:   Ng++;
1043:   MPI_Comm_size(comm, &size);
1044:   MPI_Comm_rank(comm, &rank);
1045:   scale = Ng / size + 1;
1046:   ng    = scale;
1047:   if (rank == size - 1) ng = Ng - scale * (size - 1);
1048:   ng     = PetscMax(1, ng);
1049:   rstart = scale * rank;

1051:   /* determine ownership ranges of global indices */
1052:   PetscMalloc1(2 * size, &nprocs);
1053:   PetscArrayzero(nprocs, 2 * size);

1055:   /* determine owners of each local node  */
1056:   PetscMalloc1(n, &owner);
1057:   for (i = 0; i < n; i++) {
1058:     proc                 = lindices[i] / scale; /* processor that globally owns this index */
1059:     nprocs[2 * proc + 1] = 1;                   /* processor globally owns at least one of ours */
1060:     owner[i]             = proc;
1061:     nprocs[2 * proc]++; /* count of how many that processor globally owns of ours */
1062:   }
1063:   nsends = 0;
1064:   for (i = 0; i < size; i++) nsends += nprocs[2 * i + 1];
1065:   PetscInfo(mapping, "Number of global owners for my local data %" PetscInt_FMT "\n", nsends);

1067:   /* inform other processors of number of messages and max length*/
1068:   PetscMaxSum(comm, nprocs, &nmax, &nrecvs);
1069:   PetscInfo(mapping, "Number of local owners for my global data %" PetscInt_FMT "\n", nrecvs);

1071:   /* post receives for owned rows */
1072:   PetscMalloc1((2 * nrecvs + 1) * (nmax + 1), &recvs);
1073:   PetscMalloc1(nrecvs + 1, &recv_waits);
1074:   for (i = 0; i < nrecvs; i++) MPI_Irecv(recvs + 2 * nmax * i, 2 * nmax, MPIU_INT, MPI_ANY_SOURCE, tag1, comm, recv_waits + i);

1076:   /* pack messages containing lists of local nodes to owners */
1077:   PetscMalloc1(2 * n + 1, &sends);
1078:   PetscMalloc1(size + 1, &starts);
1079:   starts[0] = 0;
1080:   for (i = 1; i < size; i++) starts[i] = starts[i - 1] + 2 * nprocs[2 * i - 2];
1081:   for (i = 0; i < n; i++) {
1082:     sends[starts[owner[i]]++] = lindices[i];
1083:     sends[starts[owner[i]]++] = i;
1084:   }
1085:   PetscFree(owner);
1086:   starts[0] = 0;
1087:   for (i = 1; i < size; i++) starts[i] = starts[i - 1] + 2 * nprocs[2 * i - 2];

1089:   /* send the messages */
1090:   PetscMalloc1(nsends + 1, &send_waits);
1091:   PetscMalloc1(nsends + 1, &dest);
1092:   cnt = 0;
1093:   for (i = 0; i < size; i++) {
1094:     if (nprocs[2 * i]) {
1095:       MPI_Isend(sends + starts[i], 2 * nprocs[2 * i], MPIU_INT, i, tag1, comm, send_waits + cnt);
1096:       dest[cnt] = i;
1097:       cnt++;
1098:     }
1099:   }
1100:   PetscFree(starts);

1102:   /* wait on receives */
1103:   PetscMalloc1(nrecvs + 1, &source);
1104:   PetscMalloc1(nrecvs + 1, &len);
1105:   cnt = nrecvs;
1106:   PetscCalloc1(ng + 1, &nownedsenders);
1107:   while (cnt) {
1108:     MPI_Waitany(nrecvs, recv_waits, &imdex, &recv_status);
1109:     /* unpack receives into our local space */
1110:     MPI_Get_count(&recv_status, MPIU_INT, &len[imdex]);
1111:     source[imdex] = recv_status.MPI_SOURCE;
1112:     len[imdex]    = len[imdex] / 2;
1113:     /* count how many local owners for each of my global owned indices */
1114:     for (i = 0; i < len[imdex]; i++) nownedsenders[recvs[2 * imdex * nmax + 2 * i] - rstart]++;
1115:     cnt--;
1116:   }
1117:   PetscFree(recv_waits);

1119:   /* count how many globally owned indices are on an edge multiplied by how many processors own them. */
1120:   nownedm = 0;
1121:   for (i = 0; i < ng; i++) {
1122:     if (nownedsenders[i] > 1) nownedm += nownedsenders[i];
1123:   }

1125:   /* create single array to contain rank of all local owners of each globally owned index */
1126:   PetscMalloc1(nownedm + 1, &ownedsenders);
1127:   PetscMalloc1(ng + 1, &starts);
1128:   starts[0] = 0;
1129:   for (i = 1; i < ng; i++) {
1130:     if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1131:     else starts[i] = starts[i - 1];
1132:   }

1134:   /* for each nontrivial globally owned node list all arriving processors */
1135:   for (i = 0; i < nrecvs; i++) {
1136:     for (j = 0; j < len[i]; j++) {
1137:       node = recvs[2 * i * nmax + 2 * j] - rstart;
1138:       if (nownedsenders[node] > 1) ownedsenders[starts[node]++] = source[i];
1139:     }
1140:   }

1142:   if (debug) { /* -----------------------------------  */
1143:     starts[0] = 0;
1144:     for (i = 1; i < ng; i++) {
1145:       if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1146:       else starts[i] = starts[i - 1];
1147:     }
1148:     for (i = 0; i < ng; i++) {
1149:       if (nownedsenders[i] > 1) {
1150:         PetscSynchronizedPrintf(comm, "[%d] global node %" PetscInt_FMT " local owner processors: ", rank, i + rstart);
1151:         for (j = 0; j < nownedsenders[i]; j++) PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", ownedsenders[starts[i] + j]);
1152:         PetscSynchronizedPrintf(comm, "\n");
1153:       }
1154:     }
1155:     PetscSynchronizedFlush(comm, PETSC_STDOUT);
1156:   } /* -----------------------------------  */

1158:   /* wait on original sends */
1159:   if (nsends) {
1160:     PetscMalloc1(nsends, &send_status);
1161:     MPI_Waitall(nsends, send_waits, send_status);
1162:     PetscFree(send_status);
1163:   }
1164:   PetscFree(send_waits);
1165:   PetscFree(sends);
1166:   PetscFree(nprocs);

1168:   /* pack messages to send back to local owners */
1169:   starts[0] = 0;
1170:   for (i = 1; i < ng; i++) {
1171:     if (nownedsenders[i - 1] > 1) starts[i] = starts[i - 1] + nownedsenders[i - 1];
1172:     else starts[i] = starts[i - 1];
1173:   }
1174:   nsends2 = nrecvs;
1175:   PetscMalloc1(nsends2 + 1, &nprocs); /* length of each message */
1176:   for (i = 0; i < nrecvs; i++) {
1177:     nprocs[i] = 1;
1178:     for (j = 0; j < len[i]; j++) {
1179:       node = recvs[2 * i * nmax + 2 * j] - rstart;
1180:       if (nownedsenders[node] > 1) nprocs[i] += 2 + nownedsenders[node];
1181:     }
1182:   }
1183:   nt = 0;
1184:   for (i = 0; i < nsends2; i++) nt += nprocs[i];

1186:   PetscMalloc1(nt + 1, &sends2);
1187:   PetscMalloc1(nsends2 + 1, &starts2);

1189:   starts2[0] = 0;
1190:   for (i = 1; i < nsends2; i++) starts2[i] = starts2[i - 1] + nprocs[i - 1];
1191:   /*
1192:      Each message is 1 + nprocs[i] long, and consists of
1193:        (0) the number of nodes being sent back
1194:        (1) the local node number,
1195:        (2) the number of processors sharing it,
1196:        (3) the processors sharing it
1197:   */
1198:   for (i = 0; i < nsends2; i++) {
1199:     cnt                = 1;
1200:     sends2[starts2[i]] = 0;
1201:     for (j = 0; j < len[i]; j++) {
1202:       node = recvs[2 * i * nmax + 2 * j] - rstart;
1203:       if (nownedsenders[node] > 1) {
1204:         sends2[starts2[i]]++;
1205:         sends2[starts2[i] + cnt++] = recvs[2 * i * nmax + 2 * j + 1];
1206:         sends2[starts2[i] + cnt++] = nownedsenders[node];
1207:         PetscArraycpy(&sends2[starts2[i] + cnt], &ownedsenders[starts[node]], nownedsenders[node]);
1208:         cnt += nownedsenders[node];
1209:       }
1210:     }
1211:   }

1213:   /* receive the message lengths */
1214:   nrecvs2 = nsends;
1215:   PetscMalloc1(nrecvs2 + 1, &lens2);
1216:   PetscMalloc1(nrecvs2 + 1, &starts3);
1217:   PetscMalloc1(nrecvs2 + 1, &recv_waits);
1218:   for (i = 0; i < nrecvs2; i++) MPI_Irecv(&lens2[i], 1, MPIU_INT, dest[i], tag2, comm, recv_waits + i);

1220:   /* send the message lengths */
1221:   for (i = 0; i < nsends2; i++) MPI_Send(&nprocs[i], 1, MPIU_INT, source[i], tag2, comm);

1223:   /* wait on receives of lens */
1224:   if (nrecvs2) {
1225:     PetscMalloc1(nrecvs2, &recv_statuses);
1226:     MPI_Waitall(nrecvs2, recv_waits, recv_statuses);
1227:     PetscFree(recv_statuses);
1228:   }
1229:   PetscFree(recv_waits);

1231:   starts3[0] = 0;
1232:   nt         = 0;
1233:   for (i = 0; i < nrecvs2 - 1; i++) {
1234:     starts3[i + 1] = starts3[i] + lens2[i];
1235:     nt += lens2[i];
1236:   }
1237:   if (nrecvs2) nt += lens2[nrecvs2 - 1];

1239:   PetscMalloc1(nt + 1, &recvs2);
1240:   PetscMalloc1(nrecvs2 + 1, &recv_waits);
1241:   for (i = 0; i < nrecvs2; i++) MPI_Irecv(recvs2 + starts3[i], lens2[i], MPIU_INT, dest[i], tag3, comm, recv_waits + i);

1243:   /* send the messages */
1244:   PetscMalloc1(nsends2 + 1, &send_waits);
1245:   for (i = 0; i < nsends2; i++) MPI_Isend(sends2 + starts2[i], nprocs[i], MPIU_INT, source[i], tag3, comm, send_waits + i);

1247:   /* wait on receives */
1248:   if (nrecvs2) {
1249:     PetscMalloc1(nrecvs2, &recv_statuses);
1250:     MPI_Waitall(nrecvs2, recv_waits, recv_statuses);
1251:     PetscFree(recv_statuses);
1252:   }
1253:   PetscFree(recv_waits);
1254:   PetscFree(nprocs);

1256:   if (debug) { /* -----------------------------------  */
1257:     cnt = 0;
1258:     for (i = 0; i < nrecvs2; i++) {
1259:       nt = recvs2[cnt++];
1260:       for (j = 0; j < nt; j++) {
1261:         PetscSynchronizedPrintf(comm, "[%d] local node %" PetscInt_FMT " number of subdomains %" PetscInt_FMT ": ", rank, recvs2[cnt], recvs2[cnt + 1]);
1262:         for (k = 0; k < recvs2[cnt + 1]; k++) PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", recvs2[cnt + 2 + k]);
1263:         cnt += 2 + recvs2[cnt + 1];
1264:         PetscSynchronizedPrintf(comm, "\n");
1265:       }
1266:     }
1267:     PetscSynchronizedFlush(comm, PETSC_STDOUT);
1268:   } /* -----------------------------------  */

1270:   /* count number subdomains for each local node */
1271:   PetscCalloc1(size, &nprocs);
1272:   cnt = 0;
1273:   for (i = 0; i < nrecvs2; i++) {
1274:     nt = recvs2[cnt++];
1275:     for (j = 0; j < nt; j++) {
1276:       for (k = 0; k < recvs2[cnt + 1]; k++) nprocs[recvs2[cnt + 2 + k]]++;
1277:       cnt += 2 + recvs2[cnt + 1];
1278:     }
1279:   }
1280:   nt = 0;
1281:   for (i = 0; i < size; i++) nt += (nprocs[i] > 0);
1282:   *nproc = nt;
1283:   PetscMalloc1(nt + 1, procs);
1284:   PetscMalloc1(nt + 1, numprocs);
1285:   PetscMalloc1(nt + 1, indices);
1286:   for (i = 0; i < nt + 1; i++) (*indices)[i] = NULL;
1287:   PetscMalloc1(size, &bprocs);
1288:   cnt = 0;
1289:   for (i = 0; i < size; i++) {
1290:     if (nprocs[i] > 0) {
1291:       bprocs[i]        = cnt;
1292:       (*procs)[cnt]    = i;
1293:       (*numprocs)[cnt] = nprocs[i];
1294:       PetscMalloc1(nprocs[i], &(*indices)[cnt]);
1295:       cnt++;
1296:     }
1297:   }

1299:   /* make the list of subdomains for each nontrivial local node */
1300:   PetscArrayzero(*numprocs, nt);
1301:   cnt = 0;
1302:   for (i = 0; i < nrecvs2; i++) {
1303:     nt = recvs2[cnt++];
1304:     for (j = 0; j < nt; j++) {
1305:       for (k = 0; k < recvs2[cnt + 1]; k++) (*indices)[bprocs[recvs2[cnt + 2 + k]]][(*numprocs)[bprocs[recvs2[cnt + 2 + k]]]++] = recvs2[cnt];
1306:       cnt += 2 + recvs2[cnt + 1];
1307:     }
1308:   }
1309:   PetscFree(bprocs);
1310:   PetscFree(recvs2);

1312:   /* sort the node indexing by their global numbers */
1313:   nt = *nproc;
1314:   for (i = 0; i < nt; i++) {
1315:     PetscMalloc1((*numprocs)[i], &tmp);
1316:     for (j = 0; j < (*numprocs)[i]; j++) tmp[j] = lindices[(*indices)[i][j]];
1317:     PetscSortIntWithArray((*numprocs)[i], tmp, (*indices)[i]);
1318:     PetscFree(tmp);
1319:   }

1321:   if (debug) { /* -----------------------------------  */
1322:     nt = *nproc;
1323:     for (i = 0; i < nt; i++) {
1324:       PetscSynchronizedPrintf(comm, "[%d] subdomain %" PetscInt_FMT " number of indices %" PetscInt_FMT ": ", rank, (*procs)[i], (*numprocs)[i]);
1325:       for (j = 0; j < (*numprocs)[i]; j++) PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", (*indices)[i][j]);
1326:       PetscSynchronizedPrintf(comm, "\n");
1327:     }
1328:     PetscSynchronizedFlush(comm, PETSC_STDOUT);
1329:   } /* -----------------------------------  */

1331:   /* wait on sends */
1332:   if (nsends2) {
1333:     PetscMalloc1(nsends2, &send_status);
1334:     MPI_Waitall(nsends2, send_waits, send_status);
1335:     PetscFree(send_status);
1336:   }

1338:   PetscFree(starts3);
1339:   PetscFree(dest);
1340:   PetscFree(send_waits);

1342:   PetscFree(nownedsenders);
1343:   PetscFree(ownedsenders);
1344:   PetscFree(starts);
1345:   PetscFree(starts2);
1346:   PetscFree(lens2);

1348:   PetscFree(source);
1349:   PetscFree(len);
1350:   PetscFree(recvs);
1351:   PetscFree(nprocs);
1352:   PetscFree(sends2);

1354:   /* put the information about myself as the first entry in the list */
1355:   first_procs    = (*procs)[0];
1356:   first_numprocs = (*numprocs)[0];
1357:   first_indices  = (*indices)[0];
1358:   for (i = 0; i < *nproc; i++) {
1359:     if ((*procs)[i] == rank) {
1360:       (*procs)[0]    = (*procs)[i];
1361:       (*numprocs)[0] = (*numprocs)[i];
1362:       (*indices)[0]  = (*indices)[i];
1363:       (*procs)[i]    = first_procs;
1364:       (*numprocs)[i] = first_numprocs;
1365:       (*indices)[i]  = first_indices;
1366:       break;
1367:     }
1368:   }

1370:   /* save info for reuse */
1371:   mapping->info_nproc    = *nproc;
1372:   mapping->info_procs    = *procs;
1373:   mapping->info_numprocs = *numprocs;
1374:   mapping->info_indices  = *indices;
1375:   mapping->info_cached   = PETSC_TRUE;
1376:   return 0;
1377: }

1379: /*@C
1380:     ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by ISLocalToGlobalMappingGetBlockInfo()

1382:     Collective on ISLocalToGlobalMapping

1384:     Input Parameter:
1385: .   mapping - the mapping from local to global indexing

1387:     Output Parameters:
1388: +   nproc - number of processors that are connected to this one
1389: .   proc - neighboring processors
1390: .   numproc - number of indices for each processor
1391: -   indices - indices of local nodes shared with neighbor (sorted by global numbering)

1393:     Level: advanced

1395: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1396:           `ISLocalToGlobalMappingGetInfo()`
1397: @*/
1398: PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1399: {
1401:   if (mapping->info_free) {
1402:     PetscFree(*numprocs);
1403:     if (*indices) {
1404:       PetscInt i;

1406:       PetscFree((*indices)[0]);
1407:       for (i = 1; i < *nproc; i++) PetscFree((*indices)[i]);
1408:       PetscFree(*indices);
1409:     }
1410:   }
1411:   *nproc    = 0;
1412:   *procs    = NULL;
1413:   *numprocs = NULL;
1414:   *indices  = NULL;
1415:   return 0;
1416: }

1418: /*@C
1419:     ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each processor and
1420:      each index shared by more than one processor

1422:     Collective on ISLocalToGlobalMapping

1424:     Input Parameter:
1425: .   mapping - the mapping from local to global indexing

1427:     Output Parameters:
1428: +   nproc - number of processors that are connected to this one
1429: .   proc - neighboring processors
1430: .   numproc - number of indices for each subdomain (processor)
1431: -   indices - indices of nodes (in local numbering) shared with neighbors (sorted by global numbering)

1433:     Level: advanced

1435:     Notes: The user needs to call ISLocalToGlobalMappingRestoreInfo when the data is no longer needed.

1437:     Fortran Usage:
1438: $        ISLocalToGlobalMpngGetInfoSize(ISLocalToGlobalMapping,PetscInt nproc,PetscInt numprocmax,ierr) followed by
1439: $        ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping,PetscInt nproc, PetscInt procs[nproc],PetscInt numprocs[nproc],
1440:           PetscInt indices[nproc][numprocmax],ierr)
1441:         There is no ISLocalToGlobalMappingRestoreInfo() in Fortran. You must make sure that procs[], numprocs[] and
1442:         indices[][] are large enough arrays, either by allocating them dynamically or defining static ones large enough.

1444: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1445:           `ISLocalToGlobalMappingRestoreInfo()`
1446: @*/
1447: PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1448: {
1449:   PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k;

1452:   bs = mapping->bs;
1453:   ISLocalToGlobalMappingGetBlockInfo(mapping, nproc, procs, &bnumprocs, &bindices);
1454:   if (bs > 1) { /* we need to expand the cached info */
1455:     PetscCalloc1(*nproc, &*indices);
1456:     PetscCalloc1(*nproc, &*numprocs);
1457:     for (i = 0; i < *nproc; i++) {
1458:       PetscMalloc1(bs * bnumprocs[i], &(*indices)[i]);
1459:       for (j = 0; j < bnumprocs[i]; j++) {
1460:         for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k;
1461:       }
1462:       (*numprocs)[i] = bnumprocs[i] * bs;
1463:     }
1464:     mapping->info_free = PETSC_TRUE;
1465:   } else {
1466:     *numprocs = bnumprocs;
1467:     *indices  = bindices;
1468:   }
1469:   return 0;
1470: }

1472: /*@C
1473:     ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by ISLocalToGlobalMappingGetInfo()

1475:     Collective on ISLocalToGlobalMapping

1477:     Input Parameter:
1478: .   mapping - the mapping from local to global indexing

1480:     Output Parameters:
1481: +   nproc - number of processors that are connected to this one
1482: .   proc - neighboring processors
1483: .   numproc - number of indices for each processor
1484: -   indices - indices of local nodes shared with neighbor (sorted by global numbering)

1486:     Level: advanced

1488: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1489:           `ISLocalToGlobalMappingGetInfo()`
1490: @*/
1491: PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[])
1492: {
1493:   ISLocalToGlobalMappingRestoreBlockInfo(mapping, nproc, procs, numprocs, indices);
1494:   return 0;
1495: }

1497: /*@C
1498:     ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information for each node

1500:     Collective on ISLocalToGlobalMapping

1502:     Input Parameter:
1503: .   mapping - the mapping from local to global indexing

1505:     Output Parameters:
1506: +   nnodes - number of local nodes (same ISLocalToGlobalMappingGetSize())
1507: .   count - number of neighboring processors per node
1508: -   indices - indices of processes sharing the node (sorted)

1510:     Level: advanced

1512:     Notes: The user needs to call ISLocalToGlobalMappingRestoreInfo when the data is no longer needed.

1514: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1515:           `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`
1516: @*/
1517: PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *nnodes, PetscInt *count[], PetscInt **indices[])
1518: {
1519:   PetscInt n;

1522:   ISLocalToGlobalMappingGetSize(mapping, &n);
1523:   if (!mapping->info_nodec) {
1524:     PetscInt i, m, n_neigh, *neigh, *n_shared, **shared;

1526:     PetscMalloc2(n + 1, &mapping->info_nodec, n, &mapping->info_nodei);
1527:     ISLocalToGlobalMappingGetInfo(mapping, &n_neigh, &neigh, &n_shared, &shared);
1528:     for (i = 0; i < n; i++) mapping->info_nodec[i] = 1;
1529:     m                      = n;
1530:     mapping->info_nodec[n] = 0;
1531:     for (i = 1; i < n_neigh; i++) {
1532:       PetscInt j;

1534:       m += n_shared[i];
1535:       for (j = 0; j < n_shared[i]; j++) mapping->info_nodec[shared[i][j]] += 1;
1536:     }
1537:     if (n) PetscMalloc1(m, &mapping->info_nodei[0]);
1538:     for (i = 1; i < n; i++) mapping->info_nodei[i] = mapping->info_nodei[i - 1] + mapping->info_nodec[i - 1];
1539:     PetscArrayzero(mapping->info_nodec, n);
1540:     for (i = 0; i < n; i++) {
1541:       mapping->info_nodec[i]    = 1;
1542:       mapping->info_nodei[i][0] = neigh[0];
1543:     }
1544:     for (i = 1; i < n_neigh; i++) {
1545:       PetscInt j;

1547:       for (j = 0; j < n_shared[i]; j++) {
1548:         PetscInt k = shared[i][j];

1550:         mapping->info_nodei[k][mapping->info_nodec[k]] = neigh[i];
1551:         mapping->info_nodec[k] += 1;
1552:       }
1553:     }
1554:     for (i = 0; i < n; i++) PetscSortRemoveDupsInt(&mapping->info_nodec[i], mapping->info_nodei[i]);
1555:     ISLocalToGlobalMappingRestoreInfo(mapping, &n_neigh, &neigh, &n_shared, &shared);
1556:   }
1557:   if (nnodes) *nnodes = n;
1558:   if (count) *count = mapping->info_nodec;
1559:   if (indices) *indices = mapping->info_nodei;
1560:   return 0;
1561: }

1563: /*@C
1564:     ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by ISLocalToGlobalMappingGetNodeInfo()

1566:     Collective on ISLocalToGlobalMapping

1568:     Input Parameter:
1569: .   mapping - the mapping from local to global indexing

1571:     Output Parameters:
1572: +   nnodes - number of local nodes
1573: .   count - number of neighboring processors per node
1574: -   indices - indices of processes sharing the node (sorted)

1576:     Level: advanced

1578: .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`,
1579:           `ISLocalToGlobalMappingGetInfo()`
1580: @*/
1581: PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *nnodes, PetscInt *count[], PetscInt **indices[])
1582: {
1584:   if (nnodes) *nnodes = 0;
1585:   if (count) *count = NULL;
1586:   if (indices) *indices = NULL;
1587:   return 0;
1588: }

1590: /*@C
1591:    ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped

1593:    Not Collective

1595:    Input Parameter:
1596: . ltog - local to global mapping

1598:    Output Parameter:
1599: . array - array of indices, the length of this array may be obtained with ISLocalToGlobalMappingGetSize()

1601:    Level: advanced

1603:    Notes:
1604:     ISLocalToGlobalMappingGetSize() returns the length the this array

1606: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`, `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1607: @*/
1608: PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1609: {
1612:   if (ltog->bs == 1) {
1613:     *array = ltog->indices;
1614:   } else {
1615:     PetscInt       *jj, k, i, j, n = ltog->n, bs = ltog->bs;
1616:     const PetscInt *ii;

1618:     PetscMalloc1(bs * n, &jj);
1619:     *array = jj;
1620:     k      = 0;
1621:     ii     = ltog->indices;
1622:     for (i = 0; i < n; i++)
1623:       for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j;
1624:   }
1625:   return 0;
1626: }

1628: /*@C
1629:    ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with ISLocalToGlobalMappingGetIndices()

1631:    Not Collective

1633:    Input Parameters:
1634: + ltog - local to global mapping
1635: - array - array of indices

1637:    Level: advanced

1639: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1640: @*/
1641: PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1642: {

1647:   if (ltog->bs > 1) PetscFree(*(void **)array);
1648:   return 0;
1649: }

1651: /*@C
1652:    ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block

1654:    Not Collective

1656:    Input Parameter:
1657: . ltog - local to global mapping

1659:    Output Parameter:
1660: . array - array of indices

1662:    Level: advanced

1664: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreBlockIndices()`
1665: @*/
1666: PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1667: {
1670:   *array = ltog->indices;
1671:   return 0;
1672: }

1674: /*@C
1675:    ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with ISLocalToGlobalMappingGetBlockIndices()

1677:    Not Collective

1679:    Input Parameters:
1680: + ltog - local to global mapping
1681: - array - array of indices

1683:    Level: advanced

1685: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()`
1686: @*/
1687: PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array)
1688: {
1692:   *array = NULL;
1693:   return 0;
1694: }

1696: /*@C
1697:    ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings

1699:    Not Collective

1701:    Input Parameters:
1702: + comm - communicator for the new mapping, must contain the communicator of every mapping to concatenate
1703: . n - number of mappings to concatenate
1704: - ltogs - local to global mappings

1706:    Output Parameter:
1707: . ltogcat - new mapping

1709:    Note: this currently always returns a mapping with block size of 1

1711:    Developer Note: If all the input mapping have the same block size we could easily handle that as a special case

1713:    Level: advanced

1715: .seealso: `ISLocalToGlobalMappingCreate()`
1716: @*/
1717: PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat)
1718: {
1719:   PetscInt i, cnt, m, *idx;

1725:   for (cnt = 0, i = 0; i < n; i++) {
1726:     ISLocalToGlobalMappingGetSize(ltogs[i], &m);
1727:     cnt += m;
1728:   }
1729:   PetscMalloc1(cnt, &idx);
1730:   for (cnt = 0, i = 0; i < n; i++) {
1731:     const PetscInt *subidx;
1732:     ISLocalToGlobalMappingGetSize(ltogs[i], &m);
1733:     ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx);
1734:     PetscArraycpy(&idx[cnt], subidx, m);
1735:     ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx);
1736:     cnt += m;
1737:   }
1738:   ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat);
1739:   return 0;
1740: }

1742: /*MC
1743:       ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the ISLocalToGlobalMapping object. When ISGlobalToLocalMappingApply() is
1744:                                     used this is good for only small and moderate size problems.

1746:    Options Database Keys:
1747: .   -islocaltoglobalmapping_type basic - select this method

1749:    Level: beginner

1751: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH`
1752: M*/
1753: PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog)
1754: {
1755:   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Basic;
1756:   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Basic;
1757:   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic;
1758:   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Basic;
1759:   return 0;
1760: }

1762: /*MC
1763:       ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the ISLocalToGlobalMapping object. When ISGlobalToLocalMappingApply() is
1764:                                     used this is good for large memory problems.

1766:    Options Database Keys:
1767: .   -islocaltoglobalmapping_type hash - select this method

1769:    Notes:
1770:     This is selected automatically for large problems if the user does not set the type.

1772:    Level: beginner

1774: .seealso: `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH`
1775: M*/
1776: PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog)
1777: {
1778:   ltog->ops->globaltolocalmappingapply      = ISGlobalToLocalMappingApply_Hash;
1779:   ltog->ops->globaltolocalmappingsetup      = ISGlobalToLocalMappingSetUp_Hash;
1780:   ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash;
1781:   ltog->ops->destroy                        = ISLocalToGlobalMappingDestroy_Hash;
1782:   return 0;
1783: }

1785: /*@C
1786:     ISLocalToGlobalMappingRegister -  Adds a method for applying a global to local mapping with an ISLocalToGlobalMapping

1788:    Not Collective

1790:    Input Parameters:
1791: +  sname - name of a new method
1792: -  routine_create - routine to create method context

1794:    Notes:
1795:    ISLocalToGlobalMappingRegister() may be called multiple times to add several user-defined mappings.

1797:    Sample usage:
1798: .vb
1799:    ISLocalToGlobalMappingRegister("my_mapper",MyCreate);
1800: .ve

1802:    Then, your mapping can be chosen with the procedural interface via
1803: $     ISLocalToGlobalMappingSetType(ltog,"my_mapper")
1804:    or at runtime via the option
1805: $     -islocaltoglobalmapping_type my_mapper

1807:    Level: advanced

1809: .seealso: `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`, `ISLOCALTOGLOBALMAPPINGHASH`

1811: @*/
1812: PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping))
1813: {
1814:   ISInitializePackage();
1815:   PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function);
1816:   return 0;
1817: }

1819: /*@C
1820:    ISLocalToGlobalMappingSetType - Builds ISLocalToGlobalMapping for a particular global to local mapping approach.

1822:    Logically Collective on ISLocalToGlobalMapping

1824:    Input Parameters:
1825: +  ltog - the ISLocalToGlobalMapping object
1826: -  type - a known method

1828:    Options Database Key:
1829: .  -islocaltoglobalmapping_type  <method> - Sets the method; use -help for a list
1830:     of available methods (for instance, basic or hash)

1832:    Notes:
1833:    See "petsc/include/petscis.h" for available methods

1835:   Normally, it is best to use the ISLocalToGlobalMappingSetFromOptions() command and
1836:   then set the ISLocalToGlobalMapping type from the options database rather than by using
1837:   this routine.

1839:   Level: intermediate

1841:   Developer Note: ISLocalToGlobalMappingRegister() is used to add new types to ISLocalToGlobalMappingList from which they
1842:   are accessed by ISLocalToGlobalMappingSetType().

1844: .seealso: `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()`
1845: @*/
1846: PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type)
1847: {
1848:   PetscBool match;
1849:   PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL;


1854:   PetscObjectTypeCompare((PetscObject)ltog, type, &match);
1855:   if (match) return 0;

1857:   /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */
1858:   if (type) {
1859:     PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r);
1861:   }
1862:   /* Destroy the previous private LTOG context */
1863:   PetscTryTypeMethod(ltog, destroy);
1864:   ltog->ops->destroy = NULL;

1866:   PetscObjectChangeTypeName((PetscObject)ltog, type);
1867:   if (r) (*r)(ltog);
1868:   return 0;
1869: }

1871: /*@C
1872:    ISLocalToGlobalMappingGetType - Get the type of the l2g map

1874:    Not Collective

1876:    Input Parameter:
1877: .  ltog - the ISLocalToGlobalMapping object

1879:    Output Parameter:
1880: .  type - the type

1882:    Level: intermediate

1884: .seealso: `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`
1885: @*/
1886: PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type)
1887: {
1890:   *type = ((PetscObject)ltog)->type_name;
1891:   return 0;
1892: }

1894: PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE;

1896: /*@C
1897:   ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the IS package.

1899:   Not Collective

1901:   Level: advanced

1903: .seealso: `ISRegister()`, `ISLocalToGlobalRegister()`
1904: @*/
1905: PetscErrorCode ISLocalToGlobalMappingRegisterAll(void)
1906: {
1907:   if (ISLocalToGlobalMappingRegisterAllCalled) return 0;
1908:   ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE;
1909:   ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic);
1910:   ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash);
1911:   return 0;
1912: }