Actual source code: aomapping.c
1: #define PETSCDM_DLL
3: /*
4: These AO application ordering routines do not require that the input
5: be a permutation, but merely a 1-1 mapping. This implementation still
6: keeps the entire ordering on each processor.
7: */
9: #include ../src/dm/ao/aoimpl.h
11: typedef struct {
12: PetscInt N;
13: PetscInt *app; /* app[i] is the partner for petsc[appPerm[i]] */
14: PetscInt *appPerm;
15: PetscInt *petsc; /* petsc[j] is the partner for app[petscPerm[j]] */
16: PetscInt *petscPerm;
17: } AO_Mapping;
21: PetscErrorCode AODestroy_Mapping(AO ao)
22: {
23: AO_Mapping *aomap = (AO_Mapping *) ao->data;
27: PetscFree4(aomap->app,aomap->appPerm,aomap->petsc,aomap->petscPerm);
28: PetscFree(ao->data);
29: return(0);
30: }
34: PetscErrorCode AOView_Mapping(AO ao, PetscViewer viewer)
35: {
36: AO_Mapping *aomap = (AO_Mapping *) ao->data;
37: PetscMPIInt rank;
38: PetscInt i;
39: PetscTruth iascii;
43: MPI_Comm_rank(((PetscObject)ao)->comm, &rank);
44: if (rank) return(0);
46: if (!viewer) {
47: viewer = PETSC_VIEWER_STDOUT_SELF;
48: }
50: PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &iascii);
51: if (iascii) {
52: PetscViewerASCIIPrintf(viewer, "Number of elements in ordering %D\n", aomap->N);
53: PetscViewerASCIIPrintf(viewer, " App. PETSc\n");
54: for(i = 0; i < aomap->N; i++) {
55: PetscViewerASCIIPrintf(viewer, "%D %D %D\n", i, aomap->app[i], aomap->petsc[aomap->appPerm[i]]);
56: }
57: }
58: return(0);
59: }
63: PetscErrorCode AOPetscToApplication_Mapping(AO ao, PetscInt n, PetscInt *ia)
64: {
65: AO_Mapping *aomap = (AO_Mapping *) ao->data;
66: PetscInt *app = aomap->app;
67: PetscInt *petsc = aomap->petsc;
68: PetscInt *perm = aomap->petscPerm;
69: PetscInt N = aomap->N;
70: PetscInt low, high, mid=0;
71: PetscInt idex;
72: PetscInt i;
74: /* It would be possible to use a single bisection search, which
75: recursively divided the indices to be converted, and searched
76: partitions which contained an index. This would result in
77: better running times if indices are clustered.
78: */
80: for(i = 0; i < n; i++) {
81: idex = ia[i];
82: if (idex < 0) continue;
83: /* Use bisection since the array is sorted */
84: low = 0;
85: high = N - 1;
86: while (low <= high) {
87: mid = (low + high)/2;
88: if (idex == petsc[mid]) {
89: break;
90: } else if (idex < petsc[mid]) {
91: high = mid - 1;
92: } else {
93: low = mid + 1;
94: }
95: }
96: if (low > high) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid input index %D", idex);
97: ia[i] = app[perm[mid]];
98: }
99: return(0);
100: }
104: PetscErrorCode AOApplicationToPetsc_Mapping(AO ao, PetscInt n, PetscInt *ia)
105: {
106: AO_Mapping *aomap = (AO_Mapping *) ao->data;
107: PetscInt *app = aomap->app;
108: PetscInt *petsc = aomap->petsc;
109: PetscInt *perm = aomap->appPerm;
110: PetscInt N = aomap->N;
111: PetscInt low, high, mid=0;
112: PetscInt idex;
113: PetscInt i;
115: /* It would be possible to use a single bisection search, which
116: recursively divided the indices to be converted, and searched
117: partitions which contained an index. This would result in
118: better running times if indices are clustered.
119: */
121: for(i = 0; i < n; i++) {
122: idex = ia[i];
123: if (idex < 0) continue;
124: /* Use bisection since the array is sorted */
125: low = 0;
126: high = N - 1;
127: while (low <= high) {
128: mid = (low + high)/2;
129: if (idex == app[mid]) {
130: break;
131: } else if (idex < app[mid]) {
132: high = mid - 1;
133: } else {
134: low = mid + 1;
135: }
136: }
137: if (low > high) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE, "Invalid input index %D", idex);
138: ia[i] = petsc[perm[mid]];
139: }
140: return(0);
141: }
143: static struct _AOOps AOps = {AOView_Mapping,
144: AODestroy_Mapping,
145: AOPetscToApplication_Mapping,
146: AOApplicationToPetsc_Mapping,
147: PETSC_NULL,
148: PETSC_NULL,
149: PETSC_NULL,
150: PETSC_NULL};
154: /*@C
155: AOMappingHasApplicationIndex - Searches for the supplied application index.
157: Input Parameters:
158: + ao - The AOMapping
159: - index - The application index
161: Output Parameter:
162: . hasIndex - Flag is PETSC_TRUE if the index exists
164: Level: intermediate
166: .keywords: AO, index
167: .seealso: AOMappingHasPetscIndex(), AOCreateMapping()
168: @*/
169: PetscErrorCode AOMappingHasApplicationIndex(AO ao, PetscInt idex, PetscTruth *hasIndex)
170: {
171: AO_Mapping *aomap;
172: PetscInt *app;
173: PetscInt low, high, mid;
178: aomap = (AO_Mapping *) ao->data;
179: app = aomap->app;
180: /* Use bisection since the array is sorted */
181: low = 0;
182: high = aomap->N - 1;
183: while (low <= high) {
184: mid = (low + high)/2;
185: if (idex == app[mid]) {
186: break;
187: } else if (idex < app[mid]) {
188: high = mid - 1;
189: } else {
190: low = mid + 1;
191: }
192: }
193: if (low > high) {
194: *hasIndex = PETSC_FALSE;
195: } else {
196: *hasIndex = PETSC_TRUE;
197: }
198: return(0);
199: }
203: /*@
204: AOMappingHasPetscIndex - Searches for the supplied petsc index.
206: Input Parameters:
207: + ao - The AOMapping
208: - index - The petsc index
210: Output Parameter:
211: . hasIndex - Flag is PETSC_TRUE if the index exists
213: Level: intermediate
215: .keywords: AO, index
216: .seealso: AOMappingHasApplicationIndex(), AOCreateMapping()
217: @*/
218: PetscErrorCode AOMappingHasPetscIndex(AO ao, PetscInt idex, PetscTruth *hasIndex)
219: {
220: AO_Mapping *aomap;
221: PetscInt *petsc;
222: PetscInt low, high, mid;
227: aomap = (AO_Mapping *) ao->data;
228: petsc = aomap->petsc;
229: /* Use bisection since the array is sorted */
230: low = 0;
231: high = aomap->N - 1;
232: while (low <= high) {
233: mid = (low + high)/2;
234: if (idex == petsc[mid]) {
235: break;
236: } else if (idex < petsc[mid]) {
237: high = mid - 1;
238: } else {
239: low = mid + 1;
240: }
241: }
242: if (low > high) {
243: *hasIndex = PETSC_FALSE;
244: } else {
245: *hasIndex = PETSC_TRUE;
246: }
247: return(0);
248: }
252: /*@C
253: AOCreateMapping - Creates a basic application mapping using two integer arrays.
255: Input Parameters:
256: + comm - MPI communicator that is to share AO
257: . napp - size of integer arrays
258: . myapp - integer array that defines an ordering
259: - mypetsc - integer array that defines another ordering (may be PETSC_NULL to indicate the identity ordering)
261: Output Parameter:
262: . aoout - the new application mapping
264: Options Database Key:
265: $ -ao_view : call AOView() at the conclusion of AOCreateMapping()
267: Level: beginner
269: Notes: the arrays myapp and mypetsc need NOT contain the all the integers 0 to napp-1, that is there CAN be "holes" in the indices.
270: Use AOCreateBasic() or AOCreateBasicIS() if they do not have holes for better performance.
272: .keywords: AO, create
273: .seealso: AOCreateBasic(), AOCreateBasic(), AOCreateMappingIS(), AODestroy()
274: @*/
275: PetscErrorCode AOCreateMapping(MPI_Comm comm,PetscInt napp,const PetscInt myapp[],const PetscInt mypetsc[],AO *aoout)
276: {
277: AO ao;
278: AO_Mapping *aomap;
279: PetscInt *allpetsc, *allapp;
280: PetscInt *petscPerm, *appPerm;
281: PetscInt *petsc;
282: PetscMPIInt size, rank,*lens, *disp,nnapp;
283: PetscInt N, start;
284: PetscInt i;
285: PetscTruth opt;
290: *aoout = 0;
291: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
292: DMInitializePackage(PETSC_NULL);
293: #endif
295: PetscHeaderCreate(ao, _p_AO, struct _AOOps, AO_COOKIE, AO_MAPPING, "AO", comm, AODestroy, AOView);
296: PetscNewLog(ao, AO_Mapping, &aomap);
297: PetscMemcpy(ao->ops, &AOps, sizeof(AOps));
298: ao->data = (void*) aomap;
300: /* transmit all lengths to all processors */
301: MPI_Comm_size(comm, &size);
302: MPI_Comm_rank(comm, &rank);
303: PetscMalloc2(size,PetscMPIInt, &lens,size,PetscMPIInt,&disp);
304: nnapp = napp;
305: MPI_Allgather(&nnapp, 1, MPI_INT, lens, 1, MPI_INT, comm);
306: N = 0;
307: for(i = 0; i < size; i++) {
308: disp[i] = N;
309: N += lens[i];
310: }
311: aomap->N = N;
312: ao->N = N;
313: ao->n = N;
315: /* If mypetsc is 0 then use "natural" numbering */
316: if (!mypetsc) {
317: start = disp[rank];
318: PetscMalloc((napp+1) * sizeof(PetscInt), &petsc);
319: for(i = 0; i < napp; i++) {
320: petsc[i] = start + i;
321: }
322: } else {
323: petsc = (PetscInt*)mypetsc;
324: }
326: /* get all indices on all processors */
327: PetscMalloc4(N,PetscInt, &allapp,N,PetscInt,&appPerm,N,PetscInt,&allpetsc,N,PetscInt,&petscPerm);
328: MPI_Allgatherv((void*)myapp, napp, MPIU_INT, allapp, lens, disp, MPIU_INT, comm);
329: MPI_Allgatherv((void*)petsc, napp, MPIU_INT, allpetsc, lens, disp, MPIU_INT, comm);
330: PetscFree2(lens,disp);
332: /* generate a list of application and PETSc node numbers */
333: PetscMalloc4(N,PetscInt, &aomap->app,N,PetscInt,&aomap->appPerm,N,PetscInt,&aomap->petsc,N,PetscInt,&aomap->petscPerm);
334: PetscLogObjectMemory(ao, 4*N * sizeof(PetscInt));
335: for(i = 0; i < N; i++) {
336: appPerm[i] = i;
337: petscPerm[i] = i;
338: }
339: PetscSortIntWithPermutation(N, allpetsc, petscPerm);
340: PetscSortIntWithPermutation(N, allapp, appPerm);
341: /* Form sorted arrays of indices */
342: for(i = 0; i < N; i++) {
343: aomap->app[i] = allapp[appPerm[i]];
344: aomap->petsc[i] = allpetsc[petscPerm[i]];
345: }
346: /* Invert petscPerm[] into aomap->petscPerm[] */
347: for(i = 0; i < N; i++) {
348: aomap->petscPerm[petscPerm[i]] = i;
349: }
350: /* Form map between aomap->app[] and aomap->petsc[] */
351: for(i = 0; i < N; i++) {
352: aomap->appPerm[i] = aomap->petscPerm[appPerm[i]];
353: }
354: /* Invert appPerm[] into allapp[] */
355: for(i = 0; i < N; i++) {
356: allapp[appPerm[i]] = i;
357: }
358: /* Form map between aomap->petsc[] and aomap->app[] */
359: for(i = 0; i < N; i++) {
360: aomap->petscPerm[i] = allapp[petscPerm[i]];
361: }
362: #ifdef PETSC_USE_DEBUG
363: /* Check that the permutations are complementary */
364: for(i = 0; i < N; i++) {
365: if (i != aomap->appPerm[aomap->petscPerm[i]])
366: SETERRQ(PETSC_ERR_PLIB, "Invalid ordering");
367: }
368: #endif
369: /* Cleanup */
370: if (!mypetsc) {
371: PetscFree(petsc);
372: }
373: PetscFree4(allapp,appPerm,allpetsc,petscPerm);
375: opt = PETSC_FALSE;
376: PetscOptionsGetTruth(PETSC_NULL, "-ao_view", &opt,PETSC_NULL);
377: if (opt) {
378: AOView(ao, PETSC_VIEWER_STDOUT_SELF);
379: }
381: *aoout = ao;
382: return(0);
383: }
387: /*@C
388: AOCreateMappingIS - Creates a basic application ordering using two index sets.
390: Input Parameters:
391: + comm - MPI communicator that is to share AO
392: . isapp - index set that defines an ordering
393: - ispetsc - index set that defines another ordering, maybe PETSC_NULL for identity IS
395: Output Parameter:
396: . aoout - the new application ordering
398: Options Database Key:
399: $ -ao_view : call AOView() at the conclusion of AOCreateMappingIS()
401: Level: beginner
403: Notes: the index sets isapp and ispetsc need NOT contain the all the integers 0 to N-1, that is there CAN be "holes" in the indices.
404: Use AOCreateBasic() or AOCreateBasicIS() if they do not have holes for better performance.
406: .keywords: AO, create
407: .seealso: AOCreateBasic(), AOCreateMapping(), AODestroy()
408: @*/
409: PetscErrorCode AOCreateMappingIS(IS isapp, IS ispetsc, AO *aoout)
410: {
411: MPI_Comm comm;
412: const PetscInt *mypetsc, *myapp;
413: PetscInt napp, npetsc;
414: PetscErrorCode ierr;
417: PetscObjectGetComm((PetscObject) isapp, &comm);
418: ISGetLocalSize(isapp, &napp);
419: if (ispetsc) {
420: ISGetLocalSize(ispetsc, &npetsc);
421: if (napp != npetsc) SETERRQ(PETSC_ERR_ARG_SIZ, "Local IS lengths must match");
422: ISGetIndices(ispetsc, &mypetsc);
423: } else {
424: mypetsc = NULL;
425: }
426: ISGetIndices(isapp, &myapp);
428: AOCreateMapping(comm, napp, myapp, mypetsc, aoout);
430: ISRestoreIndices(isapp, &myapp);
431: if (ispetsc) {
432: ISRestoreIndices(ispetsc, &mypetsc);
433: }
434: return(0);
435: }