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