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, <og);
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: }