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: }