Actual source code: aomapping.c
1: #ifdef PETSC_RCS_HEADER
2: static char vcid[] = "$Id: aomapping.c,v 1.3 2000/01/10 03:15:40 knepley Exp $";
3: #endif
5: /*
6: These AO application ordering routines do not require that the input
7: be a permutation, but merely a 1-1 mapping. This implementation still
8: keeps the entire ordering on each processor.
9: */
11: #include src/dm/ao/aoimpl.h
12: #include petscsys.h
14: typedef struct {
15: int N;
16: int *app; /* app[i] is the partner for petsc[appPerm[i]] */
17: int *appPerm;
18: int *petsc; /* petsc[j] is the partner for app[petscPerm[j]] */
19: int *petscPerm;
20: } AO_Mapping;
22: int AODestroy_Mapping(AO ao)
23: {
24: AO_Mapping *aomap = (AO_Mapping *) ao->data;
25: int ierr;
28: PetscFree(aomap->app);
29: PetscFree(ao->data);
30: return(0);
31: }
33: int AOView_Mapping(AO ao, PetscViewer viewer)
34: {
35: AO_Mapping *aomap = (AO_Mapping *) ao->data;
36: int rank, i;
37: PetscTruth isascii;
38: int ierr;
41: MPI_Comm_rank(ao->comm, &rank);
42: if (rank) return(0);
44: if (!viewer) {
45: viewer = PETSC_VIEWER_STDOUT_SELF;
46: }
48: PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &isascii);
49: if (isascii == PETSC_TRUE) {
50: PetscViewerASCIIPrintf(viewer, "Number of elements in ordering %dn", aomap->N);
51: PetscViewerASCIIPrintf(viewer, " App. PETScn");
52: for(i = 0; i < aomap->N; i++) {
53: PetscViewerASCIIPrintf(viewer, "%d %d %dn", i, aomap->app[i], aomap->petsc[aomap->appPerm[i]]);
54: }
55: }
56: return(0);
57: }
59: int AOPetscToApplication_Mapping(AO ao, int n, int *ia)
60: {
61: AO_Mapping *aomap = (AO_Mapping *) ao->data;
62: int *app = aomap->app;
63: int *petsc = aomap->petsc;
64: int *perm = aomap->petscPerm;
65: int N = aomap->N;
66: int low, high, mid;
67: int index;
68: int i;
70: /* It would be possible to use a single bisection search, which
71: recursively divided the indices to be converted, and searched
72: partitions which contained an index. This would result in
73: better running times if indices are clustered.
74: */
76: for(i = 0; i < n; i++) {
77: index = ia[i];
78: if (index < 0) continue;
79: /* Use bisection since the array is sorted */
80: low = 0;
81: high = N - 1;
82: while (low <= high) {
83: mid = (low + high)/2;
84: if (index == petsc[mid]) {
85: break;
86: } else if (index < petsc[mid]) {
87: high = mid - 1;
88: } else {
89: low = mid + 1;
90: }
91: }
92: if (low > high) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid input index %d", index);
93: ia[i] = app[perm[mid]];
94: }
95: return(0);
96: }
98: int AOApplicationToPetsc_Mapping(AO ao, int n, int *ia)
99: {
100: AO_Mapping *aomap = (AO_Mapping *) ao->data;
101: int *app = aomap->app;
102: int *petsc = aomap->petsc;
103: int *perm = aomap->appPerm;
104: int N = aomap->N;
105: int low, high, mid;
106: int index;
107: int i;
109: /* It would be possible to use a single bisection search, which
110: recursively divided the indices to be converted, and searched
111: partitions which contained an index. This would result in
112: better running times if indices are clustered.
113: */
115: for(i = 0; i < n; i++) {
116: index = ia[i];
117: if (index < 0) continue;
118: /* Use bisection since the array is sorted */
119: low = 0;
120: high = N - 1;
121: while (low <= high) {
122: mid = (low + high)/2;
123: if (index == app[mid]) {
124: break;
125: } else if (index < app[mid]) {
126: high = mid - 1;
127: } else {
128: low = mid + 1;
129: }
130: }
131: if (low > high) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid input index %d", index);
132: ia[i] = petsc[perm[mid]];
133: }
134: return(0);
135: }
137: static struct _AOOps AOps = {AOView_Mapping,
138: AODestroy_Mapping,
139: AOPetscToApplication_Mapping,
140: AOApplicationToPetsc_Mapping,
141: PETSC_NULL,
142: PETSC_NULL,
143: PETSC_NULL,
144: PETSC_NULL};
146: EXTERN_C_BEGIN
147: int AOSerialize_Mapping(MPI_Comm comm, AO *ao, PetscViewer viewer, PetscTruth store)
148: {
149: AO a;
150: AO_Mapping *m;
151: int fd;
152: int ierr;
155: PetscViewerBinaryGetDescriptor(viewer, &fd);
156: if (store) {
157: a = *ao;
158: m = (AO_Mapping *) a->data;
159: PetscBinaryWrite(fd, &a->N, 1, PETSC_INT, 0);
160: PetscBinaryWrite(fd, &a->n, 1, PETSC_INT, 0);
161: PetscBinaryWrite(fd, &m->N, 1, PETSC_INT, 0);
162: PetscBinaryWrite(fd, m->app, m->N, PETSC_INT, 0);
163: PetscBinaryWrite(fd, m->appPerm, m->N, PETSC_INT, 0);
164: PetscBinaryWrite(fd, m->petsc, m->N, PETSC_INT, 0);
165: PetscBinaryWrite(fd, m->petscPerm, m->N, PETSC_INT, 0);
166: } else {
167: PetscHeaderCreate(a, _p_AO, struct _AOOps, AO_COOKIE, AO_MAPPING, "AO", comm, AODestroy, AOView);
168: PetscLogObjectCreate(a);
169: PetscLogObjectMemory(a, sizeof(AO_Mapping) + sizeof(struct _p_AO));
170: PetscNew(AO_Mapping, &m);
171: a->data = (void *) m;
172: PetscMemcpy(a->ops, &AOps, sizeof(AOps));
174: PetscBinaryRead(fd, &a->N, 1, PETSC_INT);
175: PetscBinaryRead(fd, &a->n, 1, PETSC_INT);
176: PetscBinaryRead(fd, &m->N, 1, PETSC_INT);
177: PetscMalloc(m->N*4 * sizeof(int), &m->app);
178: m->appPerm = m->app + m->N;
179: m->petsc = m->appPerm + m->N;
180: m->petscPerm = m->petsc + m->N;
181: PetscLogObjectMemory(a, m->N*4 * sizeof(int));
182: PetscBinaryRead(fd, m->app, m->N, PETSC_INT);
183: PetscBinaryRead(fd, m->appPerm, m->N, PETSC_INT);
184: PetscBinaryRead(fd, m->petsc, m->N, PETSC_INT);
185: PetscBinaryRead(fd, m->petscPerm, m->N, PETSC_INT);
186: *ao = a;
187: }
189: return(0);
190: }
191: EXTERN_C_END
193: /*@C
194: AOMappingHasApplicationIndex - Searches for the supplied application index.
196: Input Parameters:
197: + ao - The AOMapping
198: - index - The application index
200: Output Parameter:
201: . hasIndex - Flag is PETSC_TRUE if the index exists
203: Level: intermediate
205: .keywords: AO, index
206: .seealso: AOMappingHasPetscIndex(), AOCreateMapping()
207: @*/
208: int AOMappingHasApplicationIndex(AO ao, int index, PetscTruth *hasIndex)
209: {
210: AO_Mapping *aomap;
211: int *app;
212: int low, high, mid;
217: aomap = (AO_Mapping *) ao->data;
218: app = aomap->app;
219: /* Use bisection since the array is sorted */
220: low = 0;
221: high = aomap->N - 1;
222: while (low <= high) {
223: mid = (low + high)/2;
224: if (index == app[mid]) {
225: break;
226: } else if (index < app[mid]) {
227: high = mid - 1;
228: } else {
229: low = mid + 1;
230: }
231: }
232: if (low > high) {
233: *hasIndex = PETSC_FALSE;
234: } else {
235: *hasIndex = PETSC_TRUE;
236: }
237: return(0);
238: }
240: /*@C
241: AOMappingHasPetscIndex - Searches for the supplied petsc index.
243: Input Parameters:
244: + ao - The AOMapping
245: - index - The petsc index
247: Output Parameter:
248: . hasIndex - Flag is PETSC_TRUE if the index exists
250: Level: intermediate
252: .keywords: AO, index
253: .seealso: AOMappingHasApplicationIndex(), AOCreateMapping()
254: @*/
255: int AOMappingHasPetscIndex(AO ao, int index, PetscTruth *hasIndex)
256: {
257: AO_Mapping *aomap;
258: int *petsc;
259: int low, high, mid;
264: aomap = (AO_Mapping *) ao->data;
265: petsc = aomap->petsc;
266: /* Use bisection since the array is sorted */
267: low = 0;
268: high = aomap->N - 1;
269: while (low <= high) {
270: mid = (low + high)/2;
271: if (index == petsc[mid]) {
272: break;
273: } else if (index < petsc[mid]) {
274: high = mid - 1;
275: } else {
276: low = mid + 1;
277: }
278: }
279: if (low > high) {
280: *hasIndex = PETSC_FALSE;
281: } else {
282: *hasIndex = PETSC_TRUE;
283: }
284: return(0);
285: }
287: /*@C
288: AOCreateMapping - Creates a basic application mapping using two integer arrays.
290: Input Parameters:
291: + comm - MPI communicator that is to share AO
292: . napp - size of integer arrays
293: . myapp - integer array that defines an ordering
294: - mypetsc - integer array that defines another ordering
296: Output Parameter:
297: . aoout - the new application mapping
299: Options Database Key:
300: $ -ao_view : call AOView() at the conclusion of AOCreateMapping()
302: Level: beginner
304: .keywords: AO, create
305: .seealso: AOCreateDebug(), AOCreateBasic(), AOCreateMappingIS(), AODestroy()
306: @*/
307: int AOCreateMapping(MPI_Comm comm, int napp, int *myapp, int *mypetsc, AO *aoout)
308: {
309: AO ao;
310: AO_Mapping *aomap;
311: int *lens, *disp;
312: int *allpetsc, *allapp;
313: int *petscPerm, *appPerm;
314: int *petsc;
315: int size, rank;
316: int N, start;
317: int i;
318: PetscTruth opt;
319: int ierr;
323: *aoout = 0;
324: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
325: DMInitializePackage(PETSC_NULL);
326: #endif
328: PetscHeaderCreate(ao, _p_AO, struct _AOOps, AO_COOKIE, AO_MAPPING, "AO", comm, AODestroy, AOView);
329: PetscLogObjectCreate(ao);
330: PetscNew(AO_Mapping, &aomap);
331: PetscLogObjectMemory(ao, sizeof(struct _p_AO) + sizeof(AO_Mapping));
332: PetscMemcpy(ao->ops, &AOps, sizeof(AOps));
333: PetscStrallocpy(AO_SER_MAPPING_BINARY, &ao->serialize_name);
334: ao->data = (void *) aomap;
336: /* transmit all lengths to all processors */
337: MPI_Comm_size(comm, &size);
338: MPI_Comm_rank(comm, &rank);
339: PetscMalloc(2*size * sizeof(int), &lens);
340: disp = lens + size;
341: MPI_Allgather(&napp, 1, MPI_INT, lens, 1, MPI_INT, comm);
342: N = 0;
343: for(i = 0; i < size; i++) {
344: disp[i] = N;
345: N += lens[i];
346: }
347: aomap->N = N;
348: ao->N = N;
349: ao->n = N;
351: /* If mypetsc is 0 then use "natural" numbering */
352: if (!mypetsc) {
353: start = disp[rank];
354: ierr = PetscMalloc((napp+1) * sizeof(int), &petsc);
355: for(i = 0; i < napp; i++) {
356: petsc[i] = start + i;
357: }
358: } else {
359: petsc = mypetsc;
360: }
362: /* get all indices on all processors */
363: PetscMalloc(N*4 * sizeof(int), &allapp);
364: appPerm = allapp + N;
365: allpetsc = appPerm + N;
366: petscPerm = allpetsc + N;
367: MPI_Allgatherv(myapp, napp, MPI_INT, allapp, lens, disp, MPI_INT, comm);
368: MPI_Allgatherv(mypetsc, napp, MPI_INT, allpetsc, lens, disp, MPI_INT, comm);
369: PetscFree(lens);
371: /* generate a list of application and PETSc node numbers */
372: PetscMalloc(N*4 * sizeof(int), &aomap->app);
373: PetscLogObjectMemory(ao, 4*N * sizeof(int));
374: aomap->appPerm = aomap->app + N;
375: aomap->petsc = aomap->appPerm + N;
376: aomap->petscPerm = aomap->petsc + N;
377: for(i = 0; i < N; i++) {
378: appPerm[i] = i;
379: petscPerm[i] = i;
380: }
381: PetscSortIntWithPermutation(N, allpetsc, petscPerm);
382: PetscSortIntWithPermutation(N, allapp, appPerm);
383: /* Form sorted arrays of indices */
384: for(i = 0; i < N; i++) {
385: aomap->app[i] = allapp[appPerm[i]];
386: aomap->petsc[i] = allpetsc[petscPerm[i]];
387: }
388: /* Invert petscPerm[] into aomap->petscPerm[] */
389: for(i = 0; i < N; i++) {
390: aomap->petscPerm[petscPerm[i]] = i;
391: }
392: /* Form map between aomap->app[] and aomap->petsc[] */
393: for(i = 0; i < N; i++) {
394: aomap->appPerm[i] = aomap->petscPerm[appPerm[i]];
395: }
396: /* Invert appPerm[] into allapp[] */
397: for(i = 0; i < N; i++) {
398: allapp[appPerm[i]] = i;
399: }
400: /* Form map between aomap->petsc[] and aomap->app[] */
401: for(i = 0; i < N; i++) {
402: aomap->petscPerm[i] = allapp[petscPerm[i]];
403: }
404: #ifdef PETSC_USE_BOPT_g
405: /* Check that the permutations are complementary */
406: for(i = 0; i < N; i++) {
407: if (i != aomap->appPerm[aomap->petscPerm[i]])
408: SETERRQ(PETSC_ERR_PLIB, "Invalid ordering");
409: }
410: #endif
411: /* Cleanup */
412: if (!mypetsc) {
413: PetscFree(petsc);
414: }
415: PetscFree(allapp);
417: PetscOptionsHasName(PETSC_NULL, "-ao_view", &opt);
418: if (opt == PETSC_TRUE) {
419: AOView(ao, PETSC_VIEWER_STDOUT_SELF);
420: }
422: *aoout = ao;
423: return(0);
424: }
426: /*@C
427: AOCreateMappingIS - Creates a basic application ordering using two index sets.
429: Input Parameters:
430: + comm - MPI communicator that is to share AO
431: . isapp - index set that defines an ordering
432: - ispetsc - index set that defines another ordering
434: Output Parameter:
435: . aoout - the new application ordering
437: Options Database Key:
438: $ -ao_view : call AOView() at the conclusion of AOCreateMappingIS()
440: Level: beginner
442: .keywords: AO, create
443: .seealso: AOCreateBasic(), AOCreateMapping(), AODestroy()
444: @*/
445: int AOCreateMappingIS(IS isapp, IS ispetsc, AO *aoout)
446: {
447: MPI_Comm comm;
448: int *mypetsc, *myapp;
449: int napp, npetsc;
450: int ierr;
453: PetscObjectGetComm((PetscObject) isapp, &comm);
454: ISGetSize(isapp, &napp);
455: if (ispetsc) {
456: ISGetSize(ispetsc, &npetsc);
457: if (napp != npetsc) SETERRQ(PETSC_ERR_ARG_SIZ, "Local IS lengths must match");
458: ISGetIndices(ispetsc, &mypetsc);
459: }
460: ISGetIndices(isapp, &myapp);
462: AOCreateMapping(comm, napp, myapp, mypetsc, aoout);
464: ISRestoreIndices(isapp, &myapp);
465: if (ispetsc) {
466: ISRestoreIndices(ispetsc, &mypetsc);
467: }
468: return(0);
469: }